关于glsl:着色器中的OpenGL Normal转换

OpenGL Normal transformation in shaders

我正在尝试在LWJGL中创建一些基本的照明着色器。一切似乎都正常,只是当我改变相机的旋转角度时,灯光也会改变。我认为这是因为旋转相机时法线的旋转也被弄乱了。

这是我原来的顶点着色器:

1
2
3
4
5
6
7
8
uniform vec3 lightDir;
varying vec3 normal;

void main()
{      
    normal = gl_NormalMatrix*gl_Normal;
    gl_Position = ftransform();
}

我的片段着色器:

1
2
3
4
5
6
7
8
9
10
varying vec3 normal;

void main(){
    vec3 color = vec3(1,1,1);
    vec3 lightDir = vec3(1,1,0);
    float inten = 1;
    color = color*dot(normal, lightDir)*inten;
    gl_FragColor = vec4(color,1);

}

要转换我使用的相机:

1
2
3
4
5
6
7
8
9
public static void applyTranslations() {
    glPushAttrib(GL_TRANSFORM_BIT);
    glMatrixMode(GL_MODELVIEW);
    glRotatef(pitch, 1, 0, 0);
    glRotatef(yaw, 0, 1, 0);
    glRotatef(roll, 0, 0, 1);
    glTranslatef(-x, -y, -z);
    glPopAttrib();
}

我意识到,这种变换相机的方法实际上可能是在相机保持静态的同时更改模型,这会弄乱法线,因此我尝试输入一个包含模型旋转的统一矩阵来变换法线,但这并没有。似乎也不起作用。现在整个模型都是黑色的。 (除旋转外,它之前一直在工作。)
我用它来将更改传递给着色器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Vector3f scale, rot, trans;
Matrix3f modelMatrix = new Matrix3f();
modelMatrix.setIdentity();
scale = new Vector3f(1,1,1);
rot = new Vector3f(xRot,yRot,zRot);
trans = new Vector3f(x,y,z);

Matrix4f.scale(scale, modelMatrix, modelMatrix);
Matrix4f.translate(trans, modelMatrix, modelMatrix);
Matrix4f.rotate((float) Math.toRadians(rot.z), new Vector3f(0,0,1), modelMatrix, modelMatrix);
Matrix4f.rotate((float) Math.toRadians(rot.y), new Vector3f(0,1,0), modelMatrix, modelMatrix);
Matrix4f.rotate((float) Math.toRadians(rot.x), new Vector3f(1,0,0), modelMatrix, modelMatrix);

FloatBuffer modelBuff = BufferUtils.createFloatBuffer(9);
modelMatrix.store(modelBuff);

int loc = ARBShaderObjects.glGetUniformLocationARB(e.m.shader.programID,"modelMatrix");
ARBShaderObjects.glUniformMatrix4ARB(loc, false, modelBuff);

然后将顶点着色器更改为:

1
2
3
4
5
6
7
8
9
uniform vec3 lightDir;
uniform modelMatrix;
varying vec3 normal;

void main()
{      
    normal = modelMatrix*gl_Normal;
    gl_Position = ftransform();
}

这是我应该做的创建并传递转换矩阵的事情吗?还有没有使用glRotatef()旋转照相机的另一种方法吗?


每次更换相机时,normal都会变换,而vec3 lightDir = vec3(1,1,0)不变。

为避免这种情况,请确保lightDirnormal在同一空间中。 在转换normal之前计算dot,或者将lightDir转换为gl_NormalMatrix,然后计算dot

除了要实现的效果外,片段着色器中还有一个问题:normal未标准化。 这是因为单位矢量的线性插值并不总是产生单位矢量。

您应该做的是这样的:

1
color*dot(normalize(normal),  transform_to_same_space(lightDir))*inten;

第二部分中的一些小问题:

您在声明modelMatrix没有类型。

您不能使用4x4矩阵变换vec3。 您可以将gl_Normal填充为0,因为它是矢量,或者将矩阵向下转换为float3x3

您将Matrix4f.scaleVector3f(1,1,1)一起使用,平移不会影响矢量,因此modelMatrix是正交的。
但是,通常情况下,应使用modelMatrix的转置逆来转换gl_Normal