GLSL/OpenGL着色器曲面细分闪烁和失败

toi*_*toi 14 c++ opengl glsl tessellation

我刚刚开始使用OpenGL细分,并且遇到了一些麻烦.我正在细分由一个顶点形成的一系列补丁.这些顶点/补丁以网格状结构构造,以后形成由Perlin Noise生成的地形.

我遇到的问题是从第二补丁开始,之后的每 5 补丁,有时会有很多细分(不是我配置的方式),但大多数情况下它根本没有得到细分.

像这样:

  

两个白色圆圈标记高度/过度细分的贴片.还要注意未分区补丁的模式.

奇怪的是,它适用于我的Surface Pro 2(英特尔HD4400显卡),但我的主台式电脑(AMD HD6950显卡)上有错误.硬件有可能坏吗?

使用以下代码生成修补程序:

    vec4* patches = new vec4[m_patchesWidth * m_patchesDepth];
    int c = 0;
    for (unsigned int z = 0; z < m_patchesDepth; ++z) {
        for (unsigned int x = 0; x < m_patchesWidth; ++x) {
            patches[c] = vec4(x * 1.5f, 0, z * 1.5f, 1.0f);
            c++;
        }
    }
    m_fxTerrain->Apply();
    glGenBuffers(1, &m_planePatches);
    glBindBuffer(GL_ARRAY_BUFFER, m_planePatches);
    glBufferData(GL_ARRAY_BUFFER, m_patchesWidth * m_patchesDepth * sizeof(vec4), patches, GL_STATIC_DRAW);
    GLuint loc = m_fxTerrain->GetAttrib("posIn");
    glEnableVertexAttribArray(loc);
    glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(vec4), nullptr);
    delete(patches);
Run Code Online (Sandbox Code Playgroud)

并绘制:

    glPatchParameteri(GL_PATCH_VERTICES, 1);
    glBindVertexArray(patches);

    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    glDrawArrays(GL_PATCHES, 0, nrOfPatches);
Run Code Online (Sandbox Code Playgroud)

顶点着色器:

#version 430 core
in vec4 posIn;

out gl_PerVertex {
    vec4 gl_Position;
};

void main() {
    gl_Position = posIn;
}
Run Code Online (Sandbox Code Playgroud)

控件着色器:

#version 430
#extension GL_ARB_tessellation_shader : enable
layout (vertices = 1) out;

uniform float OuterTessFactor;
uniform float InnerTessFactor;

out gl_PerVertex {
    vec4 gl_Position;
} gl_out[];

void main() {

    if (gl_InvocationID == 0) {
        gl_TessLevelOuter[0] = OuterTessFactor;
        gl_TessLevelOuter[1] = OuterTessFactor;
        gl_TessLevelOuter[2] = OuterTessFactor;
        gl_TessLevelOuter[3] = OuterTessFactor;

        gl_TessLevelInner[0] = InnerTessFactor;
        gl_TessLevelInner[1] = InnerTessFactor;
    }
    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
}
Run Code Online (Sandbox Code Playgroud)

评估着色器:

#version 430 
#extension GL_ARB_tessellation_shader : enable
layout (quads, equal_spacing, ccw) in;

uniform mat4 ProjView;
uniform sampler2D PerlinNoise;

out vec3 PosW;
out vec3 Normal;
out vec4 ColorFrag;
out gl_PerVertex {
    vec4 gl_Position;
};

void main() {
    vec4 pos = gl_in[0].gl_Position;
    pos.xz += gl_TessCoord.xy;
    pos.y = texture2D(PerlinNoise, pos.xz / vec2(8, 8)).x * 10.0f - 10.0f;
    Normal = vec3(0, 1, 0);
    gl_Position = ProjView * pos;
    PosW = pos.xyz;
    ColorFrag = vec4(pos.x / 64.0f, 0.0f, pos.z / 64.0f, 1.0f);
}
Run Code Online (Sandbox Code Playgroud)

片段着色器:

#version 430 core
in vec3 PosW;
in vec3 Normal;
in vec4 ColorFrag;
in vec4 PosH;

out vec3 FragColor;
out vec3 FragNormal;

void main() {
    FragNormal = Normal;
    FragColor = ColorFrag.xyz;
}
Run Code Online (Sandbox Code Playgroud)

我试图对不同的曲面细分级别进行硬编码,但这没有帮助.我最近开始使用OpenGL,所以如果我做了一些愚蠢的事情,请告诉我.

那么有谁知道什么可能导致某些补丁的"闪烁"?

更新:我有一个朋友运行该项目,他得到了相同的闪烁曲面细分模式,但除了过度镶嵌细分时,根本没有绘制失败的补丁.他和我一样拥有相同的显卡(AMD HD6950).

Dav*_*lai 10

您应该使用三角形/四边形镶嵌,其中每个贴片具有3或4个顶点.我可以看到,你使用四边形(我也使用它们).在这种情况下,您可以这样设置:

glPatchParameteri(GL_PATCH_VERTICES,4);
glBindVertexArray(VertexArray);
Run Code Online (Sandbox Code Playgroud)

(提示:对于您的地形使用drawelements,基于2D位移的网格可以获得更好的性能.)
在控件着色器中,使用

layout (vertices = 4) out;
Run Code Online (Sandbox Code Playgroud)

因为你的补丁有4个控制点.订购仍然很重要(CCW/CW).
我个人不喜欢使用内置变量,因此对于顶点着色器,您可以将顶点数据发送到tesscontrol,如下所示:

layout (location = 0) out vec3 outPos;
....
outPos.xz = grid.xy;
outPos.y = noise(outPos.xz);
Run Code Online (Sandbox Code Playgroud)

苔丝控制:

layout (location = 0) in vec3 inPos[]; //outPos (location = 0) from vertex shader
//'collects' the 4 control points to an array in the order they're sended
layout (location = 0) out vec3 outPos[];  //send the c.points to the ev. shader
...
gl_TessLevelOuter[0] = outt[0];
gl_TessLevelOuter[1] = outt[1];
gl_TessLevelOuter[2] = outt[2];
gl_TessLevelOuter[3] = outt[3];

gl_TessLevelInner[0] = inn[0];
gl_TessLevelInner[1] = inn[1];

outPos[ID] = inPos[ID];//gl_invocationID = ID
Run Code Online (Sandbox Code Playgroud)

请注意,顶点和顶点数据都是一个数组.

tessev很简单:

layout (location = 0) in vec3 inPos[]; //the 4 control points
layout (location = 0) out vec3 outPos; //this is no longer array, next is the fragment shader
...
//edit: do not forgot to add the next line
layout (quads) in;

vec3 interpolate3D(vec3 v0, vec3 v1, vec3 v2, vec3 v3) //linear interpolation for x,y,z coords on the quad
{
    return mix(mix(v0,v1,gl_TessCoord.x),mix(v3,v2,gl_TessCoord.x),gl_TessCoord.y);
};
...main{...
outPos = interpolate3D(inPos[0],inPos[1],inPos[2],inPos[3]); //the four control points of the quad. Every other point is linearly interpolated between them according to the TessCoord.
gl_Position = mvp * vec4(outPos,1.0f);
Run Code Online (Sandbox Code Playgroud)

四域的良好表示:http://ogldev.atspace.co.uk/www/tutorial30/tutorial30.html.

我认为问题在于你的单顶点补丁.我无法想象一个顶点路径如何被分成三角形,我不知道它是如何在另一个硬件上工作的.曲面细分用于将基元划分为其他简单基元,在OGL情况下为三角形,因为它可以由GPU轻松处理(3个点始终位于平面中).因此,对于三角形,最小补丁顶点数应为3.我喜欢四边形,因为索引更简单,内存成本更低.在镶嵌过程中它也将被分成三角形.http://www.informit.com/articles/article.aspx?p=2120983 此外,还有另一种类型,即等值线镶嵌.(查看链接,第二个非常好.)

总而言之,尝试使用四边形或三角形,并将控制顶点设置为4(或3).我的(相当复杂的)地形着色器在此处使用视锥体剔除,曲面细分着色器剔除基于geoclipmap的地形.此外,没有细分,它适用于顶点着色器中的顶点变形.也许这段代码的某些部分会很有用.http://speedy.sh/TAvPR/gshader.txt

具有大约4个像素/三角形的曲面细分的场景以75FPS(具有成帧)运行,具有运行时正常计算和双三次平滑等.我正在使用AMD HD 5750.通过更好的代码和预先烘焙的法线,它仍然可以更快:D.(运行最大120 w/o正常计算.)

哦,如果你在着色器中移动顶点,你只能发送x和z坐标.它也会更快.

在此输入图像描述 很多顶点.