OpenGL中图层混合公式的一点探讨
OpenGL中图层混合公式的一点探讨
一、问题的提出
OpenGL混合的时候,常常会用到如下一个公式:
Cf = (Cs * S) + (Cd * D)
其中
Cf表示最终计算得出的颜色
Cs表示源颜色(作为当前渲染命令结果进⼊入颜⾊缓存区的颜色值)
Cd表示目标颜色(已经存储在颜⾊缓存区的颜⾊值)
S表示源混合因子
D表示目标混合因子
我们设置一个demo来看,其中渲染五个矩形,居中可以移动的大红色矩形先绘制,作为目标颜色,我们分别查看渲染后的结果,主要代码如下:
void RenderScene(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
//1.开启混合
glEnable(GL_BLEND);
//2.开启组合函数 计算混合颜色因子
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//定义4种颜色
//全红色先进行绘制,作为目标颜色
GLfloat vRed[] = { 1.0f, 0.0f, 0.0f, 1.0f };
GLfloat vRed1[] = { 1.0f, 0.0f, 0.0f, 0.5f };
GLfloat vGreen[] = { 0.0f, 1.0f, 0.0f, 0.5f };
GLfloat vBlue[] = { 0.0f, 0.0f, 1.0f, 0.5f };
GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 0.5f };
//绘制大红色矩形,作为目标颜色
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed);
squareBatch.Draw();
//绘制四个源颜色矩形
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vGreen);
greenBatch.Draw();
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed1);
redBatch.Draw();
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vBlue);
blueBatch.Draw();
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vBlack);
blackBatch.Draw();
//5.关闭混合功能
glDisable(GL_BLEND);
//同步绘制命令
glutSwapBuffers();
}
//上下左右键位控制大红色矩形移动
void SpecialKeys(int key, int x, int y)
{
...
上下左右移动作为目标颜色矩形的代码
...
//移动后触发重绘
glutPostRedisplay();
}
直接运行后,初始效果如下:
![](https://img.haomeiwen.com/i3038868/5bcecf04a75a6520.png)
然后我们移动中央矩形,分别和其它四个重合,显示的结果如下:
![](https://img.haomeiwen.com/i3038868/badf588541594f02.png)
![](https://img.haomeiwen.com/i3038868/d0f74962b99a17b9.png)
![](https://img.haomeiwen.com/i3038868/74157204bea1135d.png)
![](https://img.haomeiwen.com/i3038868/71073d112db71015.png)
如图所示,在和绿色、紫色、灰色重合时,看上去没有任何问题
但是在和粉色重合时,我们发现,重合部分直接是红色,没有任何的变化。
按照我们的公式Cf = (Cs * S) + (Cd * D)
,Cs为{1,0,0,0.5}
,S为0.5
,Cd为{1,0,0,1}
,D为0.5
,按照我们向量计算公式,Cf应该为{1,0,0,0.75}
,这和我们的结果完全不一致。这到底是什么原因呢?
改变颜色值来测试并得出结果
我们分别设置Cs为{1,0,0,0.5}
,Cd为{1,0,0,0.8}
来测试结果:
![](https://img.haomeiwen.com/i3038868/27889d9ef81876d2.png)
我们可以发现,重合区域明显比{1,0,0,0.8}
要深,按照公式计算得出结果应该是{1,0,0,0.65}
,结果明显比计算出的结果要深。
我们再设置Cs为{1,0,0,0.2}
,Cd为{1,0,0,0.1}
来测试结果:
![](https://img.haomeiwen.com/i3038868/bfddf9a1e4c39ef0.png)
可以看到,结果也是比计算结果
{1,0,0,0.1}
要深。
根据以上结果,我们发现直接套用公式和实际显示的结果是不一致的
那么,我们换一个思路,一个{r,g,b,a}
的颜色,我们可以改变写法为{r*a,g*a,b*a,1}
,那么我们对上述三个案例的颜色值与最终结果进行比较,可以发现最终颜色应该为:
Cf = (Cs的RGB值 * S) + ((Cd的RGB值 * Cd的alpha值)*D)
对于上述三个案例,分别可以得出:
- Cs为
{1,0,0,0.5}
,S为0.5
,Cd为{1,0,0,1}
,D为0.5
,结果为{1,0,0,1}
- Cs为
{1,0,0,0.5}
,S为0.5
,Cd为{1,0,0,0.8}
,D为0.5
,结果为{0.9,0,0,1}
- Cs为
{1,0,0,0.2}
,S为0.2
,Cd为{1,0,0,0.1}
,D为0.8
,结果为{0.28,0,0,1}
对于以上三个结果,我们也可以转换为带透明度的值,分别为
- Cf为
{1,0,0,1}
,Cs为{1,0,0,0.5}
,Cd为{1,0,0,1}
- Cf为
{1,0,0,0.9}
,Cs为{1,0,0,0.5}
,Cd为{1,0,0,0.8}
- Cf为
{1,0,0,0.28}
,Cs为{1,0,0,0.2}
,Cd为{1,0,0,0.1}
将它们分别和我们案例中的结果进行对比,发现和我们案例中的结果完全符合
所以,我们实际用于计算的的混合方程式应该为:
Cf(alpha为1) = (Cs的RGB值 * S) + ((Cd的RGB值 * Cd的alpha值)*D)
上述仅仅个人研究的一点心得,如果有不对的地方欢迎各位朋友留言探讨