Problem when use RenderTexture->newImage()! the image is black(empty),

coco2d-x-3.0
when I try to save a Sprite as a .png file, the problem occurred.
The step I follow is :

  1. sprite to RenderTexture;
  2. RenderTexture->newImage();
  3. image->saveToFile();
    and the image is black, there is nothing in it.
    although I can use the methoed renderTexture->saveToFile(), but it can’t create image which has transparent info. In fact, I need the image obejct to know pixel color in the srpite. It seems that the method RenderTexture->newImage() has problem. I can’t use the image.

my code is here:

bool PointCheck::checkHit(Sprite *sprite, float lx, float ly) //lx,ly is the local position 
{

Point oldPos = sprite->getPosition();
Point oldAnchor = sprite->getAnchorPoint(); 

Point location = Point((lx) * CC_CONTENT_SCALE_FACTOR(), (ly) * CC_CONTENT_SCALE_FACTOR());  
RenderTexture::create(sprite->getContentSize().width* CC_CONTENT_SCALE_FACTOR(),sprite->getContentSize().height * CC_CONTENT_SCALE_FACTOR(), Texture2D::PixelFormat::RGBA8888);
renderTexture->setKeepMatrix(true);
renderTexture->beginWithClear(0.0f,0.0f,0.0f,1.0f);
sprite->setAnchorPoint(Point(0,0));
sprite->setPosition(Point(0,0));
sprite->visit();
renderTexture->end();

renderTexture->saveToFile("8.png",kCCImageFormatPNG);  //it's ok, but the file has not transparent

auto image = renderTexture->newImage();   //maybe the problem is here
image->saveToFile(FileUtils::getInstance()->getWritablePath() + "9.png", false);//the image is empty
	
int index = (location.x + location.y * image->getWidth()) * 4;
unsigned char *pixel = image->getData() + index;
                                  
CCLOG("X:%.0f y:%.0f R: %d, G: %d, B: %d, A: %d",location.x ,location.y, pixel[0], pixel[1], pixel[2], pixel[3]);
               
if(pixel[0] || pixel[1] || pixel[2] || pixel[3])  
{  
   return true;
}
  return false;
}

are you getting a OpenGL error 0x0506 in -[CCEAGLView swapBuffers] 321 ???

I am also having this issue. A simple test:

auto renderTexture = RenderTexture::create(100,100);
renderTexture->beginWithClear(1,1,1,1);
renderTexture->end();

Image *testImage = renderTexture->newImage();
unsigned char *data = testImage->getData();

all the pixels in data are: {0,0,0,0}

Is this not the correct usage?

  1. Regarding the alpha channel issue, it’s an engine problem, the file is alway saved with RGB at present. We are going to fix it soon.

  2. Regarding the black image issue, it’s not proper to use newImage() in that way. Since the rendering of cocos2d-x 3.0 is based on the command queue, we should always wrap the read/write frame buffer operations with commands. Invoking newImage() directly is not guaranteed to work fine. But saveToFile should work fine because it’s wrapped with a custom command in code.

We’ve created a new issue to track the alpha-missing problem.
http://www.cocos2d-x.org/issues/5562

Thank you for your answers. And I found the bug has been resloved, thanks.

Hi, I’ve stumbled upon this post after an upgrade to cocos2dx v3.2 from 2.3. Apparently I have the same problem of wrong usage with RenderTexture->newImage(). I read your ( vision) explanation about wrapping -

,but I’m not quite sure what would “wrapping the read/write frame buffer operations with commands” practically mean, and more importantly for me, I’m not quite sure what to what or how to replace the “->newImage()” code with.
like in the following code with ( the same example zroobavela gave serves as a good example for me)

help would be greatly appreciated!

2 Likes

Bump!

Hey guys, I am constructing the background image (using RenderTexture) of a scene at first load. My idea is to put that rendered Sprite/image to some cache (TextureCache?) so that on 2nd load of the same scene, that background is already in memory. Now, I fail to get newImage() from RenderTexture just like you say above. What is the correct way of doing this?

Can we cache a sprite another way? SpriteFrameCache? I haven’t found a working way yet… Any help appreciated.

I’m using cocos2d v3.9.

Sprite *someSprite = Sprite::create("1.png");
RenderTexture *render = RenderTexture::create(someSprite->getTexture()->getPixelsWide(), someSprite->getTexture()->getPixelsHigh());
render->beginWithClear(1, 1, 1, 1);
someSprite->setAnchorPoint(Vec2(0, 0));
someSprite->visit();
render->end();
auto sprite = Sprite::create();
sprite->initWithTexture(render->getSprite()->getTexture());
sprite->setAnchorPoint(Vec2(0.5, 0.5));
sprite->setFlippedY(true);
sprite->setPosition(320, 480);
//addChild(sprite); /// ------------------- //works well, I got sprite image

However, I need this code work as designed, but it’s failed, I got just black / no image!

Image *testImage = render->newImage();
unsigned char *data = testImage->getData();

It seems this error was not fixed yet?
Also here same problem cocos2dx 3.3 newImage() problem black image

@ricardo @slackmoehrle @nite

Opened issue: https://github.com/cocos2d/cocos2d-x/issues/14861

I had same issue.
Try this:

Sprite *someSprite = Sprite::create(“1.png”);
RenderTexture *render = RenderTexture::create(someSprite->getTexture()->getPixelsWide(), someSprite->getTexture()->getPixelsHigh());
render->begin();
someSprite->setAnchorPoint(Vec2(0, 0));
someSprite->visit();
render->end();

//You need to force render to make it visible and if not, screen will be black
Director::getInstance()->getRenderer()->render();

2 Likes

In my case I had problem:

OpenGL error 0x0506 in /Users/jenkins/Public/jenkins/workspace/CCS-AutoBuild-Mono_3.5/label/mac02/cocos2dx/cocos/renderer/CCTexture2D.cpp initWithMipmaps 648

I solved this issue.
The problem occurs when one of the side of texture pixel size is more than 4096. Maybe framebuffer has a such limit.
When you use 4097 everything is black. 4096 is fine.

Wow, thank you very much… just making the transition from Cocos2D-X 2.x, and this was getting on my nerves :stuck_out_tongue: