Learn OpenGL 笔记5.6 Cubemaps(立方体贴图)
立方体贴图。就是多个texture纹理,对应到一个立方体之上。
要把多个贴图合并成一个,再赋值给cube,因为立方体贴图有一个有用的特性,它们可以使用方向向量进行索引/采样
只要提供了方向,OpenGL 就会检索该方向(最终)命中的相应纹素并返回正确采样的纹理值。
基础知识:
1.Creating a cubemap (创建一个立方体Map)
int width, height, nrChannels;
unsigned char *data;
for(unsigned int i = 0; i < textures_faces.size(); i++)
{
data = stbi_load(textures_faces[i].c_str(), &width, &height, &nrChannels, 0);
glTexImage2D(
//这个参数代表要渲染的面的方向,这些方向的enum参数是逐个增加的
GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data
);
}
wrapping and filtering 包裹和采样
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
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);
GL_TEXTURE_WRAP_R 中的 R代表三维,一维:S 二维:T 三维:R
使用方法:
//一个方向向量,代表投射在方块表面的那个texture的点
in vec3 textureDir; // direction vector representing a 3D texture coordinate
uniform samplerCube cubemap; // cubemap texture sampler
void main()
{
FragColor = texture(cubemap, textureDir);
}
2.Skybox(天空盒)
天空盒是一个(大)立方体,它包含整个场景并包含周围环境的 6 个图像,让玩家产生一种错觉,即他所处的环境实际上比实际大得多。
如果你将这 6 个边折叠成一个立方体,你会得到一个完全有纹理的立方体,它模拟了一个大景观。
去除天空盒的平移,只留下旋转:(原理是transform平移变换的参数是在变换矩阵的第四列里面,把变化矩阵缩减成3x3,然后再扩充,多余部分补0,就去掉了平移变换了)
glm::mat4 view = glm::mat4(glm::mat3(camera.GetViewMatrix()));
具体可以看之前的笔记2.7。
3.Skybox optimization(天空盒的一些配置)
3.1 需要进行早期深度测试,防止天空盒无效渲染给fragment造成压力
3.2 天空盒只是一个 1x1x1 的立方体,很可能会在所有其他对象之上渲染,通过大多数深度测试。需要手动把天空盒的深度设置为最大深度1.0。
设置方法:
void main()
{
TexCoords = aPos;
vec4 pos = projection * view * vec4(aPos, 1.0);
//核心是这一句,把z设置成w,这样透视划分的时候,深度值depth=z/w变成了1.0
gl_Position = pos.xyww;
}
3.3 我们必须通过将深度函数设置为 GL_LEQUAL 而不是默认的 GL_LESS 来更改深度函数。
(防止有物品深度和天空盒相等?此时也让物品覆盖天空盒?)
4.Environment mapping(环境贴图)
使用带有环境的立方体贴图,我们可以赋予物体反射或折射特性。 使用像这样的环境立方体贴图的技术称为Environment mapping环境贴图技术,两种最流行的技术是reflection and refraction反射和折射。
4.1 Reflection (反射)
反射是物体(或物体的一部分)反射其周围环境的属性。
计算出一个reflection vector反射向量,然后用这个向量对cubemap进行采样。
R:反射向cubemap的向量
N:法线向量
I:观察者向量
FS解析:
#version 330 core
out vec4 FragColor;
in vec3 Normal;
in vec3 Position;
uniform vec3 cameraPos;
uniform samplerCube skybox;
void main()
{
//计算视角向量
vec3 I = normalize(Position - cameraPos);
//用内置函数reflect计算出反射向量
vec3 R = reflect(I, normalize(Normal));
//利用反射向量对cubemap进行采样
FragColor = vec4(texture(skybox, R).rgb, 1.0);
}
实际上大多数模型并不是完全反射的。 例如,我们可以引入reflection maps 反射贴图,为模型提供另一个额外的细节层次。
5.Refraction(折射)
折射是由于光流过的材料发生变化而引起的光方向的变化。 折射是我们通常在类似水的表面上看到的,其中光线不会直接进入,而是稍微弯曲。
refractive indices 折射率:
FS解析:
void main()
{
float ratio = 1.00 / 1.52;
vec3 I = normalize(Position - cameraPos);
//使用内置的折射函数,根据入射向量,以及折射率,算出折射的向量
vec3 R = refract(I, normalize(Normal), ratio);
//根据折射向量算出天空盒的对应fragment
FragColor = vec4(texture(skybox, R).rgb, 1.0);
}