如何修复错误的Blinn-Phong照明

问题描述 投票:1回答:1

我试图在Vulkan着色器中为单个光源实现Blinn-Phong着色,但是我得到的结果不是我所期望的。

输出如下所示: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);
}

注意:我正在尝试将this教程中的着色器实现为Vulkan。

c++ glsl shader vulkan light
1个回答
3
投票

这似乎只是使用正确坐标系的问题。由于您的问题中缺少一些重要信息,我将不得不做出一些假设。首先,基于你有一个模型矩阵并且你的场景中有多个物体的事实,我会假设你的世界空间和物体空间一般不一样。此外,我将假设你的model矩阵从物体空间转换到世界空间,你的view矩阵从世界空间转换到视图空间,你的proj矩阵从视图空间转换到剪辑空间。我还假设您的inPositioninNormal属性在对象空间坐标中。

基于所有这些,你的viewPos只是占据了视图矩阵的最后一列,它不包含世界空间中的摄像机位置。最后一行也不会。视图矩阵从世界空间转换到视图空间。它的最后一列对应于从相机的角度看到的指向世界空间原点的矢量。你的FragPosNormal将在物体空间。而且,根据你在问题中所说的,你的光位置在世界空间。所以最后,你只需要将相对于完全不同坐标系的坐标混合在一起。例如:

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

在这里,您将从世界空间位置减去对象空间位置,这将产生完全无意义的结果。然后将这种无意义的结果归一化并用物空间方向点缀

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

此外,即使viewPos是世界太空相机的位置,这个

vec3 viewDir = normalize(viewPos - FragPos);

因为FragPos是在物空间坐标中给出的,所以仍然没有意义。

如果所涉及的所有矢量都是相对于相同的坐标系,则对坐标矢量的操作才有意义。你选择哪种坐标系并不重要。但你必须选择一个。确保所有向量实际上都与该坐标系相关,例如世界空间。如果某些矢量尚未出现在该坐标系中,则必须将它们转换为该坐标系。只有当你的所有矢量都在同一坐标系中时,你的阴影计算才会有意义......

要获得viewPos,您可以选择逆视图矩阵的最后一列(如果您因某种原因碰巧已经在某处),或者只是将相机位置作为附加制服传递。而且,不是一次又一次地对模型视图和投影矩阵进行乘法,而是对每个单个顶点进行一次,只考虑将组合的模型 - 视图 - 投影矩阵传递给着色器......

除此之外:请注意,如果曲面实际上朝向光线,您很可能只想要一个镜面反射分量。

© www.soinside.com 2019 - 2024. All rights reserved.