Зеркальное освещение появляется как на лицевой, так и на задней стороне объекта
Я пишу небольшой тест на затенение Фонга и бью себя по голове о кирпичную стену, пытаясь заставить зеркальный компонент работать. Кажется, он работает правильно, за исключением того, что зеркальный свет применяется как к передней, так и к задней части объекта. (Сам объект прозрачный, грани отсортированы вручную на стороне процессора.)
Обратите внимание, что рассеянный компонент работает отлично (отображается только на стороне, обращенной к источнику света) - что, по-моему, исключает проблему с нормалями, поступающими в фрагментный шейдер, я думаю.
Как я понимаю, зеркальный компонент пропорционален cos угла между вектором глаза и вектором отраженного света.
Для простоты мой тестовый код пытается сделать это в мировом пространстве. Положение камеры и вектор света жестко закодированы (извините) как (0,0,4)
а также (-0.707, 0, -0.707)
соответственно. Следовательно, вектор глаз (0,0,4) - fragPosition
,
Поскольку матрица модели выполняет только вращение, вершинный шейдер просто преобразует нормаль вершины с помощью матрицы модели. (Примечание: это не очень хорошая практика, так как многие типы преобразований не сохраняют нормальную ортогональность. Как правило, для нормальной матрицы следует использовать обратную транспонирование верхнего левого 3x3 матрицы модели.) Чтобы упростить задачу, фрагмент шейдер работает по одному цветному каналу с плавающей точкой и пропускает показатель зеркальности (/ использует показатель 1).
Вершинный шейдер:
#version 140
uniform mat4 mvpMtx;
uniform mat4 modelMtx;
in vec3 inVPos;
in vec3 inVNormal;
out vec3 normal_world;
out vec3 fragpos_world;
void main(void) {
gl_Position = mvpMtx * vec4(inVPos, 1.0);
normal_world = vec3(modelMtx * vec4(inVNormal, 0.0));
fragpos_world = vec3(modelMtx * vec4(inVPos, 1.0));
}
Фрагмент шейдера:
#version 140
uniform float
uLightS,
uLightD,
uLightA;
uniform float uObjOpacity;
in vec3 normal_world, fragpos_world;
out vec4 fragOutColour;
void main(void) {
vec3 vN = normalize(normal_world);
vec3 vL = vec3(-0.707, 0, -0.707);
// Diffuse:
// refl in all directions is proportional to cos(angle between -light vector & normal)
// i.e. proportional to -l.n
float df = max(dot(-vL, vN), 0.0);
// Specular:
// refl toward eye is proportional to cos(angle between eye & reflected light vectors)
// i.e. proportional to r.e
vec3 vE = normalize(vec3(0, 0, 4) - fragpos_world);
vec3 vR = reflect(vL, vN);
float sf = max(dot(vR, vE), 0.0);
float col = uLightA + df*uLightD + sf*uLightS;
fragOutColour = vec4(col, col, col, uObjOpacity);
}
Я не могу найти ошибку здесь; Кто-нибудь может объяснить, почему зеркальный компонент появляется сзади, а также на светлой стороне объекта?
Большое спасибо.
2 ответа
Ваш зеркальный вклад на самом деле будет одинаковым для передней и задней граней, потому что GLSL reflect
нечувствителен к признаку нормального. Из этой ссылки:
reflect(I, N) = I - 2.0 * dot(N, I) * N
таким образом, изменение знака N вводит два знака минус, которые отменяются. На словах, что reflect
делает, чтобы поменять знак компонента I
который находится на той же оси, что и N
, Это не зависит от того, каким образом N
сталкивается.
Если вы хотите удалить зеркальный компонент с ваших задних граней, я думаю, вам нужно будет точно проверить ваш dot(vE,vN)
,
Попробуйте изменить
fragpos_world = vec3(modelMtx * vec4(inVPos, 0.0));
в
fragpos_world = vec3(modelMtx * vec4(inVPos, 1.0));
потому что http://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices/