【问题标题】:Strange square lighting artefacts in OpenGLOpenGL中奇怪的方形照明伪影
【发布时间】:2012-06-13 06:59:57
【问题描述】:

我有一个程序可以生成高度图,然后使用 OpenGL 将其显示为网格。当我尝试添加照明时,最终会出现奇怪的方形覆盖网格。它们在某些区域比其他区域更明显,但始终存在。

我使用的是四边形网格,但切换到三角形网格后没有任何变化。我已经使用了至少三种不同的方法来计算顶点法线,都具有相同的效果。我正在使用着色器手动进行照明,但使用内置时没有任何变化 OpenGL 光照系统。

我最新的法线生成代码(faces 是一个指向顶点的索引数组,即顶点数组):

int i;
for (i = 0; i < NINDEX; i += 3) {
    vec v[3];
    v[0] = verts[faces[i + 0]];
    v[1] = verts[faces[i + 1]];
    v[2] = verts[faces[i + 2]];

    vec v1 = vec_sub(v[1], v[0]);
    vec v2 = vec_sub(v[2], v[0]);

    vec n = vec_norm(vec_cross(v2, v1));

    norms[faces[i + 0]] = vec_add(norms[faces[i + 0]], n);
    norms[faces[i + 1]] = vec_add(norms[faces[i + 1]], n);
    norms[faces[i + 2]] = vec_add(norms[faces[i + 2]], n);
}

for (i = 0; i < NVERTS; i++) {
    norms[i] = vec_norm(norms[i]);
}

虽然这不是我使用的唯一代码,但我怀疑它是否是问题的原因。

我用以下方法绘制网格:

glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, verts);

glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, 0, norms);

glDrawElements(GL_TRIANGLES, NINDEX, GL_UNSIGNED_SHORT, faces);

而且我目前没有使用任何着色器。

这可能是什么原因造成的?

编辑:一组更全面的屏幕截图:

对于最后一个,着色器代码是

顶点:

varying vec3 lightvec, normal;

void main() {
    vec3 lightpos = vec3(0, 0, 100);
    vec3 v = vec3(gl_ModelViewMatrix * gl_Vertex);
    normal = gl_NormalMatrix * gl_Normal;

    lightvec = normalize(lightpos - v);

    gl_Position = ftransform();
}

片段:

varying vec3 lightvec, normal;

void main(void) {
    float l = dot(lightvec, normal);
    gl_FragColor = vec4(l, l, l, 1);
} 

【问题讨论】:

  • 你能贴两张同一个场景的截图,一张有线框,一张没有?
  • norms 是零初始化的吗?您在没有先将其归零的情况下将向量累积到其中,但如果它在程序中的其他地方归零,这应该不是问题。
  • 您是否对着色器中的普通属性使用平滑插值?也许切换到flat 可以帮助定位问题。此外,OpenGL 照明对我来说往往是非常错误的 - 我通常更确定我自己编写的代码。
  • @genpfault:初始化时归零

标签: c opengl lighting


【解决方案1】:

您需要在片段着色器中对法线进行归一化,如下所示:

varying vec3 lightvec, normal;

void main(void) {
    vec3 normalNormed = normalize(normal);
    float l = dot(lightvec, normalNormed);
    gl_FragColor = vec4(l, l, l, 1);
} 

但这可能很昂贵。在这种情况下,使用定向光也可以使用顶点照明。所以在顶点着色器中计算光照值

varying float lightItensity;

void main() {
    vec3 lightpos = vec3(0, 0, 100);
    vec3 v = vec3(gl_ModelViewMatrix * gl_Vertex);
    normal = gl_NormalMatrix * gl_Normal;

    lightvec = normalize(lightpos - v);

    lightItensity = dot(normal, lightvec);

    gl_Position = ftransform();
}

并在片段着色器中使用它,

varying float light;

void main(void) {
    float l = light;
    gl_FragColor = vec4(l, l, l, 1);
} 

我希望这能解决它,如果没有,请告诉我。

编辑:这是一个解释最有可能发生的事情的小图表

EDIT2:

如果这没有帮助,请添加更多三角形。插入高度图的值并在其间添加一些顶点。

或者,尝试更改您的细分方案。例如,这样的等边三角形网格可以使伪影不那么突出。

你必须在你的高度图上做一些插值。

否则我不知道..祝你好运!

【讨论】:

  • 谢谢,但不幸的是我已经尝试过这样做。我开始怀疑问题出在我的显卡(1.5 年前的英特尔集成芯片)上。
  • 我非常怀疑。着色器代码应该在任何支持它的显卡上以相同的方式执行。
【解决方案2】:

对于非着色器版本,我没有明确的答案,但我想补充一点,如果您在片段着色器中进行逐像素照明,您可能应该在片段着色器中对法线和 lightvec 进行归一化.

如果您不这样做,它们就不是单位长度(两个归一化向量之间的线性插值不一定是归一化的)。这可以解释您在着色器版本中看到的一些伪影,因为点积的大小会根据与顶点的距离而变化,这看起来就像您所看到的那样。

编辑:另一个想法,您在渲染非着色器版本时是否对网格进行任何非均匀缩放(不同的 x、y、z)?如果你缩放它,那么你需要通过逆比例因子修改法线,或者设置glEnable(GL_NORMALIZE)。请参阅此处了解更多信息: http://www.lighthouse3d.com/tutorials/glsl-tutorial/normalization-issues/

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-09-04
    • 1970-01-01
    • 1970-01-01
    • 2017-01-25
    • 2017-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多