首先要做的就是通过根据贴图的alpha值渲染一些草在地面上。
老样子还是先是顶点着色器
#version 330 core
out vec2 TextureCoord;
out vec4 vertexColor;
layout (location=0) in vec3 aPos;
layout (location=1) in vec3 aColor;
layout (location=2) in vec2 aTextureCoord;//纹理坐标
uniform mat4 modelMat;//模型矩阵
uniform mat4 viewMat;//视角矩阵
uniform mat4 projMat;//投影
void main()
{
gl_Position=projMat*viewMat*modelMat*vec4(aPos.x,aPos.y,aPos.z,1.0f);
vertexColor=vec4(aColor,1.0f);
TextureCoord=aTextureCoord;
}
片段着色器
#version 330 core
out vec4 FragColor;
in vec2 TextureCoord;
uniform sampler2D ourTexture;//纹理
void main()
{
vec4 texColor = texture(ourTexture, TextureCoord);
if(texColor.a < 0.1)//alpha值小于0.1就抛弃
discard;
FragColor = texColor;
}
形状和位置的数组
float transparentVertices[] = {
// positions // texture Coords (swapped y coordinates because texture is flipped upside down)
0.0f, 0.5f, 0.0f, 0.0f, 0.0f,
0.0f, -0.5f, 0.0f, 0.0f, 1.0f,
1.0f, -0.5f, 0.0f, 1.0f, 1.0f,
0.0f, 0.5f, 0.0f, 0.0f, 0.0f,
1.0f, -0.5f, 0.0f, 1.0f, 1.0f,
1.0f, 0.5f, 0.0f, 1.0f, 0.0f
};
glm::vec3 grass_pos[]=
{
glm::vec3(-1.5f, 0.0f, -0.48f),
glm::vec3(1.5f, 0.0f, 0.51f),
glm::vec3(0.0f, 0.0f, 0.7f),
glm::vec3(-0.3f, 0.0f, -2.3f),
glm::vec3(-1.0f, 0.0f, -0.314f),
glm::vec3(1.0f, 0.0f, 0.51f),
glm::vec3(2.23f, 0.0f, 0.7f),
glm::vec3(-1.3f, 0.0f, -2.3f),
glm::vec3(-0.5f, 0.0f, -0.48f),
glm::vec3(2.5f, 0.0f, 1.1f),
glm::vec3(1.0f, 0.0f, 0.78f),
glm::vec3(-0.9f, 0.0f, -2.3f),
glm::vec3(0.5f, 0.0f, -0.6f)
};
然后是申请对应的VAO和VBO
GLuint transparentVBO, transparentVAO;
glGenVertexArrays(1, &transparentVAO);
glGenBuffers(1, &transparentVBO);
glBindVertexArray(transparentVAO);
glBindBuffer(GL_ARRAY_BUFFER, transparentVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(transparentVertices), transparentVertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(2);
加载纹理图片
unsigned int texbufferC;
texbufferC = Load_Texture("grass.png", GL_RGBA, GL_RGBA, 2);
开始绘制
for (int i = 0; i < sizeof(grass_pos) / sizeof(grass_pos[0]); i++)
{
glBindVertexArray(transparentVAO);//应用透明VAO
glm::mat4 modelMat;
modelMat = glm::translate(modelMat,grass_pos[i]);//定义位置
glActiveTexture(GL_TEXTURE2);//加载和绑定纹理
glBindTexture(GL_TEXTURE_2D, texbufferC);
shader.setInt("ourTexture", 2);//传输纹理号给片段着色器
shader.setMat4("modelMat", modelMat);//设置模型矩阵
glDrawArrays(GL_TRIANGLES,0,6);//根据模型行数决定这里的数值
}
绘制结果:
其中的
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, texbufferC);
是可以去掉的,因为前面已经绑定过纹理编号了。
现在再来写写半透明的窗子。
先开启混合
glEnable(GL_BLEND);//开始混合
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);//混合函数设置,源颜色向量的alpha做源因子,1-alpha做目标因子
再使用vector装一下窗口位置。
vector<glm::vec3> windows_pos =
{
glm::vec3(-1.5f, 0.0f, -0.48f),
glm::vec3(1.5f, 0.0f, 0.51f),
glm::vec3(0.0f, 0.0f, 0.7f),
glm::vec3(-0.3f, 0.0f, -2.3f),
glm::vec3(0.5f, 0.0f, -0.6f)
};
然后再用map做一个窗口与相机距离之间的排序。
std::map<float, glm::vec3>sorted;//map相当于字典
for (unsigned int i = 0; i < windows_pos.size(); i++)
{
float distance = glm::length(myCamera->Position - windows_pos[i]);//通过相机位置计算先后顺序
sorted[distance] = windows_pos[i];
}
最后渲染这些窗口
glBindVertexArray(transparentVAO);
for (std::map<float, glm::vec3>::reverse_iterator it = sorted.rbegin(); it != sorted.rend(); ++it)
{
modelMat = glm::mat4(1.0f);
modelMat = glm::translate(modelMat, it->second);
shader.setInt("ourTexture", 2);
shader.setMat4("modelMat", modelMat);
glDrawArrays(GL_TRIANGLES, 0, 6);
}
最后结果:
记住:
glEnable(GL_DEPTH_TEST);//开启深度测试
glEnable(GL_BLEND);//开始混合
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);//混合函数设置,源颜色向量的alpha做源因子,1-alpha做目标因子
这些开启什么模式的东西,必须在 glfwMakeContextCurrent(window);之后,否则就相当于没有开启。
放在glfwMakeContextCurrent(window);之前的结果。
面剔除
面剔除就是不渲染立方体后面不能看见的面,可以节省50%及以上的片段着色器性能。对于想前面的草,窗,地面这些非闭合物体需要关闭面剔除。
glEnable(GL_CULL_FACE);//开启面剔除
glCullFace(GL_BACK);//只剔除后面的
glDisable(GL_CULL_FACE);//关闭面剔除
如果在渲染非闭合物体时,没有关闭面剔除,就会导致
渲染出来的箱子中空,地面消失了。