2016-01-16 13 views
0

我正在使用QT5 Gui框架开发OpenGL应用程序,但是,我不是OpenGL的专家,在尝试模拟方向灯时遇到了一些问题。我使用'几乎'与我在WebGL应用程序中使用的相同的算法,它工作得很好。在OpenGL中模拟方向灯时的问题

该应用程序用于呈现大型网格块(每个由8个独立顶点表示)的多个相邻单元格,这意味着整个网格块的某些顶点在VBO中被复制。几何着色器中的每个面的法线计算如代码中所示。

QOpenGLWidget paintGL()正文。

void OpenGLWidget::paintGL() 
{ 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
    glEnable(GL_DEPTH_TEST); 
    glEnable(GL_CULL_FACE);   

    m_camera = camera.toMatrix(); 
    m_world.setToIdentity(); 

    m_program->bind(); 
    m_program->setUniformValue(m_projMatrixLoc, m_proj); 
    m_program->setUniformValue(m_mvMatrixLoc, m_camera * m_world); 

    QMatrix3x3 normalMatrix = (m_camera * m_world).normalMatrix(); 
    m_program->setUniformValue(m_normalMatrixLoc, normalMatrix); 

    QVector3D lightDirection = QVector3D(1,1,1); 
    lightDirection.normalize(); 
    QVector3D directionalColor = QVector3D(1,1,1); 
    QVector3D ambientLight = QVector3D(0.2,0.2,0.2); 
    m_program->setUniformValue(m_lightDirectionLoc, lightDirection); 
    m_program->setUniformValue(m_directionalColorLoc, directionalColor); 
    m_program->setUniformValue(m_ambientColorLoc, ambientLight); 

    geometries->drawGeometry(m_program); 
    m_program->release(); 
    } 
} 

顶点着色器

#version 330 
layout(location = 0) in vec4 vertex; 
uniform mat4 projMatrix; 
uniform mat4 mvMatrix; 

void main() 
{ 
    gl_Position = projMatrix * mvMatrix * vertex; 
} 

几何着色器

#version 330 
layout (triangles) in; 
layout (triangle_strip, max_vertices = 3) out; 
out vec3 transformedNormal; 
uniform mat3 normalMatrix; 

void main() 
{ 
    vec3 A = gl_in[2].gl_Position.xyz - gl_in[0].gl_Position.xyz; 
    vec3 B = gl_in[1].gl_Position.xyz - gl_in[0].gl_Position.xyz; 

    gl_Position = gl_in[0].gl_Position; 
    transformedNormal = normalMatrix * normalize(cross(A,B)); 
    EmitVertex(); 
    gl_Position = gl_in[1].gl_Position; 
    transformedNormal = normalMatrix * normalize(cross(A,B)); 
    EmitVertex(); 
    gl_Position = gl_in[2].gl_Position; 
    transformedNormal = normalMatrix * normalize(cross(A,B)); 
    EmitVertex(); 
    EndPrimitive(); 
} 

片段着色器

#version 330 
in vec3 transformedNormal; 
out vec4 fColor; 
uniform vec3 lightDirection; 
uniform vec3 ambientColor; 
uniform vec3 directionalColor; 

void main() 
{ 
     highp float directionalLightWeighting = max(dot(transformedNormal, lightDirection), 0.0); 
     vec3 vLightWeighting = ambientColor + directionalColor * directionalLightWeighting; 
     highp vec3 color = vec3(1, 1, 0.0); 
     fColor = vec4(color*vLightWeighting, 1.0); 
} 

的第一问题是在面即照明似乎改变每当摄像机角度C (相机位置不影响它,只有角度)。您可以在下面的快照中看到此行为。我的猜测是我在计算正常矩阵时做错了什么,但我无法弄清楚它是什么。 enter image description here

第二个问题(引起我头痛的问题)是无论何时相机移动时,单元格的边缘会显示块状和斜线,当相机四处移动时闪烁。当太多的细胞聚集在一起时,这种效应变得非常讨厌。

enter image description here

在快照使用的模型是仅有10个细胞的样品板,以更好地示出出现故障的影响。实际模型(网格块)包含多达200K个单元堆叠在一起。

编辑:第二个问题的解决方案。 我正在使用0.01f和50000.0f的znear/zfar,当我将 更改为1.0f时,此效应消失。根据OpenGL Wiki,这是由接近0.0的zNear剪切平面值造成的。随着zNear剪裁平面设置越来越接近0。0,深度缓存的有效精度显着降低

EDIT2:我试着调试绘制法线作为意见提出, 我很快就意识到,我可能不应该计算它们基于 GL_POSITION(后在VS MVP矩阵乘法)代替我应该使用 原始顶点位置,所以我修改的着色器如下:

顶点着色器(修订版)

#version 330 
layout(location = 0) in vec4 vertex; 
out vec3 vert; 
uniform mat4 projMatrix; 
uniform mat4 mvMatrix; 

void main() 
{ 
    vert = vertex.xyz; 
    gl_Position = projMatrix * mvMatrix * vertex; 
} 

几何着色器(修订版)

#version 330 
layout (triangles) in; 
layout (triangle_strip, max_vertices = 3) out; 
in vec3 vert []; 
out vec3 transformedNormal; 
uniform mat3 normalMatrix; 

void main() 
{ 
    vec3 A = vert[2].xyz - vert[0].xyz; 
    vec3 B = vert[1].xyz - vert[0].xyz; 

    gl_Position = gl_in[0].gl_Position; 
    transformedNormal = normalize(normalMatrix * normalize(cross(A,B))); 
    EmitVertex(); 
    gl_Position = gl_in[1].gl_Position; 
    transformedNormal = normalize(normalMatrix * normalize(cross(A,B))); 
    EmitVertex(); 
    gl_Position = gl_in[2].gl_Position; 
    transformedNormal = normalize(normalMatrix * normalize(cross(A,B))); 
    EmitVertex(); 
    EndPrimitive(); 
} 

但是,即使本变形例的表面的法线仍然与相机角度改变,如屏幕截图示出以下之后。我不知道如果正常的计算是错误的或正常的矩阵计算做错了或可能都...

enter image description here

EDIT3:第一个问题解决方案:从 transformedNormal = normalize(normalMatrix * normalize(cross(A,B))); 改变GS正常计算transformedNormal = normalize(cross(A,B));似乎解决了 的问题。从计算中删除正常矩阵固定了 问题,法线不随视角变化。

如果我错过了任何重要/相关信息,请在评论中通知我。

+1

单元边界是空洞还是不同的光线?如果有帮助,我会尝试QUAD_STRIP或TRIANGLE_STRIP。什么是渲染的场景大小和你的frustrums'z_near,z_far'和深度缓冲区'bit_width'?在这种情况下,深度缓冲区精度问题可能会降低'Z_far/z_near'的比例。您应该添加另一个通道并调试通过从几何着色器中将它们作为行发布来实际查看它们是否正确计算,从而绘制计算出的法线。 – Spektre

+0

这里的东西就像上一张图​​片[正常映射出现了可怕的错误](http://stackoverflow.com/a/28541305/2521214) – Spektre

+0

@Spektre,改变znear,zfar值为我解决了第二个问题,我编辑了原始帖子但idk为什么发生这种情况。我会尝试在GS中画出计算出的法线,看看它们是否正确计算。 我很抱歉,但我没有得到你的意思'单元格边界是洞或不同的照明? '我也不认为我可以在几何着色器中访问QUAD_STRIP。 –

回答

1
  1. 深度缓冲器精度

    深度缓冲器通常被存储为16或24位的缓冲器。这是浮点数的归一化到特定范围的硬件实现。所以你可以看到与标准float相比,尾数/指数的位数很少。

    如果我过于简单化的东西,并承担integer值而不是float然后16位缓冲区你有2^16值。如果你有znear=0.1zfar=50000.0,那么你在整个范围内只有65535个值。现在,当深度值为非线性时,在和附近获得更高的精度,在zfar平面附近降低很多,所以深度值将随着越来越高的步骤跳动,从而在任何2个多边形靠近时引起准确度问题。

    我凭经验得到这个在我的意见设置的平面:

    • (zfar-znear)/desired_accuracy_step > 0.3*(2^n)

    哪里n是深度缓冲位宽和desired_accuracy_step在Z轴想要的分辨率,我需要。有时我看到它通过znear值进行交换。

+0

这很有见地,谢谢 –