GLSL / OpenGL着色器镶嵌闪烁和失败 [英] GLSL/OpenGL shader tessellation flickering and failure

查看:515
本文介绍了GLSL / OpenGL着色器镶嵌闪烁和失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚开始使用OpenGL细分,并遇到了一些麻烦。我镶嵌由一个顶点形成的一系列补丁。这些顶点/补丁以网格形式结构化,以后形成由Perlin Noise生成的地形。



我遇到的问题是从第二个补丁开始,每5个 th 补丁后,有时有很多的细分(不是我的方式配置),但大多数时间它根本没有镶嵌。



像这样:



  

两个白色圆圈标记了高度/过度镶嵌的补丁。



奇怪的是,它适用于我的Surface Pro 2(英特尔HD4400显卡),但我的主台式机上的错误(AMD HD6950图形)。硬件是否可能是坏的?



补丁是用以下代码生成的:



  vec4 * patches = new vec4 [m_patchesWidth * m_patchesDepth]; 
int c = 0;
for(unsigned int z = 0; 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);



并且绘制:



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

glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
glDrawArrays(GL_PATCHES,0,nrOfPatches);



顶点着色器:



< #version 430 core
in vec4 posIn;

out gl_PerVertex {
vec4 gl_Position;
};

void main(){
gl_Position = posIn;
}



控制着色器:



  #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; $ b $ g 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;
}



评估着色器:



  #version 430 
#extension GL_ARB_tessellation_shader:启用
布局(quad,equal_spacing,ccw)

uniform mat4 ProjView;
uniform sampler2D PerlinNoise;

out vec3 PosW;
out vec3正常;
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);
}



碎片着色器:



  #version 430核心
在vec3 PosW;
in vec3 Normal;
in vec4 ColorFrag;
in vec4 PosH;

out vec3 FragColor;
out vec3 FragNormal;

void main(){
FragNormal = Normal;
FragColor = ColorFrag.xyz;
}



我尝试过硬编码不同的细分级别,但没有帮助。我最近开始使用OpenGL,所以请让我知道,如果我做一些愚蠢的事情。



因此,任何人都有任何想法,可能导致这种闪烁 ?



更新:我有一个朋友运行该项目,他有相同的闪烁镶嵌模式,但是失败的补丁根本没有绘制,除非过度镶嵌。

解决方案

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

  glPatchParameteri(GL_PATCH_VERTICES,4); 
glBindVertexArray(VertexArray);

(提示:对于您的地形使用drawelements, br>
在控制着色器中,使用

 布局(vertices = 

,因为您的补丁有4个控制点。顺序仍然很重要(CCW / CW)。

我个人不喜欢使用内置变量,因此对于顶点着色器,您可以将顶点数据发送到tesscontrol,如下所示:

  layout(location = 0)out vec3 outPos; 
....
outPos.xz = grid.xy;
outPos.y = noise(outPos.xz);

Tess控制:



< layout(location = 0)in vec3 inPos []; //从顶点着色器中取出outPos(location = 0)
//按照它们发送的顺序收集4个控制点到数组
layout(location = 0)out vec3 outPos []; //发送c.points到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



tessev很简单:

  layout(location = 0)in vec3 inPos []; // 4个控制点
layout(location = 0)out vec3 outPos; //这不再是数组,接下来是片段着色器
...
//编辑:不要忘记添加下一行
layout(quad)

vec3 interpolate3D(vec3 v0,vec3 v1,vec3 v2,vec3 v3)//在四边形上的x,y,z坐标的线性插值
{
return 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] //四边形的四个控制点。每个其他点根据TessCoord在它们之间进行线性内插。
gl_Position = mvp * vec4(outPos,1.0f);

四元域的一个很好的表示: 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(带有fraps)运行,具有运行时正常计算和双三次平滑等。我使用AMD HD 5750.它仍然可以更快,更好的代码和预焙正常:D。 (最大运行速度为120 w / o正常计算)



哦,如果你在着色器中移动顶点,你只能发送x和z坐标。




很多顶点。


I just started with OpenGL tessellation and have run into a bit a trouble. I am tessellating series of patches formed by one vertex each. These vertices/patches are structured in a gridlike fashion to later form a terrain generated by Perlin Noise.

The problem I have run into is that starting from the second patch, and every 5th patch after that, sometimes have a lot of tessellation (not the way i configured) but most of the time it doesn't get tessellated at all.

Like so:

  

The two white circles mark the highly/over tessellated patches. Also note the pattern of untessellated patches.

The strange thing is that it works on my Surface Pro 2 (Intel HD4400 graphics) but bugs on my main desktop computer (AMD HD6950 graphics). Is it possible the hardware is bad?

The patches are generated with the code:

    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);

And drawn with:

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

    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    glDrawArrays(GL_PATCHES, 0, nrOfPatches);

Vertex Shader:

#version 430 core
in vec4 posIn;

out gl_PerVertex {
    vec4 gl_Position;
};

void main() {
    gl_Position = posIn;
}

Control shader:

#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;
}

Evaluation shader:

#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);
}

Fragment shader:

#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;
}

I have tried to hardcode the different tessellation levels but that did not help. I recently started out with OpenGL so please let me know if i am doing something stupid.

So does anyone have any idea what could be causing this "flickering" of certain patches?

Update: I had a friend run the project and he got the same pattern of flickering tessellation but the failing patches were not drawn at all except when being overly tessellated. He has the same graphics card as I do (AMD HD6950).

解决方案

You should use triangle/quad tessellation, in which each patch has 3 or 4 vertices. As I can see, you use quads (I use them too). In that case, you can set it like this:

glPatchParameteri(GL_PATCH_VERTICES,4);
glBindVertexArray(VertexArray);

(TIP: use drawelements for your terrain, much better performance for 2D-displacement based mesh.)
In the control shader, use

layout (vertices = 4) out;

since your patch has 4 control points. The ordering is still important (CCW/CW).
Personally I don't like to use built-in variables, so for the vertex shader you can send your vertex data to the tesscontrol like this:

layout (location = 0) out vec3 outPos;
....
outPos.xz = grid.xy;
outPos.y = noise(outPos.xz);

Tess control:

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

Note that both in and out vertex data is an array.

The tessev is simple:

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);

A good representation of the quad domain: http://ogldev.atspace.co.uk/www/tutorial30/tutorial30.html.

I think the problem is with your one-vertex patch. I cannot imagine how a one vertex path can be divided into triangles, I don't know how it works on another hardware. The tessellation is for divide primitives into other simple primitives, to triangles in case of OGL, since it can be handled by a GPU easily (3 points always lie in a plane). So, the minimum number of patch vertices should be 3, for a triangle. I like quads, because it simplier to index, and the memory cost is less. It will be divided into triangles too during tessellation. http://www.informit.com/articles/article.aspx?p=2120983 Also, there is another type, the isoline tessellation. (check out the links, the second is pretty good.)

All in all, try it with quads or triangles, and set the control vertices to 4 (or 3). My (pretty complex) terrain shader is here with frustum culling, tessellation shader culling for a geoclipmap based terrain. Also, without tessellation it works with vertex morph in vertex shader. Maybe some part of this code will be useful. http://speedy.sh/TAvPR/gshader.txt

A scene with tessellation at about 4 pixels/triangle runs at 75 FPS (with fraps) with runtime normal calculation and bicubic smoothing and other things. I'm using AMD HD 5750. It still could be much faster with better code and pre-baked normals:D. (runs at max 120 w/o normal calc.)

Oh, and you can only send the x and z coords if you displace the vertex in the shader. It will be faster too.

Lots of vertices.

这篇关于GLSL / OpenGL着色器镶嵌闪烁和失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆