Нормальное отображение с освещением в openGL

Я пытаюсь реализовать нормальное отображение и освещение в моем фрагментном шейдере. Но мои коды, похоже, не работают. Моя идея - передать дополнительную копию ModelMatrix фрагментному шейдеру, чтобы он мог преобразовать нормали, хранящиеся в текстуре. Но отраженный свет на самом деле происходит на другой стороне.

[Обновления] После получения некоторых советов я вычислил матрицу TBN в вершинном шейдере, преобразовал базу TBN в мировое пространство, преобразовал lightPosition и eyePosition в tangentSpace. Но на этот раз планета даже не светит вообще! Только окружающий свет появляется. Затем я обнаружил, что это произошло потому, что компонент diffuse оценивает отрицательные значения, которые затем фиксируются на 0. Кажется, я не могу найти ошибку в шейдере.

VertexShader:

#version 400

in layout(location=0) vec3 vertexPosition;
in layout(location=1) vec2 vertexUV;
in layout(location=2) vec3 vertexNormal;
in layout(location=3) vec3 vertexTangent;
in layout(location=4) vec3 vertexBitangent;

out vec2 UV;
out vec3 vertexPositionWorld;
out vec3 tangentLightPos;
out vec3 tangentViewPos;
out vec3 tangentFragPos;

uniform vec3 lightPositionWorld;
uniform vec3 eyePositionWorld;

uniform mat4 M;
uniform mat4 V;
uniform mat4 P;

void main()
{
gl_Position = P * V * M * vec4(vertexPosition, 1.0f);
vertexPositionWorld = vec3(M * vec4(vertexPosition, 1.0f));
UV = vertexUV;

// note scaling problem here 
mat3 normalMatrix = transpose(inverse(mat3(M)));
// mat3 normalMatrix = inverse(transpose(mat3(M)));
vec3 T = normalize(normalMatrix * vertexTangent);
vec3 B = normalize(normalMatrix * vertexBitangent);
vec3 N = normalize(normalMatrix * vertexNormal);

mat3 TBN = transpose(mat3(T, B, N));
tangentLightPos = TBN * lightPositionWorld;
tangentViewPos = TBN * eyePositionWorld;
tangentFragPos = TBN * vertexPositionWorld;
}

FragmentShader:

#version 400

uniform sampler2D textureSampler_1;
uniform sampler2D textureSampler_2;
uniform vec3 AmbientLightPower;
uniform vec3 DiffuseLightPower;
uniform vec3 SpecularLightPower;
uniform float specularLightPower;

in vec2 UV;
in vec3 vertexPositionWorld;
in vec3 tangentLightPos;
in vec3 tangentViewPos;
in vec3 tangentFragPos;

out vec4 finalColor;

void main()
{
vec3 normal = texture(textureSampler_2, UV).rgb;
normal = normalize(normal * 2.0 - 1.0);

vec3 MaterialAmbientColor = texture( textureSampler_1, UV ).rgb;
vec3 MaterialDiffuseColor = texture( textureSampler_1, UV ).rgb;
vec3 MaterialSpecularColor = vec3(0.3,0.3,0.3);
// diffuse light
vec3 lightDirection = normalize(tangentLightPos - tangentFragPos);
float DiffuseBrightness = clamp(dot(lightDirection, normal), 0, 1);

// specular light
vec3 reflectedDirection = normalize(reflect(-lightDirection, normal));
vec3 viewDirection = normalize(tangentViewPos - tangentFragPos);
float SpecularBrightness = clamp(dot(reflectedDirection, viewDirection), 0, 1);

finalColor = vec4(

MaterialAmbientColor  * AmbientLightPower +

MaterialDiffuseColor  * DiffuseLightPower * DiffuseBrightness +

MaterialSpecularColor * SpecularLightPower * pow(SpecularBrightness, specularLightPower), 1.0f);
}

1 ответ

Ваш подход - взять карту нормалей и преобразовать ее в матрицу модели. Это действительно только тогда, когда карта нормалей является картой норм мирового пространства. Карты нормального пространства в мире используются редко, обычно карты нормалей представляют собой карты нормалей касательного пространства. Если вы не уверены, какой у вас тип карты нормалей, то вы можете проверить текстуру - если она выглядит в основном синей, то, скорее всего, у вас есть карта нормалей касательного пространства, если она очень многоцветная, то, вероятно, это мировое пространство и мой ответ не подходит для вас.

Чтобы работать с картами нормалей касательного пространства, вам нужно проделать немного больше работы. Как правило, в вершинном шейдере вы получаете некоторые базисные векторы (Normal, Binormal и Tangent aka NBT), и вы используете эти векторы либо для преобразования карты нормалей в мировое пространство, либо для преобразования положения света в касательное пространство (последнее часто более эффективно для небольшого количества источников света, потому что вы выполняете больше работы в вершинном шейдере).

Касательное пространство - сложная задача, чтобы поразмыслить, и я бы посоветовал немного прочитать тему. Эта статья может стать достойным началом.

Другие вопросы по тегам