OpenGL:skybox的绘制

天空盒(Skybox)是一种高效渲染环境的核心技术,它通过在立方体表面贴合精心处理的环境纹理,创造出无限延展的世界幻觉。当你在其中转动视角时,这些环境纹理会随着视角变化而呈现正确的透视关系,让人错觉自己置身于一个无边无际的世界中。

相比传统的3D环境模型,天空盒进需要36个顶点即可创建完整的环境体验。对于天空盒的绘制,我们需要用到6张不同的图片作为立方体不同面的纹理,这6张图片构成我们完整的环境。

在OpenGL中,对于天空盒的绘制有两种方法,一种是直接绘制一个立方体,然后对立方体每个面贴不同的图片,另一种是通过 cubemap 实现天空盒的绘制。在这里,我们使用第一种方式进行天空盒的实现。

  1. 首先,我们需要了解所使用的纹理的分布:
    在这里插入图片描述

上面的图就是我们所用到的天空盒的纹理,我们需要将这张图绘制到立方体上面去,并且还是有顺序的进行绘制,下面是对应的UV坐标。

在这里插入图片描述

float skyboxVertices[180] = {
        // +Z (Front Face)
        -1.0f, -1.0f,  1.0f,   0.25f, 1.0f/3.0f, // 左下
         1.0f, -1.0f,  1.0f,   0.50f, 1.0f/3.0f, // 右下
         1.0f,  1.0f,  1.0f,   0.50f, 2.0f/3.0f, // 右上
         1.0f,  1.0f,  1.0f,   0.50f, 2.0f/3.0f, // 右上
        -1.0f,  1.0f,  1.0f,   0.25f, 2.0f/3.0f, // 左上
        -1.0f, -1.0f,  1.0f,   0.25f, 1.0f/3.0f, // 左下

        // -X (Left Face)
        -1.0f,  1.0f,  1.0f,   0.25f, 2.0f/3.0f, // 右上
        -1.0f,  1.0f, -1.0f,   0.00f, 2.0f/3.0f, // 左上
        -1.0f, -1.0f, -1.0f,   0.00f, 1.0f/3.0f, // 左下
        -1.0f, -1.0f, -1.0f,   0.00f, 1.0f/3.0f, // 左下
        -1.0f, -1.0f,  1.0f,   0.25f, 1.0f/3.0f, // 右下
        -1.0f,  1.0f,  1.0f,   0.25f, 2.0f/3.0f, // 右上

        // +X (Right Face)
         1.0f,  1.0f, -1.0f,   0.75f, 2.0f/3.0f, // 右上
         1.0f,  1.0f,  1.0f,   0.50f, 2.0f/3.0f, // 左上
         1.0f, -1.0f,  1.0f,   0.50f, 1.0f/3.0f, // 左下
         1.0f, -1.0f,  1.0f,   0.50f, 1.0f/3.0f, // 左下
         1.0f, -1.0f, -1.0f,   0.75f, 1.0f/3.0f, // 右下
         1.0f,  1.0f, -1.0f,   0.75f, 2.0f/3.0f, // 右上

        // -Z (Back Face)
         1.0f, -1.0f, -1.0f,   0.75f, 1.0f/3.0f, // 左下
        -1.0f, -1.0f, -1.0f,   1.00f, 1.0f/3.0f, // 右下
        -1.0f,  1.0f, -1.0f,   1.00f, 2.0f/3.0f, // 右上
        -1.0f,  1.0f, -1.0f,   1.00f, 2.0f/3.0f, // 右上
         1.0f,  1.0f, -1.0f,   0.75f, 2.0f/3.0f, // 左上
         1.0f, -1.0f, -1.0f,   0.75f, 1.0f/3.0f, // 左下

        // +Y (Top Face)
        -1.0f,  1.0f,  1.0f,   0.25f, 2.0f/3.0f, // 左下
         1.0f,  1.0f,  1.0f,   0.50f, 2.0f/3.0f, // 右下
         1.0f,  1.0f, -1.0f,   0.50f, 1.00f,     // 右上
         1.0f,  1.0f, -1.0f,   0.50f, 1.00f,     // 右上
        -1.0f,  1.0f, -1.0f,   0.25f, 1.00f,     // 左上
        -1.0f,  1.0f,  1.0f,   0.25f, 2.0f/3.0f, // 左下

        // -Y (Bottom Face)
        -1.0f, -1.0f, -1.0f,   0.25f, 0.00f,     // 左上
         1.0f, -1.0f, -1.0f,   0.50f, 0.00f,     // 右上
         1.0f, -1.0f,  1.0f,   0.50f, 1.0f/3.0f, // 右下
         1.0f, -1.0f,  1.0f,   0.50f, 1.0f/3.0f, // 右下
        -1.0f, -1.0f,  1.0f,   0.25f, 1.0f/3.0f, // 左下
        -1.0f, -1.0f, -1.0f,   0.25f, 0.00f      // 左上
    };

我们使用这些数据进行立方体的绘制,这里不做赘述。

  1. 在准备完数据之后,我们需要进行shader的准备。其实也是正常绘制,一个很简单的shader
// simple_skybox.vert
#version 440
layout (location = 0) in vec3 aPosition;
layout (location = 1) in vec2 aTexCoord;

out vec2 tc;

uniform mat4 projection;
uniform mat4 view;

void main()
{
    tc = aTexCoord;
    vec4 pos = projection * view * vec4(aPosition, 1.0);
    gl_Position = pos.xyww; // 深度值设为最大值(w/w = 1.0)
}
// simple_skybox.frag
#version 440
out vec4 fragColor;

in vec2 tc;

layout (binding = 0) uniform sampler2D samp;

void main()
{
     fragColor = texture(samp, tc);
}
  1. 前序工作都准备好之后,就是进行渲染了,渲染顺序都是:渲染其他物体 -> 禁止深度写入 -> 渲染天空盒 -> 重置深度状态。
// 1. 首先生效的物体
renderScene(window, mainShader, currentTime, true); 

// 2. 天空盒配置(在最后渲染)
glDepthMask(GL_FALSE);          // 禁用深度写入
glDepthFunc(GL_LEQUAL);         // 启用小于等于深度测试

skybox.use();
skybox.setMat4("projection", pMat);

// 消位移,只保留旋转(防止近裁剪面穿帮)
glm::mat4 view = glm::mat4(glm::mat3(vMat)); 
skybox.setMat4("view", view);

// 3. 绘制天空盒
mySkybox.draw(ResourceManager::getTexture("skybox"));

// 4. 重置深度状态
glDepthMask(GL_TRUE);
glDepthFunc(GL_LESS);

在这里插入图片描述

但是这种方法渲染容易出现一个问题,那就是接缝之间可能会出现伪影,这是因为我们在计算UV坐标的时候,存在了误差,所以会导致这种问题。比较好的解决方法就是使用cubemap进行天空盒的绘制。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ht巷子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值