立方体贴图
立方体贴图是一个包含了6个2D纹理的纹理,这样可以用一个方向向量来进行索引和采样
//使用立方体贴图的着色器
in vec3 textureDir; // 代表3D纹理坐标的方向向量
uniform samplerCube cubemap; // 立方体贴图的纹理采样器
void main()
{
FragColor = texture(cubemap, textureDir);
}
天空盒!!
天空盒事实上就是一个立方体贴图
//加载天空盒贴图和立方体一样
unsigned int loadCubemap(vector<std::string> faces)
{
unsigned int textureID;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);
int width, height, nrChannels;
for (unsigned int i = 0; i < faces.size(); i++)
{
unsigned char *data = stbi_load(faces[i].c_str(), &width, &height, &nrChannels, 0);
if (data)
{
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data
);
stbi_image_free(data);
}
else
{
std::cout << "Cubemap texture failed to load at path: " << faces[i] << std::endl;
stbi_image_free(data);
}
}
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_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);
return textureID;
}
对于立方体贴图来说,直接使用位置向量来进行采样即可。
把输入的位置向量作为输出给片段着色器的纹理坐标,然后在片段着色器中作为输入采样samplerCube.之后把立方体纹理绑定后就可以出现天空的效果。
注意:如果希望移动视角时,背景不移动,应该去除位移部分,之后再转换回为4x4矩阵可以达到目的
glm::mat4 view = glm::mat4(glm::mat3(camera.GetViewMatrix()));
优化
如果先渲染天空盒,会导致后来物体进行重复渲染,可以使用提前深度测试。
即最后让天空盒渲染,但对应的这个天空盒的深度z必须是1,在透视除法中,xyz
坐标除以w分量,而深度测试中,z就是深度值.所以当z分量等于w分量时可以让z分量一直为1.0.
环境映射
使用环境立方体贴图的技术,有两个:反射和折射.
- 反射:
#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);
}
进行反射计算取样,让物体可以实现反射的功能。
2.折射:
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个不同角度创建纹理,在每次渲染迭代中存到立方体贴图中,动态产生立方体贴图。
高级数据
缓冲是一个管理特定内存块的对象,将缓冲绑定到目标时才会有对应的处理缓冲的方式。
一般使用glBufferData
进行管理,可以设置为Null之后再进行填充,或者使用glBufferSubData来填充缓冲的特定区域
分批顶点属性
float positions[] = { ... };
float normals[] = { ... };
float tex[] = { ... };
// 填充缓冲
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(positions), &positions);
glBufferSubData(GL_ARRAY_BUFFER, sizeof(positions), sizeof(normals), &normals);
glBufferSubData(GL_ARRAY_BUFFER, sizeof(positions) + sizeof(normals), sizeof(tex), &tex);
复制缓冲:
glCopyBufferSubData
把一个缓冲复制到另一个缓冲中。