Я хочу добавить направленный свет в свою сцену, используя OpenGL и GLSL. Проблема в том, что теоретически правильный способ сделать это приводит к неправильным результатам.
В вершинном шейдере я делаю следующее:
Направление света задается в мировых координатах и преобразуется с помощью viewMatrix в координаты камеры. Нормаль вершины преобразуется с помощью матрицы нормалей в координаты камеры.
void main () {
vary_textureCoord = attribute_textureCoord;
vary_normal = mat3(normalMatrix) * attribute_normal;
vary_directionalLight_direction = viewMatrix * vec4(lightDir, 1.0);
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(attribute_position, 1.0);
}
Таким образом, оба вектора находятся в координатах камеры и передаются фрагментному шейдеру. Фрагментный шейдер вычисляет интенсивность света, используя нормаль и направление света.
void main () {
vec3 normalizedNormal = normalize(vary_normal);
vec4 color = texture(tex, vary_textureCoord);
float directionalLightIntensity = max(0.0, dot(normalizedNormal, normalize(-vary_directionalLight_direction.xyz)));
out_color = color * directionalLightIntensity;
}
Этот шейдер приводит к тому, что свет не статичен, а движется вместе с камерой. Изменение вершинного шейдера с помощью этой строки:
vary_directionalLight_direction = transpose(inverse(viewMatrix)) * vec4(lightDir, 1.0);
имеет желаемые результаты. Так что же я делаю не так или где у меня недопонимание?
Вот полные коды шейдеров:
Вершинный шейдер:
# version 330
layout(location = 0) in vec3 attribute_position;
layout(location = 2) in vec2 attribute_textureCoord;
layout(location = 3) in vec3 attribute_normal;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
uniform mat4 normalMatrix;
uniform vec3 lightDir;
out vec2 vary_textureCoord;
out vec3 vary_normal;
out vec4 vary_directionalLight_direction;
void main () {
vary_textureCoord = attribute_textureCoord;
vary_normal = mat3(normalMatrix) * attribute_normal;
vary_directionalLight_direction = viewMatrix * vec4(lightDir, 1.0);
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(attribute_position, 1.0);
}
Фрагментшейдер:
# version 330
in vec2 vary_textureCoord;
in vec3 vary_normal;
in vec4 vary_directionalLight_direction;
uniform sampler2D tex;
out vec4 out_color;
void main () {
vec3 normalizedNormal = normalize(vary_normal);
vec4 color = texture(tex, vary_textureCoord);
float directionalLightIntensity = max(0.0, dot(normalizedNormal, normalize(-vary_directionalLight_direction.xyz)));
out_color = color * directionalLightIntensity;
}