OPENGL 混合功能 - 以分层方式缓慢替换颜色

标签 opengl

我想要做的是在鲜红色(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

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

red on red issue

编辑这里是代码

所以这是我的代码:

我设置了一个纹理缓冲区对象并附加到一个 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);   '

在这里,我绑定(bind)帧缓冲区并绘制到其中,并在此处设置颜色膨胀:
'  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();   '

最佳答案

请问您为什么选择 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

关于OPENGL 混合功能 - 以分层方式缓慢替换颜色,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10749114/

相关文章:

c - glCallLists 是否比一次调用一个显示列表更有效?

opengl - OpenGL纹理缓冲区对象的目的是什么?

c++ - 强制 OpenGL 将内容保存在内存中?

c++ - 如何从手动矩阵操作中推断平移、剪切等?

c++ - 相当于 glBegin/glEnd 的现代 OpenGL 是什么

java - 处理 2.0b8/处置 PGraphics 对象和内存管理

c++ - 使用四元数进行OpenGL旋转

opengl - 后处理和生成的纹理

c++ - OpenGL 正交投影

c++ - OpenGL/VTK : setting camera intrinsic parameters