Как преобразовать направленный свет в пространство камеры в GLSL

У меня есть следующий код GLSL для освещения:

uniform vec3 lightDir; // Parallel light
uniform float ambient;
uniform vec3 lightColour;

void main()
{
     gl_Position = ftransform();

     vec3 eyeNormal = normalize(gl_NormalMatrix * gl_Normal);
     float intensity = max(ambient, dot(eyeNormal, normalize(-lightDir));

     gl_FrontColor = gl_Color * vec4(lightColour, 1.0) * intensity;
}

Вектор света указан в мировом пространстве. Я устанавливаю ориентацию камеры и положение с помощью gluLookAt, Поскольку OpenGL предполагает, что вектор света находится в пространстве камеры, свет перемещается вместе с камерой, а не остается в фиксированной ориентации.

Я попытался активировать шейдер и установить вектор света до и после вызова gluLookAt, но я получаю тот же эффект. Что именно я должен сделать, чтобы правильно преобразовать вектор света?

5 ответов

У вас есть общая проблема, часто встречающаяся в онлайн-учебниках по GLSL. Вы передаете свои значения освещения через униформу. Почему бы вам не использовать glLight вызовы, как с фиксированным рендерингом функции, и получить значения из gl_LightSource[n], Разница в том, что openGL автоматически переведет все в поле зрения.

void main()
{
    // remember: directional lights are GL_POSITION with w = 0
    vec3 lightDir = vec3(gl_LightSource[0].position); 
    float ambient = gl_LightSource[0].ambient;
    vec3 lightColour = vec3(gl_LightSource[0].diffuse);


    gl_Position = ftransform();

    vec3 eyeNormal = normalize(gl_NormalMatrix * gl_Normal);
    float intensity = max(ambient, dot(eyeNormal, normalize(-lightDir));

    gl_FrontColor = gl_Color * vec4(lightColour, 1.0) * intensity;
}

Всегда отличный ресурс на эту тему: http://www.lighthouse3d.com/opengl/glsl/index.php?lights

Всегда полезен Cheat Cheat GLSL: http://www.cs.brown.edu/courses/cs123/resources/glslQuickRef.pdf

Вы должны решить, в каком месте вы будете делать освещение. Если вы хотите следовать "стандартному" OpenGL, тогда это пространство просмотра. Ваш световой вектор должен быть повернут вращением части матрицы вида перед тем, как перейти к шейдеру (это самое простое решение).

Вы также можете применять источники света в других местах (касательная, объект, мир или даже пространство экрана - для отложенного затенения), но это другая тема. Также обратите внимание, что для продвинутого использования вам нужно будет забыть OpenGL и делать все с вашими собственными матрицами и шейдерами (без освещения и преобразования по умолчанию).

Проблема в шейдере заключается в том, что у вас есть глазные нормальные пространства и световые пространства.
Я не уверен, но преобразование вашего светового вектора в вашу нормальную матрицу должно решить проблему.

Или, чтобы быть более эффективным, вы можете преобразовать vec освещения в объектном пространстве (в программном коде), тогда никакое преобразование для каждой нормали не требуется.

Я подозреваю, что часть проблемы заключается в: float intensity = max(ambient, dot(eyeNormal, normalize(-lightDir));,

Окружающий термин в ламбертовских шейдерах масштабируется точечным произведением. Здесь окружающий термин будет утверждаться часто, потому что он, вероятно, будет больше, чем скалярное произведение. Использование gl_NormalMatrix также является проблемой, потому что, как прокомментировано выше, это означает, что lightDir находится в пространстве объектов, в то время как вектор нормали преобразуется из пространства объектов в координаты глаза.

Пытаться:

vec3 n=normalize(normal);
float ndotl=max(0.0, dot(n, normalize(lightDir)));

vec3 diffuse=ambient * ndotl; 

Код в шейдере вычисляет направленный свет, который не меняется в зависимости от положения света, поэтому вам следует использовать функции spotLight или pointLight.

Попробуйте найти шейдеры для этих источников света. если вы не можете найти, скажите мне, чтобы я отправил вам один.

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