renderTexture saveToFile artifacts

I’m using the below code to save an image using RenderTexture:

    auto sprite = Sprite::create("original.png");
    auto renderTexture = RenderTexture::create(64, 64, Texture2D::PixelFormat::RGBA8888);
    renderTexture->begin();
    sprite->setAnchorPoint(Vec2(0, 0));
    sprite->setPosition(Vec2(0,0));
    sprite->visit();
    renderTexture->end();
    renderTexture->saveToFile("rendertexture.png", Image::Format::PNG);

My issue is that I get strange artifacts in the saved file. For example look at the below images:

original
rendertexture

The first image is the original while the second is the renderTexture->saveToFile() image. Notice how for the second one the edges at the top have a dark border which the original does not have. Is it maybe something to do with the alpha values at the edges not being saved properly? Any ideas on how to fix?

2 Likes

You just saving same image 2 times, render->clear(); before begin always works.

1 Like

Thanks, worked perfectly.

Hey sorry to bring this up again but I just realized that this didn’t exactly solve my problem after I saw my image on a different background. Before renderTexture->begin(), I called renderTexture->clear(255,255,255,0). However this had the result of adding a white border at my alpha values instead of a black one which I guess is used by default if you don’t call clear(). You can see this with my below images. The black background isn’t part of the image but shows how my image is affected by extra white pixels at the bottom. The first is original image and the second is the renderTexture.
original
rendertexture
The weird thing is that it’s like the alpha fails where my pixels are semi transparent. So if I use renderTexture->clear(255,0,0,0) then I get a red border even though the rgb shouldn’t have any effect since alpha is set to zero. Any ideas?

Zip original image and attach. Also, your fully code for all these render. Looks like your render twice. Aso clear with all 0.

My code is same as first post except I added clear() before begin().

auto sprite = Sprite::create("original.png");
auto renderTexture = RenderTexture::create(64, 96, Texture2D::PixelFormat::RGBA8888);
renderTexture->clear(0,0,0,0);
renderTexture->begin();
sprite->setAnchorPoint(Vec2(0, 0));
sprite->setPosition(Vec2(0,0));
sprite->visit();
renderTexture->end();
renderTexture->saveToFile("rendertexture.png", Image::Format::PNG);

With the above code, I have dark borders just like in my first post. See attached.
images.zip (18.1 KB)

I just see that current RenderTexture have some bugs. In my option there is other bug described in this topic: Radial Gradient.
And I’ve reproduced your code too, I believe it’s a bug. You should create an issue: https://github.com/cocos2d/cocos2d-x/issues/new and probably @zhangxm can take a look and fix. Thats something with new 3.15+ cocos…

@hotcoco i can not download the images.zip, it seems it is broken. Could you please upload it again? Thanks.

Ok, i downloaded in the corresponding github issue, i will take a look now.

Please refer to the github issue. It is a usage issue, but a bug.

Issue closed, so I will countinue here.

  1. And what if I have already several Sprites on the scene with applied my own BlendFunc needed for visual effects?

  2. Also, question why it’s by default BlendFunc::ALPHA_NON_PREMULTIPLIED ?

    void Sprite::updateBlendFunc(void)
    {
    CCASSERT(_renderMode != RenderMode::QUAD_BATCHNODE, “CCSprite: updateBlendFunc doesn’t work when the sprite is rendered using a SpriteBatchNode”);

     // it is possible to have an untextured sprite
     if (! texture || ! texture->hasPremultipliedAlpha())
     {
         _blendFunc = BlendFunc::ALPHA_NON_PREMULTIPLIED;
         setOpacityModifyRGB(false);
     }
     else
     {
         _blendFunc = BlendFunc::ALPHA_PREMULTIPLIED;
         setOpacityModifyRGB(true);
     }
    

    }

When texture loads it will be auto changed to proper func.

Also, - https://github.com/cocos2d/cocos2d-x/blob/d07794052fed5c3edc29d4a60f99399d49271515/cocos/2d/CCRenderTexture.h#L338

/** The Sprite being used.
The sprite, by default, will use the following blending function: GL_ONE, GL_ONE_MINUS_SRC_ALPHA.

  1. Is that mean that it’s a bug because it’s suppose to have GL_ONE, GL_ONE_MINUS_SRC_ALPHA by default for Sprite?

No, it is not a bug of Sprite, the blend function is selected depends on if it has alpha channel or not. And on most situations, picture has alpha channel, and it is the expected behavior to blend with the background.

@zhangxm

I have added some visual effect for some Sprite(just needed to my game) and can’t set {GL_ONE, GL_ZERO} …

So I can’t do:

sprite->setBlendFunc({GL_ONE, GL_ZERO}); —》 change the blend function
sprite->visit();

So, assuming this:

I’m using RenderTexture for some sprites and got artifacts on final image. I’m not sure, but in some old previous versions I haven’t faced with this problem for same situation with same game. Also, I can’t change blending of sprite to visit, by my game design. How to solve this? This is an issue…