Шейдер направленного света OpenGL

Я хочу добавить направленный свет в свою сцену, используя 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;
}

person liphtip    schedule 27.12.2017    source источник


Ответы (1)


Матрица преобразования выглядит так:

( X-axis.x, X-axis.y, X-axis.z, 0 )
( Y-axis.x, Y-axis.y, Y-axis.z, 0 )
( Z-axis.x, Z-axis.y, Z-axis.z, 0 )
( trans.x,  trans.y,  trans.z,  1 ) 

Если вы хотите преобразовать позицию, вам необходимо применить к ней полную матрицу преобразования.

mat4 viewMatrix;
vec3 pos;
vec4 viewPos = viewMatrix * vec4(pos, 1.0);

Это применяет ориентацию и положение вида к положению pos.

Но направление не имеет начала. Направление имеет только ориентацию. Это означает, что если вы хотите преобразовать вектор направления по виду, вам нужно умножить его на верхнюю левую часть 3*3 4*4 viewMatrix:

vary_directionalLight_direction = vec4(mat3(viewMatrix) * lightDir, 1.0);
person Rabbid76    schedule 27.12.2017