Изменение значения Fragment Diffuse в зависимости от положения/вращения камеры

Я пытаюсь заставить простое рассеянное освещение работать в GLSL. У меня есть куб, который передается как массив точек, и я вычисляю нормали граней внутри своего геометрического шейдера (поскольку я намерен деформировать сетку во время выполнения, поэтому мне понадобятся новые нормали граней).

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

Вершина:

#version 330 core

layout(location = 0) in vec3 vertexPosition_modelspace;

uniform mat4 MVP;

void main(){     
    gl_Position =  MVP * vec4(vertexPosition_modelspace,1);
}

Геометрия:

#version 330

precision highp float;

layout (triangles) in;
layout (triangle_strip) out;
layout (max_vertices = 3) out;

out vec3 normal;
uniform mat4 MVP;
uniform mat4 MV;

void main(void)
{
    for (int i = 0; i < gl_in.length(); i++) {
        gl_Position = gl_in[i].gl_Position;


        vec3 U = gl_in[1].gl_Position.xyz - gl_in[0].gl_Position.xyz;
        vec3 V = gl_in[2].gl_Position.xyz - gl_in[0].gl_Position.xyz;

        normal.x = (U.y * V.z) - (U.z * V.y);
        normal.y = (U.z * V.x) - (U.x * V.z);
        normal.z = (U.x * V.y) - (U.y * V.x);

        normal = normalize(transpose(inverse(MV)) * vec4(normal,1)).xyz;

        EmitVertex();
    }
    EndPrimitive();
}

Фрагмент:

#version 330 core

in vec3 normal;
out vec4 out_color;
const vec3 lightDir = vec3(-1,-1,1);

uniform mat4 MV;

void main()
{
    vec3 nlightDir = normalize(vec4(lightDir,1)).xyz;
    float diffuse = clamp(dot(nlightDir,normal),0,1);

    out_color = vec4(diffuse*vec3(0,1,0),1.0);
}

Спасибо


person APalmer    schedule 17.05.2013    source источник


Ответы (1)


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

normal = normalize(transpose(inverse(MV)) * vec4(normal,1)).xyz;

Используя 1 в качестве четвертого компонента нормали, вы полностью нарушаете это вычисление. Это приводит к переводу нормали, что недопустимо.

Кроме того, ваше значение normal вычисляется на основе gl_Position. И gl_Position находится в пространстве клипа, а не в пространстве модели. Таким образом, все, что вы получаете, — это обычное clip-space, а это не то, что вам нужно, не нужно и даже не может быть использовано.

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

Кроме того, выполните инверсию/транспонирование на ЦП и передайте его шейдеру. О, и исключите из цикла все обычные вычисления; вам нужно сделать это только один раз для каждого треугольника (сохранить его в локальной переменной и скопировать в вывод для каждой вершины). И перестаньте делать кросс-произведение вручную; используйте встроенную функцию GLSL cross.

vec3 nlightDir = normalize(vec4(lightDir,1)).xyz;

Это имеет не больше смысла, чем использование 1 в качестве четвертого компонента в вашем преобразовании ранее. Просто нормализуйте lightDir напрямую.

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

person Nicol Bolas    schedule 17.05.2013