【问题标题】:OPENGL Blending function - replacing colors slowly in a layering mannerOPENGL 混合功能 - 以分层方式缓慢替换颜色
【发布时间】:2012-05-28 10:56:51
【问题描述】:

我想要做的是在鲜红色 (1,0,0,1) 之上添加带有 alpha (0.1,0,0,0.2) 的深红色。对于第一层它工作正常,结果是 (0.9 ,0 ,0, 1);但是,当红色值达到 0.5 时,它不能低于该值。

第一层用以下等式演示,并且工作正常:

glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
ColorBuffer color = (1,0,0,1)      Bright Red
SourceColor color = (0.1,0,0,0.2)  Dark Red

GL_ONE = 1   ,  GL_ONE_MINUS_SRC_ALPHA = 1 - 0.2 = 0.8

Cf = (ColorSource * One) + (ColorBuffer * One Minus Src Alpha);
Cf = ((0.1,0,0)*1 )   +  ((1,0,0) * 0.8);
Cf =   0.1,0,0        +     0.8,0,0;
Cf =   0.9,0,0  // Here is the result

现在在多层之后再往下走,它会到达目标颜色更暗的点:0.5,现在颜色永远不会变暗,如下所示,它从 0.5,0,0 开始,但结果是 0.5 ,0,0:

Cf = ((0.1,0,0)*1 )   +  ((0.5,0,0) * 0.8);
Cf =    0.1,0,0       +       0.4,0,0;
Cf =    0.5,0,0 

这是结果,这意味着颜色缓冲区没有改变,我覆盖的颜色不再有任何效果。

如何让我的深红色分层,直到它取代鲜红色?

演示问题的简单处理草图 - 你会注意到这里我正在尝试 GL_SRC_ALPHA,但它仍然存在这个问题:

http://studionu.net/files/OPENGL_test.zip

下图描述了左边的问题,右边是想要的效果。

在此编辑代码

这是我的代码:

我设置了一个纹理缓冲对象并附加到一个 FBO:

 'gl.glGenTextures(1, drawTex, 0);    
  gl.glBindTexture(GL.GL_TEXTURE_2D, drawTex[0]);
  gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
  gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
  gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE);
  gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE);
  gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA8, 1000, 500, 0, GL.GL_BGRA,    GL.GL_UNSIGNED_BYTE, null);  '

' // Creating FBO.
  gl.glGenFramebuffersEXT(1, drawFBO, 0);
  gl.glBindFramebufferEXT(GL.GL_FRAMEBUFFER_EXT, drawFBO[0]);
  gl.glFramebufferTexture2DEXT(GL.GL_FRAMEBUFFER_EXT, GL.GL_COLOR_ATTACHMENT0_EXT, GL.GL_TEXTURE_2D, drawTex[0], 0);
  int stat = gl.glCheckFramebufferStatusEXT(GL.GL_FRAMEBUFFER_EXT);
  if (stat != GL.GL_FRAMEBUFFER_COMPLETE_EXT) System.out.println("FBO error");
  gl.glBindFramebufferEXT(GL.GL_FRAMEBUFFER_EXT, 0);'

然后我清除帧缓冲区:

' gl.glBindFramebufferEXT(GL.GL_FRAMEBUFFER_EXT, drawFBO[0]);

  // Drawing to the first color attachement of drawFBO (this is where drawTex is attached to).
  gl.glDrawBuffer(GL.GL_COLOR_ATTACHMENT0_EXT);    
  gl.glViewport(0, 0, 1000, 500);

    gl.glColor4f(0.0, 0.0, 0.0, 0.0);   

  gl.glClear(gl.GL_COLOR_BUFFER_BIT);

  // Unbinding drawFBO. Now drawing to screen again.
  gl.glBindFramebufferEXT(GL.GL_FRAMEBUFFER_EXT, 0);   '

在这里我绑定帧缓冲区并绘制到它,我在这里设置颜色膨胀:

'  gl.glBindFramebufferEXT(GL.GL_FRAMEBUFFER_EXT, drawFBO[0]);
  // Drawing to the first color attachement of drawFBO (this is where drawTex is attached to).
  gl.glDrawBuffer(GL.GL_COLOR_ATTACHMENT0_EXT);    

 // Setting orthographic projection.   
  gl.glMatrixMode(GL.GL_PROJECTION);
  gl.glPushMatrix();      
  gl.glLoadIdentity();
  gl.glOrtho(0.0, 1000, 0.0, 500, -100.0, +100.0);
  gl.glMatrixMode(GL.GL_MODELVIEW);
 gl.glPushMatrix();   
 gl.glLoadIdentity();

  gl.glViewport(0, 0, 1000, 500);

  gl.glDisable(GL.GL_TEXTURE_2D);


 gl.glEnableClientState(GL.GL_VERTEX_ARRAY);
 gl.glVertexPointer(2, GL.GL_FLOAT, 0, paintBuffer);
 // gl.glHint (gl.GL_POINT_SMOOTH_HINT, gl.GL_NICEST);    
 // gl.glEnable(gl.GL_POINT_SMOOTH);
 gl.glEnable(gl.GL_VERTEX_PROGRAM_POINT_SIZE);

 gl.glEnable(gl.GL_BLEND);      
 gl.glEnable(gl.GL_DEPTH_TEST);
 gl.glDepthFunc(gl.GL_NICEST);
 gl.glDisable(gl.GL_ALPHA_TEST);
 gl.glAlphaFunc(gl.GL_LESS, 0.01);

 gl.glPointSize(35.0);  

  float kBrushOpacity = 0.05/3.0; 

  println(kBrushOpacity);

  float  colorchange = 1.0;



 if (timer>200) {
   colorchange = 0.5; //////COLOR GETS DARKER
  }

 if (timer>400) {
   //colorchange = 0.2; //////COLOR GETS DARKER AGAIN
 }

  timer++;
 gl.glDisableClientState( gl.GL_COLOR_ARRAY );
  gl.glColor4f(colorchange, 0, 0.0, kBrushOpacity);  
  gl.glBlendFuncSeparate(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA,gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_DST_ALPHA);////////THIS IS THE OPENGL BLEND EQUATION FOR PREMULTIPLIED COLORS



  gl.glDrawArrays(GL.GL_POINTS, 0, count); //Count tells us how many point exist to be drawn.
 gl.glDisable(gl.GL_BLEND);     //Dont use blend when drawing the texture to screen. Just draw it.

 gl.glDisableClientState(GL.GL_VERTEX_ARRAY);
  gl.glMatrixMode(GL.GL_PROJECTION);
  gl.glPopMatrix(); 
 gl.glMatrixMode(GL.GL_MODELVIEW);
 gl.glPopMatrix();    
 // Unbinding drawFBO. Now drawing to screen again.
  gl.glBindFramebufferEXT(GL.GL_FRAMEBUFFER_EXT, 0);   '

在这里我在屏幕上绘制纹理:

' gl.glDrawArrays(GL.GL_POINTS, 0, count); //Count tells us how many point exist to be drawn.
gl.glDisable(gl.GL_BLEND);      //Dont use blend when drawing the texture to screen. Just draw it.

gl.glDisableClientState(GL.GL_VERTEX_ARRAY);
gl.glMatrixMode(GL.GL_PROJECTION);
gl.glPopMatrix(); 
gl.glMatrixMode(GL.GL_MODELVIEW);
gl.glPopMatrix();     
// Unbinding drawFBO. Now drawing to screen again.
gl.glBindFramebufferEXT(GL.GL_FRAMEBUFFER_EXT, 0);   

// Setting orthographic projection. 
gl.glMatrixMode(GL.GL_PROJECTION);
gl.glPushMatrix();    
gl.glLoadIdentity();
gl.glOrtho(0.0, width, 0.0, height, -100.0, +100.0);
gl.glMatrixMode(GL.GL_MODELVIEW);
gl.glPushMatrix();    
gl.glLoadIdentity();

 gl.glViewport(0, 0, width, height);

 // Drawing texture to screen.
 gl.glEnable(GL.GL_TEXTURE_2D);
 gl.glActiveTexture(GL.GL_TEXTURE0);
  gl.glBindTexture(GL.GL_TEXTURE_2D, drawTex[0]);
 gl.glTexEnvf(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_REPLACE);
 gl.glBegin(GL.GL_QUADS);
gl.glTexCoord2f(0.0, 1.0);
gl.glVertex2f(0.0, 0.0);

 gl.glTexCoord2f(1.0, 1.0);
 gl.glVertex2f(width, 0.0);

 gl.glTexCoord2f(1.0, 0.0);
 gl.glVertex2f(width, height);

 gl.glTexCoord2f(0.0, 0.0);
 gl.glVertex2f(0.0, height);
  gl.glEnd();
  gl.glBindTexture(GL.GL_TEXTURE_2D, 0);

  gl.glMatrixMode(GL.GL_PROJECTION);
  gl.glPopMatrix(); 
 gl.glMatrixMode(GL.GL_MODELVIEW);
gl.glPopMatrix();   '

【问题讨论】:

    标签: opengl


    【解决方案1】:

    请问您为什么选择 GL_ONE 作为源因子?您的混合公式的总乘数值大于 1 的事实意味着只需将相同的颜色与自身混合并使其变亮,当您在尝试使其变暗时达到平衡时就会看到这一点。

    如果您使用更常见的源因子 GL_SRC_ALPHA,我认为它的行为应该符合您的预期。您有没有选择使用它的原因?

    如果您使用 GL_SRC_ALPHA 和 GL_ONE_MINUS_SRC_ALPHA 作为源/目标混合因子,您将不会因执行混合而偏向于使图像变亮,因为乘法因子的总和为 1。

    编辑:我不同意使用 GL_SRC_ALPHA 仍然会遇到同样的问题。我在 excel 中对公式做了一个快速模型,如下所示。混合的值最终收敛到源颜色 (0.1f)。如果您想更快地收敛,请使用更大的 src alpha 值。

    参数:

    Source Red = 0.1
    Source Alpha = 0.2
    Dest Red = 1.0 (iteration==0), Result[iteration-1] (iteration != 0)
    1-Src Alpha = 0.8
    Result = Src Red * Src Alpha + Dest Red * One_Minus_Src_Alpha
    

    结果:

    列:

    0: Iteration
    1: Source Red    
    2: Source Alpha
    3: Dest Red
    4: 1-Src Alpha
    5: Result
    
    0   1   2   3       4   5
    ------------------------------------------------
    0   0.1 0.2 1.00    0.8 0.82   (0.1 * 0.2 + 1.0  * 0.8 = 0.82)
    1   0.1 0.2 0.82    0.8 0.68   (0.1 * 0.2 + 0.82 * 0.8 = 0.68) 
    2   0.1 0.2 0.68    0.8 0.56   (etc...)
    3   0.1 0.2 0.56    0.8 0.47
    4   0.1 0.2 0.47    0.8 0.39
    5   0.1 0.2 0.39    0.8 0.34
    6   0.1 0.2 0.34    0.8 0.29
    7   0.1 0.2 0.29    0.8 0.25
    8   0.1 0.2 0.25    0.8 0.22
    9   0.1 0.2 0.22    0.8 0.20
    10  0.1 0.2 0.20    0.8 0.18
    11  0.1 0.2 0.18    0.8 0.16
    12  0.1 0.2 0.16    0.8 0.15
    13  0.1 0.2 0.15    0.8 0.14
    14  0.1 0.2 0.14    0.8 0.13
    15  0.1 0.2 0.13    0.8 0.13
    16  0.1 0.2 0.13    0.8 0.12
    17  0.1 0.2 0.12    0.8 0.12
    18  0.1 0.2 0.12    0.8 0.11
    19  0.1 0.2 0.11    0.8 0.11
    20  0.1 0.2 0.11    0.8 0.11
    21  0.1 0.2 0.11    0.8 0.11
    22  0.1 0.2 0.11    0.8 0.11
    23  0.1 0.2 0.11    0.8 0.10
    24  0.1 0.2 0.10    0.8 0.10
    25  0.1 0.2 0.10    0.8 0.10
    

    【讨论】:

    • 我选择 GL_ONE 作为我的源因子,因为我没有任何背景,所以绘制的第一个位不会显示,因为颜色缓冲区在 RGBA 的各个方面基本上都是 0,至少这就是它的作用我,当我没有任何背景。如果背景是不透明的,SRC_ALPHA 会在一定程度上起作用。
    • 顺便说一句,蒂姆,你有处理吗,我可以给你发一个简单的草图来复制问题吗?在这里:studionu.net/files/OPENGL_test.zip 试试看,让我知道。如您所见,SRC_ALPHA 也遇到了这个问题
    • 我不同意 SRC_ALPHA 遇到同样的问题,请查看我的编辑(我没有那个软件)。
    • 您说得对,先生,那么肯定是其他原因造成了这个问题......嗯,这是一个除了绿色之外有问题的图像,这是按照您的建议使用 SRC_ALPHA。 studionu.nu/files/GLPaint_dark_color.png你使用xCode吗?我可以把代码发给你
    • 只需将代码粘贴到您的帖子中,或者使用键盘,就足够了。你确定你做了足够多的迭代来让它融合吗?请注意,在我的示例中,大约需要 25 次迭代才能达到初始值。您可能想尝试使用更大的 src_alpha 以更快地收敛。
    【解决方案2】:

    答案是使用与 GIMP 或 Photoshop 或 SKetchbook 等绘图程序相同的方法。他们从不混合任何新绘制到画布上的东西,它只是在每次调用结束时绘制为纹理四边形。这么快,你永远看不到它......无论如何,这对我有用,希望对其他人有所帮助。

    【讨论】:

      猜你喜欢
      • 2010-11-07
      • 2014-09-22
      • 2014-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多