将法线应用于四边形时,OpenGL会产生奇怪的结果

时间:2015-03-22 17:41:14

标签: opengl lighting normals

我在白墙上遇到了问题,你可以看到:

enter image description here

以下是我用来制作一块墙的代码,我用这些来制作整个建筑。我只是为了更简单的坐标制作了一个立方体,添加了法线,然后根据我想要使用的地方以两种可能的方式缩放它。这是代码

    private static void wallUnit(GLAutoDrawable glAutoDrawable, int param) {
    GL2 gl2 = glAutoDrawable.getGL().getGL2();

    gl2.glBindTexture(gl2.GL_TEXTURE_2D, 1);

    if (param == 0)
        gl2.glScalef(0.5f, 3f, 6f); // side wall
    else
        gl2.glScalef(6f, 3f, 0.5f); // front/ back walls

    gl2.glBegin(gl2.GL_QUADS);    

    // Back face
    gl2.glNormal3f(0.0f, 0.0f, -1.0f); // quad normal
    gl2.glTexCoord2f(0.0f, 0.0f);
    gl2.glVertex3f(-1.0f, -1.0f, -1.0f);
    gl2.glTexCoord2f(2.0f, 0.0f);
    gl2.glVertex3f(1.0f, -1.0f, -1.0f); 
    gl2.glTexCoord2f(2.0f, 2.0f);
    gl2.glVertex3f(1.0f, 1f, -1.0f);  
    gl2.glTexCoord2f(0.0f, 2.0f);
    gl2.glVertex3f(-1.0f, 1f, -1.0f);        

    // Bottom face
    gl2.glNormal3f(1.0f, 0.0f, 0.0f); // quad normal
    gl2.glTexCoord2f(0.0f, 0.0f);
    gl2.glVertex3f(-1.0f, -1.0f, -1.0f);
    gl2.glTexCoord2f(2.0f, 0.0f);
    gl2.glVertex3f(1.0f, -1.0f, -1.0f); 
    gl2.glTexCoord2f(2.0f, 2.0f);
    gl2.glVertex3f(1.0f, -1.0f, 1.0f);   
    gl2.glTexCoord2f(0.0f, 2.0f);
    gl2.glVertex3f(-1.0f, -1.0f, 1.0f);        

    // Right side
    gl2.glNormal3f(0.0f, -1.0f, 0.0f); // quad normal
    gl2.glTexCoord2f(0.0f, 0.0f);
    gl2.glVertex3f(1.0f, -1.0f, -1.0f);
    gl2.glTexCoord2f(2.0f, 0.0f);
    gl2.glVertex3f(1.0f, -1.0f, 1.0f);    
    gl2.glTexCoord2f(2.0f, 2.0f);
    gl2.glVertex3f(1.0f, 1.0f, 1.0f);     
    gl2.glTexCoord2f(0.0f, 2.0f);
    gl2.glVertex3f(1.0f, 1f, -1.0f);         

    // Top face
    gl2.glNormal3f(-1.0f, 0.0f, 0.0f); // quad normal
    gl2.glTexCoord2f(0.0f, 0.0f);
    gl2.glVertex3f(1.0f, 1.0f, 1.0f);
    gl2.glTexCoord2f(2.0f, 0.0f);
    gl2.glVertex3f(1.0f, 1f, -1.0f);   
    gl2.glTexCoord2f(2.0f, 2.0f);
    gl2.glVertex3f(-1.0f, 1f, -1.0f); 
    gl2.glTexCoord2f(0.0f, 2.0f);
    gl2.glVertex3f(-1.0f, 1f, 1.0f);        

    // Left side
    gl2.glNormal3f(0.0f, 1.0f, 0.0f); // quad normal
    gl2.glTexCoord2f(0.0f, 0.0f);
    gl2.glVertex3f(-1.0f, -1.0f, -1.0f);  
    gl2.glTexCoord2f(2.0f, 0.0f);
    gl2.glVertex3f(-1.0f, -1.0f, 1.0f);    
    gl2.glTexCoord2f(2.0f, 2.0f);
    gl2.glVertex3f(-1.0f, 1.0f, 1.0f);     
    gl2.glTexCoord2f(0.0f, 2.0f);
    gl2.glVertex3f(-1.0f, 1f, -1.0f);        

    // Front face
    gl2.glNormal3f(0.0f, 0.0f, 1.0f); // quad normal
    gl2.glTexCoord2f(0.0f, 0.0f);
    gl2.glVertex3f(-1.0f, -1.0f, 1.0f);
    gl2.glTexCoord2f(2.0f, 0.0f);
    gl2.glVertex3f(1.0f, -1.0f, 1.0f);  
    gl2.glTexCoord2f(2.0f, 2.0f);
    gl2.glVertex3f(1.0f, 1f, 1.0f);
    gl2.glTexCoord2f(0.0f, 2.0f);
    gl2.glVertex3f(-1.0f, 1f, 1.0f);        

    gl2.glEnd();
}

现在你可以看到有一个问题,两块墙彼此相邻的法线相同,所以应该是相同的颜色,对吧?但相反,墙的一部分只是更暗。出了什么问题?

1 个答案:

答案 0 :(得分:0)

使用旧版固定管道,您当前的模型 - 视图转换将应用于法线。或者更准确地说,模型 - 视图变换的左上3×3子矩阵的逆转置应用于法线。这正是将相同的变换正确应用于法线向量所需要的。

您需要注意的一件事是,在应用此转换后,法线可能不再被标准化。默认情况下,它们会自动重新规范化。非标准化法线的典型症状是错误的光照计算,正如您在示例中看到的那样。

只要您的模型 - 视图转换仅包含旋转和翻译,您就无需担心。旋转不会更改矢量的长度,并且平移部分甚至不会应用于法线。但是,如果任何其他类型的变换是模型 - 视图矩阵的一部分,则法线必须在变换后重新规范化。

有两种方法可以在转换后强制重新标准化法线。如果除了旋转和平移之外,您的模型视图矩阵只包含统一缩放,您可以使用:

glEnable(GL_RESCALE_NORMAL);

这比更通用的选项更有效:

glEnable(GL_NORMALIZE);

这将执行法线的完全重新标准化,适用于任何类型的转换。需要此选项的典型转换类型是非均匀缩放或剪切变换。