Opengl 如何在细分控制着色器中访问同一面片中的所有顶点

Opengl 如何在细分控制着色器中访问同一面片中的所有顶点,opengl,glsl,tessellation,Opengl,Glsl,Tessellation,我想在Tessenlation控件着色器中执行LOD。我的方法是计算每个面片在屏幕坐标上占据的面积,并为它们设置不同的细分级别 所以我需要访问面片中的所有顶点,我这样做就像: for(int i = 0; i < 4; i++) { position_screen[i] = ProjectionMatrix * ModelViewMatrix * gl_in[i].gl_Position; } 以下是OpenGL中的相关代码: glBindBuffer(GL_ELEMENT_AR

我想在Tessenlation控件着色器中执行LOD。我的方法是计算每个面片在屏幕坐标上占据的面积,并为它们设置不同的细分级别

所以我需要访问面片中的所有顶点,我这样做就像:

for(int i = 0; i < 4; i++)
{
    position_screen[i] = ProjectionMatrix * ModelViewMatrix * gl_in[i].gl_Position;
}
以下是OpenGL中的相关代码:

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, rect_index_buffer);
glPatchParameteri(GL_PATCH_VERTICES, 4);
glDrawElements(GL_PATCHES, RECT_INDEX_SIZE, GL_UNSIGNED_INT, 0);    

但是结果很奇怪。细分级别与scrren上的区域相关,但所有面片都具有相同的细分级别

那有什么问题

我想这是我尝试访问面片内顶点的方式出错了。那我怎么做呢

以下是我的细分控制着色器中的代码,希望对您有所帮助:

#version 400  
layout( vertices=4 ) out; 

uniform mat4 ProjectionMatrix;
uniform mat4 ModelViewMatrix;

uniform float window_height;
uniform float window_width;

float PI = 3.14159;

float calcTriangleArea(float l[3])  //Heron's formula
{
    float p = (l[0] + l[1] + l[2]) / 2.0;

    return sqrt(p * (p - l[0]) * (p - l[1]) * (p - l[2]));
}

float calcSqureArea(vec4 position[4])
{
    vec2 position_screen[4];
    for(int i=0;i<4;i++)
    {
        position_screen[i] = position[i].xy;
    }

    float l[4];

    for(int i = 0;i < 4;i++)
    {
        l[i] = length(position_screen[(i + 1) % 4] - position_screen[i % 4]);
    }

    float diagonal = length(position_screen[2] - position_screen[0]);

    float l1[3];
    float l2[3];

    l1[0] = l[0];
    l1[1] = l[1];
    l1[2] = diagonal;

    l2[0] = l[2];
    l2[1] = l[3];
    l2[2] = diagonal;

    float area = calcTriangleArea(l1) + calcTriangleArea(l2);

    return area;
}

float checkInsideView(vec4 position[4]) //check if the patch is visible
{
    int flag = 4;
    for(int i=0;i<4;i++)
    {
        if((position[i].x >= -window_width / 2.0) && (position[i].x <= window_width / 2.0) && 
    (position[i].y >= -window_height / 2.0) && (position[i].y <= window_height / 2.0))
        {
            flag --;
        }
    }

    if(flag == 0)   //all 4 vertices are visible
    {
        return 0.0;
    }
    else if(flag == 4)  //not all visible
    {
        return 2.0;
    }
    else    //all vertices are not visible
    {
        return 1.0;
    }
}

float calcLODLevel()
{
    vec4 position_screen[4];
    for(int i = 0; i < 4; i++)
    {
        position_screen[i] = ProjectionMatrix * ModelViewMatrix * gl_in[i].gl_Position;
    }

    float in_view_level = checkInsideView(position_screen);

    //tess number is decided by the area that this patch covers on 
    //the screen
    float area = calcSqureArea(position_screen);
    float level = sqrt(area);   

    if(in_view_level == 1.0)    
    {
        level /= sqrt(2);
    }
    //dont do tessellation
    //if this patch is not visible
    else if(in_view_level == 2.0)
    {
        level = 1.0;
    }

    return level;
}

void main()
{
    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;

    float lod_level = calcLODLevel();

    gl_TessLevelOuter[0] = lod_level;
    gl_TessLevelOuter[1] = lod_level;
    gl_TessLevelOuter[2] = lod_level;  
    gl_TessLevelOuter[3] = lod_level;  
    gl_TessLevelInner[0] = lod_level;
    gl_TessLevelInner[1] = lod_level;   
}
#版本400
布局(顶点=4)向外;
均匀mat4投影矩阵;
统一mat4模型视图矩阵;
均匀浮动窗口高度;
均匀浮动窗口宽度;
浮点数PI=3.14159;
float calcTriangleArea(float l[3])//Heron公式
{
浮点数p=(l[0]+l[1]+l[2])/2.0;
返回sqrt(p*(p-l[0])*(p-l[1])*(p-l[2]);
}
浮动CalcSqUrea(vec4位置[4])
{
vec2位置_屏幕[4];

对于(int i=0;i我认为问题在于屏幕坐标的计算,导致细分级别太小。关键部分是:

position_screen[i] = ProjectionMatrix * ModelViewMatrix * gl_in[i].gl_Position;
这里计算的是剪辑坐标,而不是屏幕坐标。要从剪辑坐标中获取屏幕坐标,您需要:

  • 执行透视分割。这将为您提供范围[-1.0,1.0]内的NDC(标准化设备坐标)
  • 从NDC计算屏幕坐标
在代码中,计算可能如下所示:

vec4 posClip = ProjectionMatrix * ModelViewMatrix * gl_in[i].gl_Position;
vec2 posNdc = posClip.xy * (1.0 / posClip.w);
vec2 posScreen = 0.5 * (posNdc + 1.0) * vec2(window_width, window_height);

我认为问题在于您对屏幕坐标的计算,导致细分级别太小。关键部分是:

position_screen[i] = ProjectionMatrix * ModelViewMatrix * gl_in[i].gl_Position;
这里计算的是剪辑坐标,而不是屏幕坐标。要从剪辑坐标中获取屏幕坐标,您需要:

  • 执行透视分割。这将为您提供范围[-1.0,1.0]内的NDC(标准化设备坐标)
  • 从NDC计算屏幕坐标
在代码中,计算可能如下所示:

vec4 posClip = ProjectionMatrix * ModelViewMatrix * gl_in[i].gl_Position;
vec2 posNdc = posClip.xy * (1.0 / posClip.w);
vec2 posScreen = 0.5 * (posNdc + 1.0) * vec2(window_width, window_height);

无论如何,谢谢,但这个苔丝级别确实不是太小。我最想弄明白的是,为什么所有补丁共享相同的苔丝级别,而它们应该具有不同的苔丝级别。在使用的计算中,结果将只取决于世界坐标空间中的大小。如果要使用屏幕空间中的大小,则需要透视分割。无论如何,谢谢,但是这个tess级别确实不是太小。我最想弄清楚的是,为什么所有面片共享相同的tess级别,而它们应该具有不同的tess级别。使用您正在使用的计算,结果将只取决于世界坐标空间中的大小。如果您想在scre中使用大小在空间中,您需要透视分割。无论如何,谢谢,但这个苔丝级别确实不是太小。我最想弄清楚的是,为什么所有面片共享相同的苔丝级别,而它们应该具有不同的苔丝级别。使用计算,结果将仅取决于世界坐标空间中的大小。如果您不想o使用屏幕空间中的大小,您需要透视分割。