Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[cocos2dx] Two-color tinted skeletons do not render on the first frame #2501

Closed
badlogic opened this issue Apr 16, 2024 · 8 comments
Closed
Assignees
Labels

Comments

@badlogic
Copy link
Collaborator

See repro steps here:
https://esotericsoftware.com/forum/d/25903-cocos2d-x-c-crash-after-re-exporting-with-spine-41/9

@TyelorD
Copy link

TyelorD commented Apr 29, 2024

Some more info about this bug:

While two-color tinting is enabled, it causes visual artifacts on the skeleton on the frames just before/after going to a new animation. I never set animation mixing for any of these animations however, and Cocos2d-x defaults the mixing to 0.0f, at least it did in v3.17.2 (so I don't think these visual artifacts are related to any animation mixing, especially since turning off two-color tinting fixes these artifacts).

It also seems to make any skeleton atlases that were exported with premultiplied alphas enabled to render with artifacts on the edges of the symbols: as if the premultiplied alpha was being applied twice. But neither changing the GL mode to BlendFunc::ALPHA_NON_PREMULTIPLIED and/or calling SkeletonRenderer::setOpacityModifyRGB(false) on the Skeleton with the premultiplied alphas in it's Atlas changed this behavior. It's worth noting however that disabling Image::PNG_PREMULTIPLIED_ALPHA_ENABLED does cause the Skeleton to render properly and without artifacts, but it also breaks every other PNG image used.

@badlogic
Copy link
Collaborator Author

Two-color tinting is implemented with a custom batcher (SkeletonTwoColorBatch.cpp) which submits custom commands (TwoColorTrianglesCommand) to the Cocos2d-x renderer.

Following the repro steps for the RaptorExample, I've confirmed that on the first frame, the SkeletonRenderer actually submits render commands to the batcher, which submits them to the Cocos2d-x Renderer, which you can see here:

Screenshot 2024-04-30 at 11 27 57

This happens in CCRenderer.cpp:371. These submitted commands are ultimately processed in Renderer::processRenderCommand()

Screenshot 2024-04-30 at 11 34 57

I can also confirm that the commands are submitted to the GPU:

Screenshot 2024-04-30 at 11 38 35

In subsequent frames, the exact same code paths are executed, but result in the commands actually being rendered.

Another indicator that we do everything correctly is that in our example, the Cocos2d-x backend reports the number of vertices and draw calls correctly for the first frame, despite nothing being rendered.

Screenshot 2024-04-30 at 11 56 39

The second issue you described might well be a "follow-on" error from the original issue that causes the first frame not to be drawn.

I'm afraid I have no idea how this can be. On our end, we are not doing anything different between the first and subsequent frames. My guess is that this is a bug in Cocos2d-x with regards to custom rendering commands. As such, we might have to loop in the Cocos2d-X folks. (or fork maintainers) to fix this. I'm afraid I'm not familiar enough with Cocos2d-X internals to fix this myself.

So, ultimately, this needs to be passed to whoever is now maintaining Cocos2d-X (or a fork). I'm afraid on our end there is not much we can do, other than recommend to not use the two-color tinting renderer.

@TyelorD
Copy link

TyelorD commented Apr 30, 2024

So, ultimately, this needs to be passed to whoever is now maintaining Cocos2d-X (or a fork). I'm afraid on our end there is not much we can do, other than recommend to not use the two-color tinting renderer.

Unfortunately Cocos2d-x has quietly dropped all maintenance and support for that engine back in 2019, so there is 0 chance of a fix ever making it to the main branch there. However I did let the folks at Axmol know: hopefully they will be able to fix the issue since they are much more knowledgeable about the inner workings of Axmol than I am.

We were using Cocos2d-x v3.17.2 until recently, so I'm not yet familiar with the changes made to the renderer logic in Cocos2d-x v4.0 (and thus also Axmol). Hopefully it ends up being a relatively simple fix, though I wasn't able to fix it after trying and experimenting for a day and a half. That said I was mostly playing around with the Spine runtimes, and not the rendering/triangle commands like you suggest.

@TyelorD
Copy link

TyelorD commented May 1, 2024

So for anyone experiencing this issue, rh101 over on the Axmol fork was able to fix this issue with the following changes:

In SkeletonRenderer.cpp, around line 461, find this section of code for the two color tint:

} else {
   TwoColorTrianglesCommand *batchedTriangles = lastTwoColorTrianglesCommand = twoColorBatch->addCommand(renderer, _globalZOrder, texture, _programState, blendFunc, trianglesTwoColor, transform, transformFlags);

    V3F_C4B_C4B_T2F *vertex = batchedTriangles->getTriangles().verts;
    for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v, ++vertex) {
        vertex->color = color4B;
        vertex->color2 = darkColor4B;
    }
}

Change it to this:

} else {
    V3F_C4B_C4B_T2F* vertex = trianglesTwoColor.verts;
    for (int v = 0, vn = trianglesTwoColor.vertCount; v < vn; ++v, ++vertex)
    {
        vertex->color  = color4B;
        vertex->color2 = darkColor4B;
    }
    lastTwoColorTrianglesCommand = twoColorBatch->addCommand(renderer, _globalZOrder, texture, _programState, blendFunc, trianglesTwoColor, transform, transformFlags);
}

Hopefully this might be useful for folks who are still using Cocos2d-x v4.0, even if they need to manually implement this change; this change will most likely be pulled into the main branch for Axmol soon.

Thanks for taking the time to look into this issue badlogic, cheers!

@badlogic badlogic reopened this May 1, 2024
@badlogic
Copy link
Collaborator Author

badlogic commented May 1, 2024 via email

@badlogic
Copy link
Collaborator Author

badlogic commented May 2, 2024

This has been fixed in the 4.2 branch. Note that this fix also handles clipping, which the change suggested by rh101 does not.

Is there a reason Axmol ships their own spine-cocos2d-x runtimes? We'd prefer if people used our official runtime, which lowers the burden on Axmol maintainers and prevents issues in the runtime fork being reported as an issue of the official runtime (should they diverge).

@rh101
Copy link
Contributor

rh101 commented May 2, 2024

This has been fixed in the 4.2 branch. Note that this fix also handles clipping, which the change suggested by rh101 does not.

The Axmol versions of the runtimes (here) do have the clipping section handled too, along with the non-two tint sections, although they probably aren't required since the vertex data isn't set the same way as the two tint render command. The Axmol Spine runtimes for 3.6, 3.7, 3.8, 4.0 and 4.1 have all been updated with the fix for this issue.

Is there a reason Axmol ships their own spine-cocos2d-x runtimes?

Axmol and Cocos2d-x have diverged, and while they are mostly compatible, to use the same runtime for both would probably require a lot of preprocessor conditionals, but that's really up to you.

@badlogic
Copy link
Collaborator Author

badlogic commented May 2, 2024 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

No branches or pull requests

3 participants