axmolengine / axmol

Axmol Engine – A Multi-platform Engine for Desktop, XBOX (UWP) and Mobile games. (A fork of Cocos2d-x-4.0)
https://axmol.dev
MIT License
923 stars 205 forks source link

Strange issue with RenderTexture when using PVR format #1059

Closed rh101 closed 1 year ago

rh101 commented 1 year ago

Using a simple program drawing a semi-transparent Glow.png image with Sprite::create() over a solid LayerColor or solid sprite, this should be the output:

Image A (correct output - note the solid black under the glow) image

If I use PVR format for the file (such as pvr.gz or pvr.ccz sprite sheet), and load with Sprite::createWithFrameName(), this is what happens:

Image B (incorrect output - note that you can see the yellow box and background under the glow) image

For some reason, the semi-transparent glow alpha section is blending in with the solid black and making it transparent, when it should be more like image A above.

Has anyone experienced this with PVR files? Using standalone PNG or PNG sprite sheets is perfectly fine, but PVR files are causing a problem. The PVR sprite sheet output was created with TexturePacker with the following settings:

image

At the moment I have absolutely no idea why it would be blending it in such a way. The code is just this (modifications to template cpp project):

bool HelloWorld::init()
{
    if (!Scene::init())
    {
        return false;
    }

    auto visibleSize = _director->getVisibleSize();
    auto origin      = _director->getVisibleOrigin();
    auto safeArea    = _director->getSafeAreaRect();
    auto safeOrigin  = safeArea.origin;
    auto closeItem = MenuItemImage::create("CloseNormal.png", "CloseSelected.png",
                                           AX_CALLBACK_1(HelloWorld::menuCloseCallback, this));

    if (closeItem == nullptr || closeItem->getContentSize().width <= 0 || closeItem->getContentSize().height <= 0)
    {
        problemLoading("'CloseNormal.png' and 'CloseSelected.png'");
    }
    else
    {
        float x = safeOrigin.x + safeArea.size.width - closeItem->getContentSize().width / 2;
        float y = safeOrigin.y + closeItem->getContentSize().height / 2;
        closeItem->setPosition(Vec2(x, y));
    }

    auto menu = Menu::create(closeItem, NULL);
    menu->setPosition(Vec2::ZERO);
    this->addChild(menu, 1);

    // Load PVR.gz sprite sheet here:
    SpriteFrameCache::getInstance()->addSpriteFramesWithFile("TestSheet.plist");

    auto* layer = LayerColor::create(Color4B::GREEN, visibleSize.width, visibleSize.height);
    addChild(layer, 0);

    auto* layerColor = LayerColor::create(Color4B::YELLOW, 200, 200);
    layerColor->setIgnoreAnchorPointForPosition(false);
    layerColor->setPosition(visibleSize.width / 2 + 400, visibleSize.height / 2);
    addChild(layerColor, 5);

    scheduleOnce([this, visibleSize](float) {
            auto* testRenderTexture = MakeTestRenderTexture();
        auto* sprite = testRenderTexture->getSprite();
        sprite->setAnchorPoint(Vec2::ANCHOR_MIDDLE);
        sprite->setPosition(visibleSize / 2);
        addChild(testRenderTexture, 10);
        }, 0.0, "RT_TEST");

    return true; 
}

RenderTexture* HelloWorld::MakeTestRenderTexture()
{
    auto* background = LayerColor::create(Color4B::BLACK, 764, 926);
    background->setAnchorPoint(Vec2::ANCHOR_MIDDLE);
    background->setPositionNormalized(Vec2(0.5f, 0.5f));
    background->setIgnoreAnchorPointForPosition(false);

    auto* glowOverlay = Sprite::createWithSpriteFrameName("Glow.png");
    glowOverlay->setPositionNormalized(Vec2(0.5f, 0.5f));
    glowOverlay->setAnchorPoint(Vec2::ANCHOR_MIDDLE);

    auto&& totalSize = glowOverlay->getContentSize();
    auto* baseNode = Node::create();
    baseNode->setContentSize(totalSize);
    baseNode->setAnchorPoint(Vec2::ANCHOR_MIDDLE);
    baseNode->setIgnoreAnchorPointForPosition(false);
    baseNode->setPosition(totalSize / 2);

    baseNode->addChild(background, 1);
    baseNode->addChild(glowOverlay, 10);

    auto* rt = RenderTexture::create(static_cast<int>(totalSize.width), static_cast<int>(totalSize.height), PixelFormat::RGBA8, PixelFormat::D24S8);
    rt->beginWithClear(0, 0, 0, 255);
    baseNode->visit();
    rt->end();

    return rt;
}
halx99 commented 1 year ago

Do you check premultiplyAlpha when convert png to .pvr?

rh101 commented 1 year ago

Do you check premultiplyAlpha when convert png to .pvr?

Good catch! The Texture Packer CLI script that processes all the graphics has ClearTransparentPixels set for transparency handling, but changing it over to PremultiplyAlpha fixed the issue! That script was created years ago, and I've never noticed this specific problem before from it, which is why I didn't even think to check it.

Thank you very much!