立方体贴图
立方体贴图的应用之一就是做天空盒子。
先是顶点着色器
#version 330 core
layout (location=0) in vec3 aPos;
out vec3 TexCoords;
uniform mat4 projMat;
uniform mat4 viewMat;
void main()
{
TexCoords=aPos;
vec4 pos=projMat*viewMat*vec4(aPos*20.0f,1.0f);
gl_Position=pos.xyww;//让天空盒子的深度一直为1.0
}
片段着色器
#version 330 core
out vec4 FragColor;
in vec3 TexCoords;
uniform samplerCube skybox;
void main()
{
FragColor=texture(skybox,TexCoords);
}
然后是主函数里面
//加载立方体贴图的函数
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);//立方体贴图的方位是枚举的,所以可以直接相加可得
}
else
{
std::cout << "Cubemap texture failed to load at path: " << faces[i] << std::endl;
}
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);
stbi_image_free(data);
}
return textureID;
}
前序工作
float skyboxVertices[] = {
// positions
-1.0f, 1.0f, -1.0f,
-1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, -1.0f,
-1.0f, -1.0f, 1.0f,
-1.0f, -1.0f, -1.0f,
-1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, 1.0f,
1.0f, -1.0f, -1.0f,
1.0f, -1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, -1.0f, 1.0f,
-1.0f, -1.0f, 1.0f,
-1.0f, 1.0f, -1.0f,
1.0f, 1.0f, -1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, -1.0f,
-1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, 1.0f,
1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, 1.0f,
1.0f, -1.0f, 1.0f
};//绘制立方体的顶点
vector<std::string>faces//天空盒子的几个面
{
"skybox/right.jpg",
"skybox/left.jpg",
"skybox/top.jpg",
"skybox/bottom.jpg",
"skybox/front.jpg",
"skybox/back.jpg"
};
unsigned int cubemapTexture = loadCubemap(faces);
Shader skyboxShader = Shader("Cubemaps_vertShader.vert", "Cubemaps_fragment.frag");
GLuint skyboxVAO,skyboxVBO;//这个就是老生常谈了,不讲了
glGenVertexArrays(1, &skyboxVAO);
glGenBuffers(1, &skyboxVBO);
glBindVertexArray(skyboxVAO);
glBindBuffer(GL_ARRAY_BUFFER, skyboxVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(skyboxVertices), skyboxVertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
开始绘制
//最后绘制天空盒子
glDepthFunc(GL_LEQUAL);
skyboxShader.Use();
viewMat = myCamera->GetViewMatrix();//获取视角矩阵
skyboxShader.setMat4("viewMat", viewMat);
skyboxShader.setMat4("projMat", projMat);//获取投影矩阵
glBindVertexArray(skyboxVAO);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture);//设定立方体矩阵
//skyboxShader.setInt("skybox", 0);
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);
glDepthFunc(GL_LESS);
效果:
反射
更新箱子的顶点着色器
#version 330 core
layout (location=0) in vec3 aPos;//输入的位置向量
layout(location=1) in vec3 aNormal;//输入的法向量
out vec3 Normal;//输出的位置向量
out vec3 Position;//输出的法向量
uniform mat4 projMat;
uniform mat4 viewMat;
uniform mat4 modelMat;
void main()
{
Normal=mat3(transpose(inverse(modelMat)))*aNormal;计算法向量
Position=vec3(modelMat*vec4(aPos,1.0f));//计算位置向量
gl_Position=projMat*viewMat*modelMat*vec4(aPos,1.0f);
}
更新cube的片段着色器
#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);//计算i向量
vec3 R=reflect(I,normalize(Normal));//reflect传入一个法向量和观察向量计算r向量
FragColor=vec4(texture(skybox,R).rgb,1.0);
}
折射
一些常用的材质折射表
假设箱子为玻璃材质:
修改片段着色器
#version 330 core
out vec4 FragColor;
in vec3 Normal;
in vec3 Position;
uniform vec3 cameraPos;
uniform samplerCube skybox;
void main()
{
float ratio=1.00/1.52;
vec3 I=normalize(Position-cameraPos);
vec3 R=refract(I,normalize(Normal),ratio);//计算的方式变成refract
FragColor=vec4(texture(skybox,R).rgb,1.0);
}
输出效果: