opengl - точечный свет перемещается при вращении камеры при использовании шейдера

Я реализовал простой шейдер для освещения; это вроде работает, но свет, кажется, движется, когда камера вращается (и только когда она вращается).

Я экспериментирую с прожектором, вот как это выглядит (это место в центре):

Если сейчас я поверну камеру, пятно перемещается; например, здесь я посмотрел вниз (я вообще не двигался, просто посмотрел вниз), и мне показалось, что у меня под ногами:

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

Дело в том, что я почти уверен, что не делаю эти две вещи, но, очевидно, я не прав; просто я не могу найти ошибку.

Вот шейдер:

Вершинный шейдер

varying vec3 vertexNormal;
varying vec3 lightDirection;

void main()
{
    vertexNormal = gl_NormalMatrix * gl_Normal;

    lightDirection = vec3(gl_LightSource[0].position.xyz - (gl_ModelViewMatrix * gl_Vertex).xyz);

    gl_Position = ftransform();
}

Фрагмент шейдера

uniform vec3 ambient;
uniform vec3 diffuse;
uniform vec3 specular;
uniform float shininess;

varying vec3 vertexNormal;
varying vec3 lightDirection;

void main()
{
    vec3 color = vec3(0.0, 0.0, 0.0);

    vec3 lightDirNorm;
    vec3 eyeVector;
    vec3 half_vector;
    float diffuseFactor;
    float specularFactor;
    float attenuation;
    float lightDistance;

    vec3 normalDirection = normalize(vertexNormal);

    lightDirNorm = normalize(lightDirection);

    eyeVector = vec3(0.0, 0.0, 1.0);
    half_vector = normalize(lightDirNorm + eyeVector);

    diffuseFactor = max(0.0, dot(normalDirection, lightDirNorm));

    specularFactor = max(0.0, dot(normalDirection, half_vector));
    specularFactor = pow(specularFactor, shininess);

    color += ambient * gl_LightSource[0].ambient;
    color += diffuseFactor * diffuse * gl_LightSource[0].diffuse;
    color += specularFactor * specular * gl_LightSource[0].specular;

    lightDistance = length(lightDirection[i]);

    float constantAttenuation = 1.0;
    float linearAttenuation = (0.02 / SCALE_FACTOR) * lightDistance;
    float quadraticAttenuation = (0.0 / SCALE_FACTOR) * lightDistance * lightDistance;

    attenuation = 1.0 / (constantAttenuation + linearAttenuation + quadraticAttenuation);

    // If it's a spotlight
    if(gl_LightSource[i].spotCutoff <= 90.0) 
    {
        float spotEffect = dot(normalize(gl_LightSource[0].spotDirection), normalize(-lightDirection));
        if (spotEffect > gl_LightSource[0].spotCosCutoff) 
        {
            spotEffect = pow(spotEffect, gl_LightSource[0].spotExponent);

            attenuation = spotEffect / (constantAttenuation + linearAttenuation + quadraticAttenuation);
        }
        else
            attenuation = 0.0;
    }

    color = color * attenuation;

    // Moltiplico il colore per il fattore di attenuazione
    gl_FragColor = vec4(color, 1.0);
}

Теперь я не могу показать вам код, в котором я визуализирую вещи, потому что это собственный язык, который интегрирует opengl и предназначен для создания 3D-приложений (это не поможет вам показать); но я делаю что-то вроде этого:

SetupLights();
UpdateCamera();
RenderStuff();

Куда:

  • SetupLights содержит фактические вызовы opengl, которые настраивают источники света и их положение;
  • UpdateCamera обновляет положение камеры, используя встроенные классы языка; У меня здесь мало сил;
  • RenderStuff вызывает встроенные функции языка для рисования сцены; У меня здесь тоже мало сил.

Так что либо я делаю что-то не так в шейдере, либо в языке есть что-то, что "за кадром" ломает вещи.

Можете ли вы указать мне правильное направление?

1 ответ

Вы написали

положение света уже в мировых координатах, и именно здесь я делаю вычисления

однако, поскольку вы применяете gl_ModelViewMatrix к своей вершине и gl_NormalMatrix к своей нормали, эти значения, вероятно, находятся в пространстве вида, что может вызвать перемещение света.

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

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