Как исправить неправильное освещение Blinn-Phong - PullRequest
1 голос
/ 31 марта 2019

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

Результат показан ниже: Incorrect lighting

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

Положение освещения в координатах (10, 10, 10).

Точка высокой интенсивности в середине круга равна (0,0,0).

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

#version 450
#extension GL_ARB_separate_shader_objects : enable

layout(binding = 0) uniform MVP {
    mat4 model;
    mat4 view;
    mat4 proj;
} mvp;

layout(location = 0) in vec3 inPosition;
layout(location = 1) in vec3 inColor;
layout(location = 2) in vec2 inTexCoord;
layout(location = 3) in vec3 inNormal;

layout(location = 0) out vec3 fragColor;
layout(location = 1) out vec2 fragTexCoord;
layout(location = 2) out vec3 Normal;
layout(location = 3) out vec3 FragPos;
layout(location = 4) out vec3 viewPos;

void main() {
    gl_Position = mvp.proj * mvp.view * mvp.model * vec4(inPosition, 1.0);
    fragColor = inColor;
    fragTexCoord = inTexCoord;
    Normal = inNormal;
    FragPos = inPosition;
    viewPos = vec3(mvp.view[3][0], mvp.view[3][1], mvp.view[3][2]);
}

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

#version 450
#extension GL_ARB_separate_shader_objects : enable

layout(binding = 1) uniform sampler2D texSampler;
layout(binding = 2) uniform LightUBO{
    vec3 position;
    vec3 color;
} Light;

layout(location = 0) in vec3 fragColor;
layout(location = 1) in vec2 fragTexCoord;
layout(location = 2) in vec3 Normal;
layout(location = 3) in vec3 FragPos;
layout(location = 4) in vec3 viewPos;

layout(location = 0) out vec4 outColor;

void main() {
    vec3 color = texture(texSampler, fragTexCoord).rgb;
    // ambient
    vec3 ambient = 0.2 * color;

    // diffuse
    vec3 lightDir = normalize(Light.lightPos - FragPos);
    vec3 normal = normalize(Normal);
    float diff = max(dot(lightDir, normal), 0.0);
    vec3 diffuse = diff * color;

    // specular
    vec3 viewDir = normalize(viewPos - FragPos);
    vec3 reflectDir = reflect(-lightDir, normal);
    float spec = 0.0;
    vec3 halfwayDir = normalize(lightDir + viewDir);  
    spec = pow(max(dot(normal, halfwayDir), 0.0), 32.0);

    vec3 specular = vec3(0.25) * spec;
    outColor = vec4(ambient + diffuse + specular, 1.0);
}

Примечание: Я пытаюсь реализовать шейдеры из этого учебника в Vulkan.

1 Ответ

3 голосов
/ 31 марта 2019

Казалось бы, это просто вопрос использования правильной системы координат.Поскольку в вашем вопросе отсутствует важная информация, мне придется сделать несколько предположений.Прежде всего, исходя из того факта, что у вас есть матрица модели и, очевидно, есть несколько объектов в вашей сцене, я предполагаю, что ваше мировое пространство и пространство объектов в целом не одно и то же.Кроме того, я предполагаю, что ваша матрица model преобразуется из пространства объектов в мировое пространство, ваша матрица view преобразуется из мирового пространства в пространство просмотра, а ваша матрица proj преобразуется из пространства просмотра в пространство отсечения.Я также предполагаю, что ваши атрибуты inPosition и inNormal находятся в координатах пространства объектов.

Исходя из всего этого, ваш viewPos просто берет последний столбец матрицы вида, который будет , а не содержат положение камеры в мировом пространстве.Также не будет последний ряд.Матрица представления трансформируется из мирового пространства в пространство просмотра.Его последний столбец соответствует вектору, указывающему на происхождение мирового пространства, если смотреть с перспективы камеры.Ваши FragPos и Normal будут в объектном пространстве.И, исходя из того, что вы сказали в своем вопросе, ваши легкие позиции находятся в мировом пространстве.Итак, в конце концов, вы просто сводите воедино координаты, относящиеся к совершенно разным системам координат.Например:

vec3 lightDir = normalize(Light.lightPos - FragPos);

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

float diff = max(dot(lightDir, normal), 0.0);

Кроме того, даже если viewPos была позицией камеры мирового пространства, это

vec3 viewDir = normalize(viewPos - FragPos);

все равнобыть бессмысленным, поскольку FragPos задано в координатах пространства объектов.

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

Чтобы получить viewPos, вы можете взять последний столбец матрицы обратного просмотра (если вы уже имелиэто где-то по какой-то причине), или просто передайте положение камеры в качестве дополнительной униформы.Кроме того, вместо того, чтобы снова и снова умножать матрицу вида модели и проекции, один раз для каждой отдельной вершины, рассмотрите просто передачу комбинированной матрицы проекции модель-вид в шейдер ...

Кроме этого: обратите внимание, что вы будетеСкорее всего, желательно иметь зеркальный компонент, только если поверхность действительно ориентирована на свет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...