расчеты света в пространстве модели

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

Шейдеры: ViewMatrix - трансформация камеры, ModelMatrix - трансформация объектов. Положение света - glm :: vec4 lightPos (3.0f, 2.0f, -30.0f, 1.0f)

Цикл рендеринга:

glUseProgram(ProgramId);
glUniformMatrix4fv(ViewMatrixUniformLocation, 1, GL_FALSE, glm::value_ptr(ViewMatrix));
glUniform4f(lightIntensityUniformLocation, 0.8f, 0.8f, 0.8f, 1.0f);
glUniform4f(ambientIntensityUniformLocation, 0.2f, 0.2f, 0.2f, 0.2f);
glUniform3fv(dirToLightUniformLocation, 1, glm::value_ptr( lightPos));

ModelMatrixStack.push(ModelMatrix);
ModelMatrix = glm::translate(ModelMatrix, glm::vec3(0, 0, -30));
ModelMatrix = glm::rotate(ModelMatrix, 75.0f, glm::vec3(0,0,1)); 
normMatrix = glm::mat3(ModelMatrix);
glUniformMatrix4fv(ModelMatrixUniformLocation, 1, GL_FALSE,           
glm::value_ptr(ModelMatrix));   
glUniformMatrix3fv(normalModelMatrixUniformLocation, 1, GL_FALSE, 
glm::value_ptr(normMatrix));
drawTeapot();

ModelMatrix = ModelMatrixStack.top();
normMatrix = glm::mat3(ModelMatrix);

glUniformMatrix4fv(ModelMatrixUniformLocation, 1, GL_FALSE,  
glm::value_ptr(ModelMatrix));
glUniformMatrix3fv(normalModelMatrixUniformLocation, 1, GL_FALSE,  
glm::value_ptr(normMatrix));
myground.draw();

glUseProgram(0);

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

#version 400

layout(location=0) in vec4 in_position;
layout(location=1) in vec3 in_normal;
out vec3 normal;
out vec4 position;

uniform mat4 ModelMatrix;
uniform mat4 ViewMatrix;
uniform mat4 ProjectionMatrix;

void main(void)
{
     vec4 vertexPosition = ModelMatrix * in_position;
     gl_Position = ProjectionMatrix * ViewMatrix * vertexPosition;
     normal = in_normal;
     position = vertexPosition;
}

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

version 400

in vec3 normal;
in vec4 position;
out vec4 outputColor;

uniform vec3 lightPos;
uniform vec4 lightIntensity;
uniform vec4 ambientIntensity;
uniform mat3 normalModelMatrix;

void main(void)
{
     vec3 normCamSpace = normalize(normalModelMatrix * normalize(normal));
     vec3 dirToLight = normalize(lightPos - vec3(position));
     float cosAngIncidence = dot(normCamSpace, dirToLight);
     cosAngIncidence = clamp(cosAngIncidence, 0, 1);
     outputColor = (lightIntensity * cosAngIncidence) + ambientIntensity;
}

person Irbis    schedule 03.05.2012    source источник


Ответы (1)


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

modelspace, где мне не нужно умножать нормали на normalModelMatrix, как показано ниже во фрагментном шейдере.

Этот расчет также работает в вершинном шейдере. Просто переместите это туда.


Обновить / РЕДАКТИРОВАТЬ

для пояснения здесь модифицированный код шейдера:

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

#version 400

layout(location=0) in vec4 in_position;
layout(location=1) in vec3 in_normal;

out vec3 eyespaceNormal;
out vec4 eyespacePosition;

uniform mat4 ModelviewMatrix;
uniform mat3 NormalMatrix; // == inverse(transpose(ModelviewMatrix))
uniform mat4 ProjectionMatrixq;

void main(void)
{
     eyespacePosition = ModelviewMatrix * in_position;
     eyespaceNormal = normalize(NormalMatrix * in_normal);
     gl_Position = ProjectionMatrix * eyespacePosition;
}

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

#version 400

in vec3 eyespaceNormal;
in vec4 eyespacePosition;
out vec4 outputColor;

uniform vec3 lightPos;
uniform vec4 lightIntensity;
uniform vec4 ambientIntensity;

void main(void)
{
     vec3 dirToLight = normalize(lightPos - vec3(eyespacePosition));
     float cosAngIncidence = dot(eyespaceNormal, dirToLight);
     cosAngIncidence = clamp(cosAngIncidence, 0, 1);
     outputColor = (lightIntensity * cosAngIncidence) + ambientIntensity;
}

BTW: ваша нормальная матрица преобразования была неправильной. Для этого необходимо использовать инверсию транспонированной матрицы просмотра модели.

person datenwolf    schedule 03.05.2012
comment
Если я правильно понял вас, то в моем случае выполнение освещения в пространстве модели может выглядеть так: в вершинном шейдере я могу отправить фрагментный шейдер in_postion без умножения на ModelMatrix (position = in_position) Затем в цикле рендеринга после последнего преобразования ModelMatrix мне нужно вычислить инверсию ModelMatrix и умножить ее на lightPos: glm :: mat4 invTransform = glm :: inverse (ModelMatrix); glUniform3fv (dirToLightUniformLocation, 1, glm :: value_ptr (invTransform * lightPos)); Наконец, мне не нужно умножать нормали на normalModelMatrix в моем шейдере. - person Irbis; 03.05.2012
comment
@ Ирбис: Нет, я не это имел в виду. Я сказал вам поместить все преобразования в вершинный шейдер. Передайте фрагментному шейдеру только легко преобразованные векторы. - person datenwolf; 03.05.2012
comment
Но до тех пор, пока я не использую неоднородный масштаб, моя нормальная матрица преобразования кажется достаточной. Я использую ViewMatrix для управления моей камерой fps, поэтому должно быть eyespacePostion = ModelMatrix * in_position, потому что я хочу, чтобы свет оставался в фиксированном положении. Более того, я считаю, что eyespaceNormal нужно нормализовать во фрагментном шейдере. Что вы думаете об упомянутой выше концепции, в которой мне не нужно использовать нормальную матрицу преобразования? - person Irbis; 03.05.2012
comment
Нормализация преобразованной нормали во фрагментном шейдере имеет смысл, если отклонение нормали по лицу велико. Технически правильным методом была не барицентрическая интерполяция с нормализацией, а сферическая интерполяция в любом случае. Вы должны преобразовать источники света в глазное пространство на ЦП, чтобы сэкономить вычислительные ресурсы графического процессора (у вас будет едва ли более 20 источников света, освещающих лицо). Вычисление этого на CPU намного эффективнее, чем вычисление его для каждой вершины снова и снова. - person datenwolf; 03.05.2012
comment
Помните: процессоры не медленнее графических процессоров, просто они не такие параллельные. Если задача не выигрывает от распараллеливания (например, преобразования только нескольких световых позиций) в нее на ЦП. - person datenwolf; 03.05.2012