OpenGL:Cube Map

前面绘制天空盒的时候有提到过 Cube Map,但是 Cube Map 又是什么呢?

Cube Map 其实是就是一个包含了6个2D纹理的纹理,每个2D纹理都组成了立方体的一个面:一个有纹理的立方体。与2D纹理坐标 (s, t) 不同的是,我们使用3个维度 (s, t, r) 来对 Cube Map 进行索引定位,并且 Cube Map 有个特性,其纹理坐标等于它的方向坐标。就是我们使用单位立方体,中心为原点,某个点的坐标就等于它的纹理坐标。

Cube Map 不只是能够用来创建天空盒,还能够用来制作环境反射和折射等效果。

6个纹理面
每个面对应OpenGL特定的目标:

枚举常量方向
GL_TEXTURE_CUBE_MAP_POSITIVE_X+X (右)
GL_TEXTURE_CUBE_MAP_NEGATIVE_X-X (左)
GL_TEXTURE_CUBE_MAP_POSITIVE_Y+Y (上)
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y-Y (下)
GL_TEXTURE_CUBE_MAP_POSITIVE_Z+Z (后/远)
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z-Z (前/近)

和2D纹理创建类似,我们需要读取纹理数据,然后将其绑定到纹理对象上面去。不同的是,我们创建的是 GL_TEXTURE_CUBE_MAP 为目标的纹理对象,并且需要给6个不同的目标设置不同的纹理。下面是创建 Cube Map 的伪代码:

GLuint textureID;
glGenTexture(1, &textureID);
glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);

const GLenum targets[6] = {
	GL_TEXTURE_CUBE_MAP_POSITIVE_X, 
    GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
    GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
    GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
    GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
    GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
};

for(int i = 0; i < 6; ++i) {
	// 读取纹理数据
	data = load_image(faces[i]);    // faces 是纹理文件的名字
	// 设置纹理数据
	glTexImage2D(targets[i], 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
}

// 设置纹理参数
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

根据上面的流程我们就创建好了一个 Cube Map 对象,下面我们将使用这个对象来进行天空盒的制作。

和skybox一样,我们需要制作shader进行天空盒的绘制:

// skybox.vert
#version 440
layout (location = 0) in vec3 aPostion;

out vec3 TexCoord;

uniform mat4 projection;
uniform mat4 view;

void main()
{
    TexCoord = aPostion;
    gl_Position = projection * view * vec4(aPostion, 1.0f);
    gl_Position = gl_Position.xyww;
}

在这个 vertex shader 中,我们将原先外部传入的纹理坐标换成了使用立方体的位置坐标作为纹理坐标(这里需要注意的是,我使用的是单位大小的立方体,如果你使用不是单位大小的,你需要进行标准化)。

// skybox.frag
#version 440
out vec4 fragColor;

in vec3 TexCoord;

layout (binding = 0) uniform samplerCube skybox;

void main()
{
    fragColor = texture(skybox, TexCoord);
}

在 fragment shader 中,注意到使用的sampler是专门对cubemap进行采样的 samplerCube,其使用方法和sampler2D 一样,就不赘述了。

和之前同样的绘制流程:渲染其他物体 -> 禁止深度写入 -> 渲染天空盒 -> 重置深度状态。

// 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. 绘制天空盒
glBindVertexArray(VAO);  
cubemap.bind();  
glDrawArrays(GL_TRIANGLES, 0, 36);   

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

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ht巷子

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

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

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

打赏作者

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

抵扣说明:

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

余额充值