透明transparent,半透明semi-transparent。
blend简述
(blend英文义为混合,其进行的操作也是混合,但是莫名奇妙花了好长时间理解。)
这步操作在前文的各种测试之后进行,指定了将要添加进颜色缓冲区的片元颜色(source)如何与原来在颜色缓冲区内的片元颜色(Destination)混合成要加入缓冲区的新颜色。
这不要求加载的纹理其原文件格式和加载格式都是GL_RGBA
,如下文glBlendFuncSeparate()
可指定GL_RGB
情况。
光栅化rasterization
可以很容易发现顶点着色器和片元着色器之间虽然传递变量,但它们处理的对象数量都不同,变量怎么一一对应。
光栅化会对顶点着色器所有out出的数据进行插值,提供给每个片元着色器,所以这两个着色器之间插入了一个自动操作即光栅化。
当传入纹理坐标到顶点着色器,那么片元着色器传入的纹理坐标就是对应当前片元的插值,于是texture(utexture0, texCoords)
就是用该纹理坐标,按照指定采样方式在utexture0
纹理上采样。
(通常用aTexCoords
表示通过layout传入的数据,用TexCoords
代表需要用in/out传递的数据,有些地方会使用uTexCoords
的写法表示通过uniform传入的数据,texCoords
表示临时的数据,gl_position
表示内部维护数据)
Discarding fragment
这个功能完全不清楚是blending还是alpha test的,也有可能是在更早之前的片元着色器的操作,但是其功能都是为了利用如.png等格式图片的透明度数据。
在片元着色器中,用discard
语句可以直接抛弃掉该片元,于是利用透明度数据制造不规则贴图的方法就出现了。
vec4 texColor = texture(utexture0, TexCoords);
if(texColor.a < 0.1f){
discard;
}
所有被discard的片元没有机会进入逐片元操作,也就无法更改颜色缓冲区。
由于纹理坐标是浮点型,在wrap方式使用repeat时,透明纹理边缘上将使用其对面的颜色,这将导致出现有色边框。
如果一个透明纹理不需要扩展使用,那么请使用GL_CLAMP_TO_EDGE
设置纹理的wrap方式。
正式blending
一个非常重要涉及到透明度数据的工作自然是有色透明玻璃,而事实上这个工作确实很复杂。
-
glEnable(GL_BLEND)
-
glBlendFunc(GLenum sfactor, GLenum dfactor)
和glBlendFuncSeparate(1,2,3,4)
-
glBlendEquation(GLenum mode)
该逐片元操作虽然需要显式启用,但是不存在缓冲区。(中间变量勉强算)
使用glBlendFunc
时,其计算公式$C=C_sF_s+C_dF_d$,而该函数控制的就是如何选出factor即F。
两个参数分别是新颜色系数和旧颜色系数,如果要制造透明效果通常使用GL_SRC_ALPHA
和GL_ONE_MINUS_DST_ALPHA
的选项,但是还可以选择0、1、某常量等各种。常量通过glBlendColor
设置。
使用glBlendEquation
修改的是SRC和DST这两项如何合并,默认是上面的GL_FUNC_ADD
,但是也可以选择减、取最大等。
根据上面对Blending步骤的解释可以发现一个重要问题:一个未通过深度测试的片元将不能进行颜色混合。
当两片玻璃前后放置,当先渲染远玻璃时,近玻璃的所有片元都能过测试,所以正常混合;当先渲染近玻璃时,一部分远玻璃将无法通过测试,这些片元将消失。
(不再加一个缓冲区记录是否透明用来记住是否透明的原因是:当出现一透明和一不透明物体时,渲染第三个物体时将由深度决定是否参与到blending计算当中。)
所以透明物体渲染要求遵循严格的先近后远原则,但是也说明如果出现三面相互遮挡的情况,当前工具无法正确渲染。
comment 评论区
star_outline 咱快来抢个沙发吧!