iPhone OpenGL ES 2.0与Cocos2D的混合产生了意想不到的结果

iPhone OpenGL ES 2.0与Cocos2D的混合产生了意想不到的结果,iphone,cocos2d-iphone,opengl-es-2.0,alpha,blending,Iphone,Cocos2d Iphone,Opengl Es 2.0,Alpha,Blending,我有一个非常简单的CCScene,只有一个CCLayer包含: 标准混合模式背景的CCSprite CCRenderTexture绘制画笔,其精灵附着到背景精灵上方的根CCLayer: 当用户使用第一个彩色笔刷时,它会像预期的那样与背景混合。 但是,如果继续在上一个笔刷的顶部使用另一种颜色刷牙,则会出现错误(当两个笔刷相互重叠时,软alpha边将失去不透明度): [_renderTexture begin]; glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE

我有一个非常简单的CCScene,只有一个CCLayer包含:

  • 标准混合模式背景的CCSprite
  • CCRenderTexture绘制画笔,其精灵附着到背景精灵上方的根CCLayer:
  • 当用户使用第一个彩色笔刷时,它会像预期的那样与背景混合。 但是,如果继续在上一个笔刷的顶部使用另一种颜色刷牙,则会出现错误(当两个笔刷相互重叠时,软alpha边将失去不透明度):

    [_renderTexture begin];
    glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ONE); // 1.
    // calculate vertices code,etc...
    glDrawArrays(GL_TRIANGLES, 0, (GLsizei)count);
    [_renderTexture end];
    

    我尝试了许多混合选项,但不知何故,我找不到正确的一个

    CCRenderTexture是否有一些特殊之处,使其无法像预期的那样与自身(先前绘制的内容)混合?

    我的用于刷牙的片段着色器只是标准纹理着色器,只需稍作更改即可在纹理中保留输入颜色alpha:

    void main() { gl_FragColor = texture2D(u_texture, v_texCoord); gl_FragColor.a = v_fragmentColor.a; } 在呈现代码时(代替
    //1.

    这非常有效,可以满足我的需求……

    …但仅当重新渲染为完全不透明度时。

    \u rendertexture.sprite
    的不透明度降低时,画笔会变亮,而不是像预期的那样淡出:

    为什么当父纹理处于完全不透明度时,画笔的字母正确地与背景混合,而当不透明度降低时,画笔的字母会变得异常?如何使画笔正确地与背景混合?编辑

    混合笔刷->图层->背景 好的,现在发生的是
    glBlendFunc(GL_SRC_ALPHA,GL_ONE_减去GL_SRC_ALPHA)
    正在将笔刷笔划混合到笔刷纹理中,但纹理中产生的alpha值是错误的。每个添加的片段需要1.将其alpha值添加到最终alpha值-它必须准确地移除交互所需的光线,2.将之前的alpha值按剩余值缩放-之前的曲面减少light是以前的值,但由于添加了一个新的表面,它们减少的光线就更少了。我不确定这是否有意义,但这导致了

    glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
                        GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
    
    现在,笔刷纹理的颜色通道包含要与背景混合的总颜色(与alpha预先相乘),alpha通道给出权重(或颜色遮挡背景的量)。由于颜色与alpha预先相乘,默认的渲染纹理混合
    GL_SRC_alpha,GL_ONE_减_SRC_alpha
    再次与alpha缩放,从而使整体颜色变暗。现在需要使用以下函数将笔刷纹理与背景混合,我收集的函数必须在Cocos2D中设置:

    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
    
    希望这是可能的。对于如何设置笔刷纹理以与
    GL_SRC_ALPHA,GL_ONE_减号_SRC_ALPHA
    混合的可能性,我没有过多考虑,但它可能需要浮点纹理和/或额外的过程来分割/规格化ALPHA,这听起来很痛苦

    或者,在绘制之前将背景渲染到渲染纹理中,并将地块保留在那里,而不进行任何层的混合

    这对我很有用:

    glDisable(GL_DEPTH_TEST);
    glClear(GL_COLOR_BUFFER_BIT);
    glEnable(GL_TEXTURE_2D);
    glEnable(GL_BLEND);
    
    fbo.bind();
    glClear(GL_COLOR_BUFFER_BIT);
    glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
                        GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
    drawTexture(brush1);
    drawTexture(brush2);
    fbo.unbind();
    
    drawTexture(grassTex); //tex alpha is 1.0, so blending doesn't affect background
    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
    drawTexture(fbo.getColour(0)); //blend in the brush layer
    

    笔刷层不透明度 使用
    GL\u ONE,GL\u ONE\u减去\u SRC\u ALPHA
    会导致库在层混合中实现不透明度的问题,因为它假设颜色乘以ALPHA。通过减少
    不透明度
    值,笔刷层的ALPHA在混合过程中会缩小。
    GL\u ONE\u减去\u SRC\u ALPHA
    然后会导致背景色要增加,但画笔层的总颜色为100%,使图像过饱和

    imo最简单的解决方案是找到一种方法,通过全局图层不透明度来缩小颜色比例,并继续使用
    GL\u ONE,GL\u ONE\u减去\u SRC\u ALPHA

    • 实际上使用
      GL\u CONSTANT\u COLOR,GL\u ONE\u减去SRC\u ALPHA
      可能是一个答案,如果库支持它,但显然它不支持
    • 您可以使用固定管道渲染来缩放颜色:
      glColor4f(不透明度、不透明度、不透明度、不透明度)
      ,但这将需要第二个渲染目标并手动进行混合,类似于上面的代码,在上面的代码中,您为背景绘制一次全屏四元图,为笔刷层绘制一次全屏四元图
    • 如果您手动进行混合,则使用片段着色器而不是
      glColor
      方法将更为稳健。如果您想要使用更复杂的混合函数,这将允许进行更大的控制,尤其是在涉及0到1范围之外的分割和临时性时:
      gl\u FragColour=纹理(画笔纹理,坐标)*图层能力;
    结束编辑


    标准的alpha混合函数是
    glBlendFunc(GL_SRC_alpha,GL_ONE_减去_SRC_alpha);
    ,而不是GL“initial”/default函数

    在glBlendFuncSeparate中对alpha值求和将使alpha过饱和,下面的颜色将被完全替换。饱和混合可能会产生不错的结果:。如果支持,还可能值得尝试和MAX混合。使用MAX的好处是减少重叠的人工制品(硬三角形位)从您的线条绘制代码-例如,替换颜色,但仅在达到总阿尔法值X之前。编辑:两种情况都需要在每个笔划后混合和清除

    我只能假设将渲染纹理混合到背景上实际上是可行的。(不适用于当前层值)

    另一方面,也有“欠混合”,即保留透射比值,而不是alpha/opacity(从):

    glBlendFunc(GL_SRC_ALPHA_SATURATE,GL_ONE)不起作用-请参阅问题的更新部分(在底部)。我假设您
    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
    
    glDisable(GL_DEPTH_TEST);
    glClear(GL_COLOR_BUFFER_BIT);
    glEnable(GL_TEXTURE_2D);
    glEnable(GL_BLEND);
    
    fbo.bind();
    glClear(GL_COLOR_BUFFER_BIT);
    glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
                        GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
    drawTexture(brush1);
    drawTexture(brush2);
    fbo.unbind();
    
    drawTexture(grassTex); //tex alpha is 1.0, so blending doesn't affect background
    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
    drawTexture(fbo.getColour(0)); //blend in the brush layer
    
    glBlendEquation(GL_FUNC_ADD); 
    glBlendFuncSeparate(GL_DST_ALPHA, GL_ONE, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);