其实就是透明度的意思,在这之前一个图片png格式会有4个通道,最后一个通道就是透明度,他的颜色是由自己的颜色和后面的颜色一起确定的,一般来说 设置为1(完全由自己颜色决定),0.25的意思是自己决定25%。
就像是抠图一样,现在我想给一个场景加上小草但是我不需要创建一个叫做草的东西,我只需要把草的贴图贴在一个2D四边形上就行。但是我只想显示草,不像显示四边形其他部分,这个时候就是透明度alpha起作用的时候了。
现在需要做的是有:生成一个小草贴图的材质material,生成一个专门生成小草的shader,生成一个画片图的meshDraw函数。
首先是材质:
Material* grassMaterial = new Material(grassShader,
LoadImageToGPU("grass.png", GL_RGBA, GL_RGBA),
LoadImageToGPU("grass.png", GL_RGBA, GL_RGBA),
LoadImageToGPU("grass.png", GL_RGBA, GL_RGBA),
glm::vec3(1.0f, 1.0f, 1.0f),
150.0f);
这里必须要把三个地方的贴图都设置为grass,如果其他两个给0,会一片黑。
然后是shader:
#version 330 core
in vec2 TexCoord;
struct Material{
vec3 ambient;
sampler2D diffuse;
sampler2D specular;
sampler2D emission;
float shininess;
};
uniform Material material;
out vec4 FragColor;
void main(){
vec4 texColor = texture(material.diffuse,TexCoord);
if(texColor.a<0.2){
discard;
}
FragColor = texColor;
}
这个shader里面需要有材质,这样才能把草的贴图放进来。
然后是mesh
void Mesh::DrawSliceArray(Shader* shader, int diffuse, int specular, int emission)
{
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, diffuse);
shader->SetUniform1i("material.diffuse", 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, specular);
shader->SetUniform1i("material.specular", 1);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, emission);
shader->SetUniform1i("material.emission", 2);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
glActiveTexture(GL_TEXTURE0);
}
for (unsigned int i = 0; i < 2; i++) {
modelMat = glm::translate(glm::mat4(1.0f), grassPosition[i]);
viewMat = camera.GetViewMatrix();
projMat = glm::perspective(glm::radians(fov), 800.0f / 600.0f, 0.1f, 100.0f);
grassShader->use();
glUniformMatrix4fv(glGetUniformLocation(grassShader->ID, "modelMat"), 1, GL_FALSE, glm::value_ptr(modelMat));
glUniformMatrix4fv(glGetUniformLocation(grassShader->ID, "viewMat"), 1, GL_FALSE, glm::value_ptr(viewMat));
glUniformMatrix4fv(glGetUniformLocation(grassShader->ID, "projMat"), 1, GL_FALSE, glm::value_ptr(projMat));
grassMesh.DrawSliceArray(grassMaterial->shader, grassMaterial->diffuse, grassMaterial->specular, grassMaterial->emission);
}
得到这样的结果,这是因为fragment中不知道需不需要丢弃那些透明度为0的部分,但是加入一个discard就行。
不过可以发现草周围有那种边框
这样就没有了,但是可以发现后面的matrix的动图变了这种样子,这是因为matrix的纹理环绕方式是gl_repeat,所以可以出现重复循环的方式。
接下来是真正的混合了,之前对于小草,我们是要么保留要么丢弃,但我想渲染半透明的图形可以不可以呢?
这是和和前面深度、模板一样,都需要开启混合功能。
glEnable(GL_BLEND);
然后再告诉他如何混合。
这样就可以了,那么里面的因子可以通过glBlendFunc来设置源因子和目标因子。
opengl给了很多设置因子的选项
再上面的例子里面,我需要把源颜色四通道里面的alpha作为源因子,1-a作为目标因子
所以是
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
现在我们要把一个透明的窗户放进去了
首先开启混合
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
把小草换成窗户试试把,得记得把片段着色器里面的discard删除
然后就是把之前草的那些东西都换成窗户。
但是却没有透明的感觉,这是为什么呢?
我在loop里面我是先画窗户,然后画机器人和箱子。但是要知道的是:混合的原理就是在源颜色的基础上添加混合的效果,在画窗户的时候本来就没有背景色,就谈不上透明了。
所以我们把窗户放到最后画把。
和预期一样,ok
刚刚我们也看到了对于这种透明混合的物体,我们一定要在最后绘制,那么对于重叠的物体,我们也需要从后往前渲染,这样才能够保证准确性。
所以绘制同时存在透明和不透明的物体场景时顺序如下:
其中排序通过map来存。具体实现我就暂时不去学习了。
其实从教程里面也可以知道,多个透明物体对于渲染来说是致命的问题,在实际过程中应该尽量避免。