将半透明精灵绘制到非黑色背景时的WebGL混合问题(cocos2d html5)

时间:2013-10-30 20:10:26

标签: html5 opengl-es cocos2d-iphone webgl cocos2d-html5

我正在尝试使用Cocos2d HTML5框架,但我认为这是一个标准的WebGL问题我无法确定,因为我对这个主题没有很好的了解。如果我有一个带有半透明像素的标准PNG图像,例如柔化边缘,并且如果背景(画布或RenderTexture背后的其他元素)填充了非黑色,则绘制到RenderTexture时的精灵最终浸泡在背景,即使它不应该。例如,如果我正在绘制的图形是红色而我使用的是绿色背景,则半透明像素最终会变为黄色。请参阅以下图片:

在坚实的黑色背景下出现,这就是我的愿望 Appearance when against a solid black background, this is what I desire

在非黑色背景下出现,bg流血 Appearance against a non-black background, with the bg bleeding through

当我放置任何非100%不透明图像时,背景中的任何内容都会显示出来。

完整的基于JavaScript的RenderTexture类代码可以在cocos2d-html5 Github Repository的cocos2d / misc_nodes / CCRenderTexture.js下看到。它是来自Cocos2d-x C ++ / Objective C的转换(没有出现这个问题)。据报道,cocosd-iphone问题跟踪器上的问题#937描述了几年前非HTML版本的相同问题。它已经解决了,但我似乎无法确定解决方案是什么或如何将其转换为WebGL格式。我确定这是一个混合问题,但我尝试更改混合模式(从GL_ONE,GL_ONE_MINUS_SRC_ALPHA到GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA等)无济于事。

非常感谢OpenGL / WebGL专家提供的任何帮助。如果我在此RenderTexture之外的Cocos2d中使用标准“精灵”,则问题不存在。此外,MotionStreak功能似乎也没有故障,但我需要RenderTexture来创建动态纹理以供进一步使用。

1 个答案:

答案 0 :(得分:2)

WebGL默认与图像和画布2D相同,即它期望画布的内容为RGBA,它期望RGB被alpha预乘(换句话说,如果alpha为零,则RGB必须也是零,因为任何时间零等于零)。最后用GL_ONE,GL_ONE_MINUS_SOURCE_ALPHA与其背后的任何东西混合。

如果你想要它不同,你有两个选择

  1. 告诉WebGL不要有alpha

    您可以通过创建没有alpha

    的上下文来执行此操作
    gl = canvas.getContext("experimental-webgl", { alpha: false });
    

    这可能是您案例的最佳选择。由于不存在alpha,因此不需要混合,这比浏览器通常需要的背景混合更快。

  2. 告诉WebGL您的RGB值不是预乘的

    gl = canvas.getContext(“experimental-webgl”,{premultipledAlpha:false});

    这意味着浏览器仍然会将您的WebGL画布与背景混合,它只会使用GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA来实现。你仍会看到背后的绿色。

  3. 在特殊情况下还有一些其他可能有用的解决方案

    1. 如果您需要在目的地使用alpha进行某些计算,则可以在完成后将alpha清除为

      ...render scene...
      
      gl.colorMask(false, false, false, true);
      gl.clearColor(0, 0, 0, 1);
      gl.clear(gl.COLOR_BUFFER_BIT);
      

      混合仍然会发生你只是不会看到它,因为你的所有alpha都设置为1.不是最好的解决方案,但如果你需要目标alpha,它可能是你唯一的解决方案。

    2. 如果您不想看到画布后面的内容,请为画布添加背景颜色

      <canvas style="background-color: green;"></cavnas>
      

      将画布的背景颜色设置为黑色也可以,但这也是一种浪费,因为它仍然会将画布与黑色混合。如果这就是你想要的,那么首先关闭alpha。