立方体贴图通过方向向量来进行索引/采样。
创建立方体贴图
unsigned int textureID;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);
//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 前
//枚举值 可以通过每次迭代加一来遍历纹理目标
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(
GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data
);
}
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);
优化天空盒
将观察矩阵转换为3x3矩阵再将其转换回4x4矩阵可以移除位移,保留旋转,使视角永远处于天空盒的中心。
glm::mat4 view = glm::mat4(glm::mat3(camera.GetViewMatrix()));
在顶点着色器中将z设为w值,使得天空盒的深度值永远是1。然后将深度函数设为GL_LEQUAL
,使得深度值小于等于1就可以测试通过。这样就可以在最后绘制天空盒且只在没有物体的地方渲染天空盒来提升性能。
void main()
{
TexCoords = aPos;
vec4 pos = projection * view * vec4(aPos, 1.0);
gl_Position = pos.xyww;
}
反射
GLSL内建的reflect函数可以计算这个反射向量,根据镜头到观察位置的向量作为入射角和法线向量使用reflect获得反射向量,然后用反射向量采集立方体贴图,达到环境贴图的效果。
#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);
vec3 R = reflect(I, normalize(Normal));
FragColor = vec4(texture(skybox, R).rgb, 1.0);
}
折射
GLSL的内建refract函数来实现,它需要一个法向量、一个观察方向和两个材质之间的折射率。
void main()
{
float ratio = 1.00 / 1.52;
vec3 I = normalize(Position - cameraPos);
vec3 R = refract(I, normalize(Normal), ratio);
FragColor = vec4(texture(skybox, R).rgb, 1.0);
}
动态环境贴图
使用帧缓冲能够为物体的6个不同角度创建出场景纹理,并在每个渲染迭代中将它们储存到一个立方体贴图中。之后就可以使用动态生成的立方体贴图来创建更真实的,包含其它物体的,反射和折射表面。但是需要为使用环境贴图的物体渲染场景6次,对程序是非常大的性能开销。