cocos2d-iphoneopengl-es-2.0cocos2d-xfboglblendfunc

Cocos2dx CCRendertexture and framebuffer object problems. My new texture doesn't look the same. Alpha values are incorrect


I'm having a bit of a problem trying to use the CCRenderTexture class from Cocos2Dx for the iPhone (which, as I understand it, is just a FBO class).

I have a class that derives from CCSprite. Within it, I'm trying to draw a texture to a CCrenderTexture and then save it for later. However, I noticed that the alpha values in my new texture seem to have been intensified. My new texture appears a bit more faded than the original, it only seems to effect pixels with an alpha less then 1.0.

Here is the code I am using:

CCRenderTexture* myRenderTexture = CCRenderTexture::create((int)getContentSize().width, (int)getContentSize().height);   //set RenderTexture to same size as sprite

myRenderTexture->begin();

CC_NODE_DRAW_SETUP();

ccGLEnableVertexAttribs(kCCVertexAttribFlag_PosColorTex);

ccGLBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);      //Is this where my problem is?  

glActiveTexture(GL_TEXTURE0);


glBindTexture( GL_TEXTURE_2D, finalTexture->getName());     //finalTexture is created before this code is run
glUniform1i(textureLocation, 0);


long offset = (long)&m_sQuad;

// vertex
int diff = offsetof( ccV3F_C4B_T2F, vertices);
glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, kQuadSize, (void*) (offset + diff));
// texCoods
diff = offsetof( ccV3F_C4B_T2F, texCoords);
glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, (void*)(offset + diff));
// color
diff = offsetof( ccV3F_C4B_T2F, colors);
glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (void*)(offset + diff));

glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glActiveTexture(GL_TEXTURE0);


myRenderTexture->end();
finalTexture = myRenderTexture->getSprite()->getTexture();   //Replace Final Texture with my new texture (Should be exact same)

finalTexture->retain();
myRenderTexture->release();

As a test, I ran the above code 4 times in succession. Each time, the texture seemed to fade a bit more. But what I expect is it to look the same each time.

The next step I took was to replace ccGLBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) with ccGLBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA) It seemed to solve my problem, as the resulting texture looked the same no matter how many times I ran it. However, I am also running a custom fragment shader on this texture (shader not pictured and not running during this test) and it requires ccGLBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) to work correctly.

After some research, I tried replacing ccGLBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) with glBlendFuncSeparate(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA,GL_ONE, GL_SRC_ALPHA). I hoped this would maintain my alpha levels, while changing the color values. Unfortunately, this had the opposite effect and seemed to actually dull the alpha, causing the texture to darken.

Here is a picture with my three tests. This bikini bottom asset makes it easy to see the effect ;)

enter image description here

Can someone tell me what I am doing doing wrong and what is causing these effects? Is it my BlendFunc? I need to be able to draw to a CCRenderTexture (or a FBO) several times in succession and I don't want any undesired effects on the image. I also need to use my shaders… so ccGLBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA) doesn't work...

Any help is appreciated! Thanks in advance!


Solution

  • I was able to find a solution that worked for me. I'm not sure if it's ideal or if there is a better way, but it seems to work.

    As I said before, using ccGLBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA) allowed me to use a CCRenderTexture as many times as I wanted, but my shaders didn't work correctly.

    Changing to glBlendFuncSeparate(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA,GL_ONE, GL_SRC_ALPHA) allowed the shaders, but the texture darkened each time I rendered it to the CCRenderTexture.

    After comparing the textures in Photoshop, it appeared that glBlendFuncSeparate(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA,GL_ONE, GL_SRC_ALPHA) would multiply my color values by my alpha value. Which makes sense I suppose, because I am setting the color blend to GL_ONE_MINUS_SRC_ALPHA.

    So my solution was to reverse this effect by then dividing my color values by the alpha value within the shader. I added these lines to the end of my shader.

    texColor.r = texColor.r / texColor.a;      \n\
    texColor.b = texColor.b / texColor.a;      \n\
    texColor.g = texColor.g / texColor.a;      \n\ 
    

    It seems a little silly, I would prefer to find a way that doesn't make these changes to the color at all, because this step is wasteful. But it works!