视图 space 中的 openGL 立方体贴图反射是错误的

openGL cubemap reflections in view space are wrong

我正在关注 this tutorial,并且我设法将立方体贴图添加到我的场景中。然后我尝试向我的对象添加反射,与教程不同,我在视图 space 中制作了我的 GLSL 代码。但是,反射似乎有点偏离。无论你面对什么角度,它们总是反射同一侧,在我的例子中,你总是在反射的物体上看到一块石头,但石头只在我的立方体贴图的一侧。 这是显示效果的视频:

.

我试过用其他形状的物体,比如立方体,效果是一样的。我还发现 this book,它显示了视图 space 反射的示例,似乎我正在做类似的事情,但它仍然不会产生预期的效果。 我的顶点着色器代码:

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 normal;
layout (location = 2) in vec2 aTexCoord;

uniform mat4 Model;
uniform mat4 View;
uniform mat4 Projection;

out vec2 TexCoord;
out vec3 aNormal;
out vec3 FragPos;

void main()
{
    aNormal = mat3(transpose(inverse(View * Model))) * normal; 
    FragPos = vec3(View * Model * vec4(aPos,1.0));
    gl_Position = Projection * vec4(FragPos,1.0);
    TexCoord = aTexCoord;
}

我的顶点代码:

#version 330 core

out vec4 FragColor;

in vec3 FragPos;
in vec3 aNormal;

uniform samplerCube skybox;


void main(){
    vec3 I = normalize(FragPos);
    vec3 R = reflect(I,normalize(aNormal));
    FragColor = vec4(texture(skybox,R).rgb,1.0);
}

由于您进行了计算,因此在片段着色器中,在视图 space 中,反射矢量 (R) 也是视图 space 中的矢量。立方体贴图 (skybox) 表示世界 space 中的环境贴图。 您必须将 R 从视图 space 转换为世界 space。这可以通过逆视图矩阵来完成逆矩阵可以通过glsl内置函数计算inverse:

#version 330 core

out vec4 FragColor;

in vec3 FragPos;
in vec3 aNormal;

uniform samplerCube skybox;
uniform mat4 View;

void main() {
    vec3 I      = normalize(FragPos);
    vec3 viewR  = reflect(I, normalize(aNormal));
    vec3 worldR = inverse(mat3(View)) * viewR;
    FragColor   = vec4(texture(skybox, worldR).rgb, 1.0);
}

注意,视图矩阵将世界space转换为视图space,逆视图矩阵将视图space转换为世界space。另见 Invertible matrix

这是一个迟到的答案,但我只是想提供额外的信息为什么它会这样。

想象你的反光物体只是一个 6 面的立方体。每张脸都可以看作是一面镜子。现在因为你在视图中 space 从你的视点可见的那个镜像平面的每个坐标都具有负 z 值。让我们直接看中心点。这个向量看起来像 (0, 0, -z) 并且因为立方体的侧面就像一面镜子,它会直接反射回你 (0, 0 , +z)。因此,您最终从立方体贴图的 GL_TEXTURE_CUBE_MAP_POSITIVE_Z 中采样。 在着色器代码中它看起来像:

vec3 V     = normalize(-frag_pos_view_space); // vector from fragment to view point (0,0,0) in view space
vec3 R     = reflect(-V, N);                  // invert V because reflect expects incident vector
vec3 color = texture(skybox, R).xyz;

现在,让我们移到立方体的另一边,看看那个镜面。在视图 space 中,你所看到的坐标仍然是 (0,0,-z) 的中心,会反射到法线周围并返回给你,所以反射矢量再次看起来像 (0,0, +z)。这意味着即使您在立方体的另一侧,您也会在立方体贴图中采样相同的面。

所以您要做的就是使用视图矩阵的逆矩阵返回到世界 space。如果另外然后你通过应用旋转来渲染天空盒本身,你甚至必须用你用来变换天空盒的模型矩阵的逆来变换你的反射向量,否则反射仍然是错误的。