(自用)learnOpenGL学习总结-高级OpenGL-混合

混合blending

其实就是透明度的意思,在这之前一个图片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

注意渲染的顺序

刚刚我们也看到了对于这种透明混合的物体,我们一定要在最后绘制,那么对于重叠的物体,我们也需要从后往前渲染,这样才能够保证准确性。

所以绘制同时存在透明和不透明的物体场景时顺序如下:

  1. 先绘制所有不透明的物体。
  2. 对所有透明的物体排序。
  3. 按顺序绘制所有透明的物体。

其中排序通过map来存。具体实现我就暂时不去学习了。

其实从教程里面也可以知道,多个透明物体对于渲染来说是致命的问题,在实际过程中应该尽量避免。

  • 5
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值