Thank you a ton @NiunioMartinez for the precise bugreport and then for analysis from @DiggiDoggi . You both made my work easy ![]()
In short: fixed in the latest engine version! ![]()
As usual, the downloads will contain the fix after it passes a few automatic tests. You can observe this page, when it will no longer show the commit “Handle glTF files containing multiple equivalent skins…” then the fix is part of the downloads.
Details, if you’re curious what / how / why:
-
The limitation on the CGE side (only partially “lifted” now), causing this, is that we cannot have 1 joint affected by 2 different skins. And this is what these models use, as investigation from @DiggiDoggi shows – 2 skins, and their “joints” list are equal. They actually share the whole “skeleton” which equals to “root joint” in our terminology.
While in principle our Skin node could express such joint usage (using DEF/USE to refer to the same skeleton root from 2 skins), our logic is not ready for this yet. But it’s possible to be solved one day in a general way in our engine, please report if you encounter the need for this “in the wild”, i.e. on models you want to use.
Our previous approach with “precalculation” (as you mentioned it worked in early 2025) indeed allowed this, by precalculating all animations without much of the assumptions.
E.g. this testcase will not work correctly with latest CGE: glTF-Sample-Assets/Models/RecursiveSkeletons at main · KhronosGroup/glTF-Sample-Assets · GitHub
( To be clear, you can have multiple skins, they just need to work on different joints and shapes. And you can have multiple shapes (so multiple geometries) in one skin. The problem only starts if multiple skins try to operate on same joints. )
-
There was a talk at glTF whether such models should be allowed, see here for all the details and discussion that I followed to some extent: Stricter Skinning Requirements · Issue #1665 · KhronosGroup/glTF · GitHub
In the end, the more flexible / complicated approach remains possible in glTF.
To make it easier for some importers, there was a plan for an “extension” called
KHR_skin_strictthat when used, declares that glTF model actually confirms to a stricter version of spec (so it relies only on a subset of features), in particular “A joint node must belong only to a single skin”. See KHR_skin_strict by donmccurdy · Pull Request #1747 · KhronosGroup/glTF · GitHub for discussion and the proposed extension text on KHR_skin_strict by donmccurdy · Pull Request #1747 · KhronosGroup/glTF · GitHub . This was proposed in 2020, so I’m not sure if there’s hope it will be really available one day, but the GitHub issues remain open. -
The 2 GitHub issues linked above contain claims that other game engines also don’t support complicated skins (see e.g. statement “No game engine supports binding a mesh to multiple skins. If an exporter wants to do this, it needs to join both skeletons.”). So, I believe Castle Game Engine is not alone in this limitation… but I didn’t check in practice how does it look. Information in this thread suggests that Unity and Unreal support it at least to some extent (maybe using a similar hack to only support specific cases, like we just did, read on
). -
What did we do now?
First of all, this cannot be random (the “moon phases” you mentioned were caused by an undefined order when iterating over
TObjectDictionary, used during glTF skins loading), And it cannot just hide some model part. At the very least, we should reject an extra skin information with clear warning “sorry, not supported” and at least show remaining shapes as non-animated.You will see for such cases a warning like
Warning: glTF: Skeleton "Group" is a root of more than one skin (named: "" and ""). This is not supported (see KHR_skin_strict discussion).And only the shapes from one skin will animate (but all shapes will be visible). It’s better than it was. -
For this specific case, we can do more, since actually the 2 skins are exactly the same. They use the same joints with the same “inverse bind matrices”. We can just put all affected shapes in one skin, and we’re good.
No warning will be shown in this case and everything just works out-of-the-box.
Disclosure: Claude Code suggested a workaround along the lines of 2nd commit, thought in the end I threw it away and made my own more efficient and robust version. So, I’m still useful:) but Claude’s guess wasn’t that terrible either.
Have fun making games!
