片段漫反射值随摄像机位置/旋转而变化

APa*_*mer 4 opengl lighting glsl geometry-shader fragment-shader

我试图让一些简单的漫射光在GLSL中工作.我有一个正在作为点数组传入的立方体,我正在计算几何着色器中的面法线(因为我打算在运行时使网格变形,所以我需要新的面法线.)

我的问题是当我将相机移动到世界各地时,漫反射值会发生变化.所以当我的立方体的脸上的阴影随着相机移动而改变.我无法弄清楚造成这种情况的原因.我的着色器如下:

顶点:

#version 330 core

layout(location = 0) in vec3 vertexPosition_modelspace;

uniform mat4 MVP;

void main(){     
    gl_Position =  MVP * vec4(vertexPosition_modelspace,1);
}
Run Code Online (Sandbox Code Playgroud)

几何:

#version 330

precision highp float;

layout (triangles) in;
layout (triangle_strip) out;
layout (max_vertices = 3) out;

out vec3 normal;
uniform mat4 MVP;
uniform mat4 MV;

void main(void)
{
    for (int i = 0; i < gl_in.length(); i++) {
        gl_Position = gl_in[i].gl_Position;


        vec3 U = gl_in[1].gl_Position.xyz - gl_in[0].gl_Position.xyz;
        vec3 V = gl_in[2].gl_Position.xyz - gl_in[0].gl_Position.xyz;

        normal.x = (U.y * V.z) - (U.z * V.y);
        normal.y = (U.z * V.x) - (U.x * V.z);
        normal.z = (U.x * V.y) - (U.y * V.x);

        normal = normalize(transpose(inverse(MV)) * vec4(normal,1)).xyz;

        EmitVertex();
    }
    EndPrimitive();
}
Run Code Online (Sandbox Code Playgroud)

分段:

#version 330 core

in vec3 normal;
out vec4 out_color;
const vec3 lightDir = vec3(-1,-1,1);

uniform mat4 MV;

void main()
{
    vec3 nlightDir = normalize(vec4(lightDir,1)).xyz;
    float diffuse = clamp(dot(nlightDir,normal),0,1);

    out_color = vec4(diffuse*vec3(0,1,0),1.0);
}
Run Code Online (Sandbox Code Playgroud)

谢谢

Nic*_*las 8

你的代码中有很多错误的东西.你的大部分问题都来自于完全忘记了各种向量所在的空间.你无法在不同空间的向量之间进行有意义的计算.

normal = normalize(transpose(inverse(MV)) * vec4(normal,1)).xyz;
Run Code Online (Sandbox Code Playgroud)

通过使用1作为法线的第四个分量,你完全打破了这个计算.它导致法线被翻译,这是不合适的.

此外,您的normal价值是基于gl_Position.并且gl_Position剪辑空间中,而不是模型空间.所以你得到的是剪辑空间正常,这不是你需要,想要或甚至可以使用的.

如果要计算相机空间法线,请从相机空间位置计算它.或者从模型空间位置计算模型空间法线,并使用模型/视图矩阵将其转换为相机空间.

此外,在CPU上执行反转/转置并将其传递给着色器.哦,把所有正常的计算都从循环中取出来; 你只需要为每个三角形做一次(将它存储在局部变量中并将其复制到每个顶点的输出).并手动停止交叉产品; 使用内置的GLSL cross功能.

vec3 nlightDir = normalize(vec4(lightDir,1)).xyz;
Run Code Online (Sandbox Code Playgroud)

这比使用1作为之前转换中的第四个组件没有任何意义.lightDir直接正常化.

同样重要的是,如果你在相机空间进行照明,那么光线方向需要随着相机而改变,以使其在世界上保持相同的明显方向.所以你将不得不采取你的世界空间光位置并将其转换为相机空间(通常在CPU上,作为制服传入).