Фонг-зеркальное освещение в glsl (lwjgl)

В настоящее время я пытаюсь сделать зеркальное освещение на сфере, используя glsl и Phong-модель.

Вот так выглядит мой фрагментный шейдер:

#version 120
uniform vec4 color;
uniform vec3 sunPosition;
uniform mat4 normalMatrix;
uniform mat4 modelViewMatrix;
uniform float shininess;
// uniform vec4 lightSpecular;
// uniform vec4 materialSpecular;

varying vec3 viewSpaceNormal;
varying vec3 viewSpacePosition;

vec4 calculateSpecular(vec3 l, vec3 n, vec3 v, vec4 specularLight, vec4 materialSpecular) {
    vec3 r = -l+2*(n*l)*n;
    return specularLight * materialSpecular * pow(max(0,dot(r, v)), shininess);
}

void main(){
    vec3 normal = normalize(viewSpaceNormal);
    vec3 viewSpacePosition = (modelViewMatrix * vec4(gl_FragCoord.x, gl_FragCoord.y, gl_FragCoord.z, 1.0)).xyz;
    vec4 specular = calculateSpecular(sunPosition, normal, viewSpacePosition, vec4(0.3,0.3,0.3,0.3), vec4(0.3,0.3,0.3,0.3));
    gl_FragColor = color+specular;
}

SunPosition не движется и имеет значение (2.0f, 3.0f, -1.0f).

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

Вот как это выглядит: http://i.imgur.com/Na2C6.png

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

Благодарю за любую помощь!

Редактировать: @Darcy Rayner То, что Indead очень помогло, кажется, что-то, что все еще не правильно...

Текущий код выглядит так:

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

viewSpacePosition = (modelViewMatrix*gl_Vertex).xyz;
viewSpaceSunPosition = (modelViewMatrix*vec4(sunPosition,1)).xyz;
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
viewSpaceNormal = (normalMatrix * vec4(gl_Position.xyz, 0.0)).xyz;

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

vec4 calculateSpecular(vec3 l, vec3 n, vec3 v, vec4 specularLight, vec4 materialSpecular) {
    vec3 r = -l+2*(n*l)*n;
    return specularLight * materialSpecular * pow(max(0,dot(r, v)), shininess);
}

void main(){
    vec3 normal = normalize(viewSpaceNormal);
    vec3 viewSpacePosition = normalize(viewSpacePosition);
    vec3 viewSpaceSunPosition = normalize(viewSpaceSunPosition);
    vec4 specular = calculateSpecular(viewSpaceSunPosition, normal, viewSpacePosition,     vec4(0.7,0.7,0.7,1.0), vec4(0.6,0.6,0.6,1.0));
    gl_FragColor = color+specular;
}

И сфера выглядит так:

-> Фото-ссылка<-

с положением солнца: sunPosition = new Vector(12.0f, 15.0f, -1.0f);

1 ответ

Попробуйте не использовать gl_FragCoord, так как он хранится в экранных координатах (и я не думаю, что преобразование его с помощью modelViewMatrix вернет его для просмотра координат). Легче всего сделать, установить viewSpacePosition в вашем вершинном шейдере как:

// Change gl_Vertex to whatever attribute you are using.
viewSpacePosition = (modelViewMatrix * gl_Vertex).xyz; 

Это должно привести вас к viewSpacePosition в координатах вида (т. Е. До применения проекции). Затем вы можете продолжить и нормализовать viewSpacePosition во фрагментном шейдере. Не уверен, что вы сохраняете солнечный вектор в мировых координатах, но вы, вероятно, захотите преобразовать его в пространство обзора, а затем нормализовать его. Попробуйте и посмотрите, что происходит, эти вещи, как правило, очень подвержены ошибкам.

gl_FragCoord является входной переменной, которая содержит значения относительной координаты окна (x, y, z, 1/w) для фрагмента.... Это значение является результатом фиксированной функциональности, которая интерполирует примитивы после обработки вершин для генерации фрагментов.

Первые два значения (x,y) gl_FragCoord содержит координаты центра пикселя, где фрагмент визуализируется. Например, при разрешении буфера кадра 800×600 фрагмент, отображаемый в левом нижнем углу, будет попадать в положение пикселя (0,5,0,5); фрагмент, выведенный в самый верхний правый угол, будет иметь координаты (799,5, 599,5). Третье значение (z) - это глубина фрагмента, отображенная в нелинейном диапазоне [0,1]. Он отображает глубины фрагментов от [znear, zfar] до [0,1].

Согласно этому, vec3 viewSpacePosition = (modelViewMatrix * vec4(gl_FragCoord.x, gl_FragCoord.y, gl_FragCoord.z, 1.0)).xyz; не делает то, что вы ожидаете. gl_FragCoord позиция вершины, которая преобразуется gl_ModelViewProjectionMatrix, интерполируется по беоцентрическим координатам фрагмента в примитиве треугольника и масштабируется по размеру области просмотра. Дальнейшее преобразование по матрице вида модели (modelView Matrix) не имеет смысла.

Для расчета зеркального света (в нашем случае модель отражения Фонга) требуется 3 вектора:

  1. Нормальный вектор поверхности, который normalize(viewSpaceNormal) в этом случае.
  2. Вектор от позиции фрагментов к камере. Камера имеет положение (0, 0, 0) в поле зрения. Таким образом, вектор представления normalize(vec3(0.0) - viewSpacePosition),
  3. Вектор света, который является вектором от позиции frgment к источнику света. Таким образом, вектор света рассчитывается по normalize(viewSpaceSunPosition - viewSpacePosition),
    Обратите внимание, так как расчет выполняется в пространстве вида (viewSpaceNormal а также viewSpacePosition находятся в поле зрения), вектор света и, следовательно, также положение источника света (viewSpaceSunPosition), должен быть в поле зрения. Это означает, что положение источника света должно быть преобразовано матрицей вида, прежде чем он будет установлен на равномерную переменную. viewSpaceSunPosition,

Обратите внимание, что матрица вида и матрица вида модели не должны быть одинаковыми. Матрица вида модели состоит из матрицы модели и матрицы вида. Обычно матрица модели содержит дополнительные преобразования для одного объекта (например, анимации на объекте в сцене).

Помимо этого, существует ошибка в расчете вектора отражения, формула расчета выглядит следующим образом:

incidentVector - 2.0 * dot(incidentVector, normalVector) * normalVector;

Обратите внимание, в GLSL есть функция reflect, который сделал бы работу.

Вершина и фрагментный шейдер должны выглядеть примерно так:

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

varying vec3 viewSpacePosition;
varying vec3 viewSpaceNormal;

void main()
{
    viewSpacePosition  = (modelViewMatrix*gl_Vertex).xyz;
    viewSpaceNormal    = (normalMatrix * vec4(gl_Position.xyz, 0.0)).xyz;
    gl_Position        = gl_ModelViewProjectionMatrix * gl_Vertex;
}

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

varying vec3 viewSpacePosition;
varying vec3 viewSpaceNormal;

uniform vec3  viewSpaceSunPosition;
uniform float shininess;

vec4 calculateSpecular(vec3 L, vec3 N, vec3 V, vec4 specularLight, vec4 materialSpecular)
{
    vec3 R = -L - 2.0 * dot(N, -L) * N;
    // vec3 R = reflect( -L, N );
    return specularLight * materialSpecular * pow(max(0,dot(R, V)), shininess);
}

void main()
{
    vec3 N = normalize( viewSpaceNormal );
    vec3 V = normalize( -viewSpacePosition );
    vec3 L = normalize( viewSpaceSunPosition - viewSpacePosition );
    vec4 specular = calculateSpecular(L, N, V, vec4(0.7,0.7,0.7,1.0), vec4(0.6,0.6,0.6,1.0));
    gl_FragColor  = color+specular;
}

Смотрите также ответы на эти вопросы:

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