8

在 3D 游戏中渲染具有固定纹理的天空时,人们通常会先在一个立方体贴图中创建 6 个纹理,然后在相机周围渲染一个立方体。在 GLSL 中,您可以使用法线而不是纹理坐标来访问纹理中的像素,并且您可以通过标准化片段相对于相机的位置来轻松获得此法线。然而,这个过程可以用围绕相机的任何形状来完成,因为当你标准化每个位置时,它总是会产生一个球体。现在我想知道:为什么它总是一个立方体而不是一个四面体?渲染一个立方体需要 12 个三角形,一个四面体只有 4 个。正如我已经说过的,任何围绕相机的形状都可以。所以四面体占用更少的 VRAM 并且渲染速度更快,没有任何缺点?为什么不使用它们?

4

2 回答 2

10

你根本不需要一些环境几何。您需要做的就是绘制一个全屏四边形,并为其计算正确的纹理坐标。现在有了现代 GL,我们甚至不需要为此提供顶点数据,我们可以使用无属性渲染:

顶点着色器:

#version 330 core
out vec3 dir;
uniform mat4 invPV;
void main()
{
        vec2 pos  = vec2( (gl_VertexID & 2)>>1, 1 - (gl_VertexID & 1)) * 2.0 - 1.0;
        vec4 front= invPV * vec4(pos, -1.0, 1.0);
        vec4 back = invPV * vec4(pos,  1.0, 1.0);

        dir=back.xyz / back.w - front.xyz / front.w;
        gl_Position = vec4(pos,1.0,1.0);
}

在哪里invPVinverse(Projection*View)因此它将考虑您的相机方向以及投影。原则上,这可以进一步简化,具体取决于您可以对投影矩阵施加多少约束。

片段着色器:

#version 330 core
in vec3 dir;
out color;
uniform samplerCube uTexEnv;
void main()
{
        color=texture(uTexEnv, dir);
}

要使用它,您只需绑定一个空的 VAO 和您的纹理,上传您的invPV矩阵并调用glDrawArrays(GL_TRIANGLE_STRIP, 0, 4).

这种方法当然可以用于球形纹理映射而不是立方体贴图

于 2015-05-04T19:27:06.460 回答
6
  1. 这是视图深度和形状的问题

    最好的天空盒形状是(半)球体,因为它的渲染表面几乎没有变形地投影到相机空间。如果您使用任何其他形状,则会出现投影伪影,尤其是在角落,例如大多数应用程序/游戏使用立方体天空盒。以有限的半径(不仅仅是单个点)查看太阳并旋转视图,使太阳从视图的中间到侧面。然后通常太阳会从圆形/圆盘形扭曲为椭圆形/椭圆形:

    立方体畸变示例 在此处输入图像描述

    这是由于天空盒相机之间的距离发生了变化。如果将其与直接渲染的星星进行比较:

    渲染的天空(没有天空盒)

    然后你就可以看到区别了。第一张图片是谷歌找到的第一张相关图片(来自某些游戏),第二张是我认为 Space Engineers 的屏幕截图,最后一张是由我的 astro 应用程序渲染的,请参见

    因此,远离球体的形状越多,您得到的扭曲就越多。

    使用 4 面金字塔比立方体更糟糕,因为边之间的角度更糟,会产生更大的伪影。另一个问题是您需要更大尺寸的金字塔来覆盖相同的空间。如果您在天空盒渲染期间出于某种目的使用深度缓冲区,您可能会通过增加Z_far平面显着影响精度。

  2. 高架

    6 和 4 个多边形之间的差异并没有那么大,因为天空盒很大(覆盖整个视图),速度主要取决于提交给屏幕的像素/纹素的数量而不是顶点数量。所以金字塔可能比立方体更慢,因为它需要更大的面(需要更多的插值器迭代)。但是,如果您想使用球形天空盒,那么您还需要球形纹理,因为如果您使用标准立方体纹理,失真仍然存在,并且这些更难以维持创建......这就是为什么更多使用立方体的原因。

  3. 球形天空盒

    他们需要不同类型的纹理。半球形纹理如下所示:

    半球形纹理

于 2015-05-04T08:28:33.997 回答