GLSL:旋转正常

GLSL: Rotating Normal

本文关键字:旋转 GLSL      更新时间:2023-10-16

有一个场景,里面有一些物体和一个地形。当我尝试旋转对象时,法线保持不变。意味着物体的黑暗面保持物体的黑暗面。我的镜面闪电正在工作。

顶点着色器:

uniform vec3 lightPos;
uniform sampler2D Texture;
varying vec2 TexCoord;
varying vec3 position;
varying vec3 vertex;
varying mat3 nMat;
varying mat3 vMatrix;
varying vec3 normal;
varying vec3 oneNormal;
varying vec3 lightPos2;
void main()
{
        gl_Position=gl_ModelViewProjectionMatrix*gl_Vertex;
        position=vec3(gl_ModelViewMatrix*gl_Vertex);
        vMatrix = mat3(gl_ModelViewMatrix);
        lightPos2 = vec3(gl_ModelViewMatrix*vec4(lightPos,1.0));
        vertex = vec3(gl_Vertex);
        nMat = gl_NormalMatrix;
        normal=gl_NormalMatrix*gl_Normal;
        oneNormal = gl_Normal;
        TexCoord=gl_MultiTexCoord0.xy;
}

片段着色器:

varying vec3 position;
varying vec3 normal;
uniform sampler2D Texture;
varying vec2 TexCoord;
uniform vec3 lightPos;
varying vec3 vertex;
uniform vec3 lambient;
uniform vec3 ldiffuse;
uniform vec3 lspecular;
uniform float shininess;
varying mat3 nMat;
varying mat3 vMatrix;
varying vec3 oneNormal;
varying vec3 lightPos2;

void main()
{
        float dist=length(vertex-lightPos);
        float att=1.0/(1.0+0.1*dist+0.01*dist*dist);
        vec4 TexColor = texture2D(Texture, TexCoord);
        vec3 ambient=TexColor.rgb*lambient; //the ambient light
    //=== Diffuse ===//
        vec3 surf2light=normalize(position-lightPos2);
        float dcont=max(0.0, 
                    dot( normalize(nMat*(-normal)), nMat*surf2light) );
        vec3 diffuse=dcont*(TexColor.rgb*ldiffuse);
    //=== Specular ===//
        vec3 surf2view = normalize(lightPos-position);
        surf2light=nMat*normalize(-vertex);
        vec3 reflection=reflect(-surf2view,normalize(normal));
        float scont=pow(max(0.0,dot(surf2light,reflection)),shininess);
        vec3 specular=scont*lspecular;
        gl_FragColor=vec4((ambient+diffuse+specular)*att,1.0);
}

你正在变换法线。但至少对于部分照明计算,您使用的是光源位置,该位置也会转换为相同的坐标空间。如果同时变换法线光源,则法线相对于光源的方向将再次相同。

从顶点着色器中提取关键线:

    position=vec3(gl_ModelViewMatrix*gl_Vertex);
    lightPos2 = vec3(gl_ModelViewMatrix*vec4(lightPos,1.0));
    normal=gl_NormalMatrix*gl_Normal;

gl_NormalMatrix对应于gl_ModelViewMatrix,并进行了必要的调整以变换方向向量而不是点。因此,模型视图变换已应用于所有positionlightPos2normal

然后,所有这三个值(应用插值)都传递到片段着色器中,您可以在其中计算漫射照明项:

    vec3 surf2light=normalize(position-lightPos2);
    float dcont=max(0.0, 
                dot( normalize(nMat*(-normal)), nMat*surf2light) );
    vec3 diffuse=dcont*(TexColor.rgb*ldiffuse);

现在,这里有几个问题:

  • 您再次将nMat(法线矩阵)应用于两个向量,即使它们已经变换过。它没有害处,因为如果您对两个向量应用相同的旋转,点积不会改变,但这没有意义。
  • 所有使用的值(positionlightPos2normal)都由模型视图矩阵转换。因此,它们的相对位置/方向与原始位置/方向完全相同。计算结果将与应用于相应的未变换向量时的结果相同。

您需要确定要用于照明计算的坐标系。至少有几个选择。对您来说最简单的方法可能是使用眼睛坐标空间。为此,可以在将光源位置传递到着色器之前将视图转换应用于光源位置,然后在着色器代码中直接使用此光源位置,而无需任何其他转换。

由于您说镜面反射照明按预期工作,并且您在那里使用均匀lightPos,因此它可能就像使用该变量而不是在漫反射计算中lightPos2一样简单。