OpenGL中图层混合公式的一点探讨

2020-07-15  本文已影响0人  默默_David

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();
}

直接运行后,初始效果如下:

初始效果

然后我们移动中央矩形,分别和其它四个重合,显示的结果如下:


重合绿色
重合紫色
重合灰色
重合粉色

如图所示,在和绿色、紫色、灰色重合时,看上去没有任何问题

但是在和粉色重合时,我们发现,重合部分直接是红色,没有任何的变化。

按照我们的公式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}来测试结果:

结果

我们可以发现,重合区域明显比{1,0,0,0.8}要深,按照公式计算得出结果应该是{1,0,0,0.65},结果明显比计算出的结果要深。

我们再设置Cs为{1,0,0,0.2},Cd为{1,0,0,0.1}来测试结果:

结果
可以看到,结果也是比计算结果{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)

对于上述三个案例,分别可以得出:

  1. Cs为{1,0,0,0.5},S为0.5,Cd为{1,0,0,1},D为0.5,结果为{1,0,0,1}
  2. Cs为{1,0,0,0.5},S为0.5,Cd为{1,0,0,0.8},D为0.5,结果为{0.9,0,0,1}
  3. Cs为{1,0,0,0.2},S为0.2,Cd为{1,0,0,0.1},D为0.8,结果为{0.28,0,0,1}

对于以上三个结果,我们也可以转换为带透明度的值,分别为

  1. Cf为{1,0,0,1},Cs为{1,0,0,0.5},Cd为{1,0,0,1}
  2. Cf为{1,0,0,0.9},Cs为{1,0,0,0.5},Cd为{1,0,0,0.8}
  3. 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)

上述仅仅个人研究的一点心得,如果有不对的地方欢迎各位朋友留言探讨

上一篇 下一篇

猜你喜欢

热点阅读