-
Notifications
You must be signed in to change notification settings - Fork 60
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
AssimpImporter: import skin data #99
Conversation
as multiple sets of custom attributes "JOINTS_i" and "WEIGHTS_i"
Todo:
|
@@ -287,9 +296,6 @@ verbosity levels in each instance. | |||
- Custom mesh attributes (such as `object_id` in Stanford PLY files) are | |||
not imported. | |||
- Texture coordinate layers with other than two components are skipped | |||
- For some file formats (such as COLLADA), Assimp may create a dummy | |||
"skeleton visualizer" mesh if the file has no mesh data. For others (such | |||
as glTF) not. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is fixed by setting AI_CONFIG_IMPORT_NO_SKELETON_MESHES
, but there's another comment down below in the Scene import section ("[...] there's sometimes just a single root node") which I'm not sure about. The node collapsing doesn't happen anymore with this setting (the test got adapted accordingly), but I wonder if this is the only circumstance where this happens.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See my comment here.
/* Skinned mesh imported into Blender and then exported */ | ||
|
||
// TODO attribution: | ||
// https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_019_SimpleSkin.md |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where would I best put attribution here? The tutorials are licensed under CC-BY 4.0 so anything allowed as long as we credit the author and add a link to the license. I'm afraid recreating a skinned mesh with Blender is a bit out of my depth.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is that where the skin.gltf
is from? Looks rather different, did you re-export with Blender? The test files from TinyGltfImporter could not be reused?
In any case, attribution should go here, something like
diff --git a/src/MagnumPlugins/AssimpImporter/AssimpImporter.h b/src/MagnumPlugins/AssimpImporter/AssimpImporter.h
index 0da7c4c3..2d03fa5c 100644
--- a/src/MagnumPlugins/AssimpImporter/AssimpImporter.h
+++ b/src/MagnumPlugins/AssimpImporter/AssimpImporter.h
@@ -128,7 +128,11 @@ This plugin provides `3dsImporter`, `Ac3dImporter`, `BlenderImporter`,
licensed under @m_class{m-label m-success} **BSD 3-clause**
([license text](http://assimp.org/index.php/license),
[choosealicense.com](https://choosealicense.com/licenses/bsd-3-clause/)).
- It requires attribution for public use.
+ It requires attribution for public use. The tests use a file from the
+ [A Simple Skin](https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_019_SimpleSkin.md)
+ glTF tutorial, licensed under @m_class{m-label m-success} **CC-BY 4.0**
+ ([license text](https://github.com/KhronosGroup/glTF-Tutorials/blob/master/LICENSE),
+ [choosealicense.com](https://choosealicense.com/licenses/cc-by-4.0/)).
@section Trade-AssimpImporter-usage Usage
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it's re-exported from Blender, mainly because I needed an extra un-skinned mesh in the scene. The original TinyGltfImporter skin test files can't be used with Assimp because they have no meshes. Assimp only exposes bones through meshes, so no meshes = no bones. Main reason I imported and re-exported that tutorial file is that it has accompanying joint weights, making it fairly simple to test both skins and vertex attributes with the same file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mosra turns out the original file is from the glTF 2 sample repo, licensed under CC0. Do I still mention it in that case? It's not used verbatim, if that makes any difference.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that's needed, no.
There is a known test failure with one glTF file, but the CIs with old Assimp versions skip that. They still report failure with 0 failed tests, is that because of the warning about some tests not containing any checks? |
/* Without this setting, Assimp adds bogus skeleton visualization meshes | ||
to files that don't have any meshes. It claims to only do this when | ||
there is animation data, but at least for Collada it always does it. */ | ||
importer->SetPropertyBool(AI_CONFIG_IMPORT_NO_SKELETON_MESHES, true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note to self: this should probably go into the "Potential compatibility breakages" section in the changelog.
} | ||
Containers::Pointer<ObjectData3D> parent = importer->object3D(0); | ||
CORRADE_COMPARE(parent->children(), {1}); | ||
CORRADE_COMPARE(parent->instanceType(), ObjectInstanceType3D::Empty); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ummm ... I don't understand why is there such a weird interaction with IMPORT_NO_SKELETON_MESHES
?
IIRC the original intent of this test was to verify that collapsing the whole file into a single node works, i.e. testing corner cases of this block of code (and the COLLADA/skeleton-related comment there is probably outdated now?).
I think in this case the expected behavior was that the importer skips the useless extra added root node and returns only its child, but I have no idea why it's no longer being done -- it should be.
The "only a single node" case in the code happens for PLY files for example (or some of the glTF files), but seems like the test doesn't explicitly verify that. I'll add a test case to check that code path.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment in the test suggested it was Assimp doing the collapsing internally so I simply adapted the test. But if it tests some importer code then it might need some more scrutiny. I'm not entirely sure what's happening either, but I can do some more debugging.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mildly related question: what are bone nodes?
/** @todo support for bone nodes */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's an outdated comment -- nodes associated with a skin. Basically what's provided by SkinData
now, I suppose this TODO expected the reference would go the other way around. Remove :)
Assimp doing the collapsing internally so I simply adapted the test.
IIRC Assimp does the collapsing internally if you enable PreTransformVertices, but still adds a silly empty root node with an identity transformation that the importer plugin then attempts to remove.
Yes, that's why :) |
Thanks for taking the time to look at this on a Sunday, very much appreciated |
based on the value of maxJointWeights
and patch joint id mesh attributes
Functionality is all there, I just need to finish a few tests... Meanwhile, enjoy some animated, skinned Mixamo characters imported from FBX files into Wonderland Engine 👯 |
… enabled and test it
Bigger struggle than anticipated, but everything should be tested now, including:
For the last one I had to do some I took another look at Assimp code to understand the |
I'll look into it during the merge. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Your code looks fine. I still need to check it out, build and run locally... and look into that scene collapsing behavior.
The Windows builds fail because of this, which I define for the Windows Assimp builds. So... I guess I should enable export functionality for these binaries? Another option would be to rewrite that test as a glTF file instead of building it up using Assimp's own APIs, I could attempt that.
Containers::Optional<SkinData3D> AssimpImporter::doSkin3D(const UnsignedInt id) { | ||
/* Import either a single mesh skin or all of them together. | ||
Since Assimp gives us no way to enumerate the original skins | ||
and assumes that one mesh = one skins, we give the users |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and assumes that one mesh = one skins, we give the users | |
and assumes that one mesh = one skin, we give the users |
This is the only remaining issue I found by looking at the code :)
Wow, goddamit. So the node collapsing worked before exactly because the After patching |
That's probably the better option because you don't have to deal with Assimp itself in the tests. I painfully edited an existing Collada file for the multiple weight attributes test, but constructing glTF buffers actually seems easier (and might uncover yet-unknown glTF Assimp bugs... I'm really suspicious I haven't hit any in the basic |
I managed to fix the Windows CI issue by using the underlying C++ APIs instead of the C wrappers, not sure why there's a difference. (Of course it's never simple, so I'm now testing a workaround workaround that negates the workaround for version 3.2... and funnily enough both "copy" calls leak memory!). One last question, about the "ignore dummy joint weights" commit -- there doesn't seem to be any difference in the test output whether the code is there or not, and looking at https://github.com/assimp/assimp/blob/1d33131e902ff3f6b571ee3964c666698a99eb0f/code/AssetLib/glTF2/glTF2Importer.cpp#L1099 it seems this happens only when the glTF looks like this "skins": [
{
"joints": []
}
], which is invalid according to the spec. So I wouldn't even bother adding a special case, and if Assimp crashes on such a file it's ... not our problem :) |
I didn't look into it all that deeply, but I ran across it when testing this file exported from Blender: What happens is that the dummy weights lead to overflow in
I suppose the correct (and slow) way to fix this would be to store everything in a map but that completely garbles the joint order (which Assimp sorts by weight, if it has to reduce the bone count in the postprocess step). Ignoring all zero-weights is another option but that has a funny aftertaste to me. |
If I'm reading Assimp's code correctly, the dummy weights are added to all joints in the skin that aren't influencing any vertex in the mesh, which is entirely possible. Should I try to create a small test with a custom file for this? |
Ah, you're right, I misread the code. I tried to craft a file by reducing If you're able to do that, that'd be great. Another thing is the leak inside |
Assimp only imports the last(!!) set of glTF vertex weights
Sweet Jesus! I think I found the dumbest Assimp bug yet. I was checking if it correctly imports multiple sets of joint weights (what I originally wanted to do with the file linked earlier, but then forgot because it caused the bug with dummy weights), and not to much suprise, it doesn't. Now comes the best part: it doesn't even import the first set of weights... The parsing code is so abysmal, they look for I added a check that finds non-normalized weights in glTF files and prints a warning (+ accompanying test), but there isn't much else we can do. Now for better news: adding the other test was fairly simple, so the dummy weight removal has a proper test that fails if you remove the checks. For some reason Github doesn't show the commits in the main PR view, but they're there in the Commits tab. Together with #100 this should hopefully be the victory lap for this PR 🙏 |
Thanks! Will get back to this hopefully this evening, now I have to work on other things ;) |
Almost done putting everything together. Thanks to #100 it doesn't leak anymore, but the newly added test for dummy weights had an error in the
TOP NOTCH error recovery right there. Very secure. Much hardening. I'll just pretend I didn't see anything. 🔥 |
I squashed the major part into a single commit, with the fun and exciting new bug/misfeature discoveries kept as a separate commits, and merged as faa16d4...d62d58c. Thanks a lot for having the perserverance to work on this 😅 |
Thanks for cleaning up the debris, I didn't realize there was so much work left to merge 🙏 |
This PR adds support for importing skins as well as joint weight mesh attributes with AssimpImporter.
doSkin3D
imports skins (joint node ids + corresponding inverse bind matrices) for each mesh with skin data. Assimp doesn't expose any of the original (possibly multi-mesh) skins and instead copies joint data into each mesh, duplicating bones if necessary. The newmergeSkins
option is meant to allow users to merge all skins in the scene into one, removing duplicate joints and adjusting mesh attributes.doMesh
imports joint ids and weights as custom mesh attributes (built-in support for those is WIP in mosra/magnum#441) named "JOINTS" and "WEIGHTS". Multiple sets (4 weights per set) of these are imported as layers of the same custom mesh attribute id. This allows more than 4 weights per vertex but requires changing the newmaxJointWeights
option (default:4
).This is very much WIP, but I pushed my current progress so you can intervene early if anything is completely off-track 😄
Commissioned by Wonderland.