-
-
Notifications
You must be signed in to change notification settings - Fork 22.8k
GLTF: MultiMeshInstance3D import #107866
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
base: master
Are you sure you want to change the base?
GLTF: MultiMeshInstance3D import #107866
Conversation
Please set up pre-commit hooks locally to ensure style correctness so you don't run CI needlessly to fix style |
less aggressive line separation
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.
Looks good overall. Just needs some changes to where the node conversion happens.
The conversion from ImporterMeshInstance3D to MultiMeshInstance3D should also be performed in GLTFDocumentExtensionConvertImporterMesh (modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.cpp
). That is where the translation from an ImporterMesh* node into the corresponding MeshInstance3D (or in this case, MultiMeshInstance3D) is happens in runtime import.
Finally, I'd love to see export code also added either here or in a future PR, so when a user exports a scene with a MultiMeshInstance3D, it creates the accessors and everything. I can't ask you to volunteer more of your time, but having the export logic would make round-trip testing much easier (import -> export -> import). For export, it would need a setting added to the export dialog whether to use the extension (required / optional / disabled), or use the current code which converts it to a normal gltf nodes.
if (Object::cast_to<ImporterMeshInstance3D>(p_node)) { | ||
ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(p_node); | ||
|
||
if (mi->get_multimesh().is_valid()) { |
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 converting the node type too early. This code should be moved into ResourceImporterScene::_generate_meshes()
. It should become an if/else statement that creates a MultiMeshInstance3D if mi->get_multimesh().is_valid()
and a normal MeshInstance3D otherwise.
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.
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.
If current is more correct, however, it ideally should display its mesh info.
edit: displayed this anyway, for multimeshes created by potential user extensions.
@@ -49,6 +49,9 @@ class GLTFNode : public Resource { | |||
GLTFCameraIndex camera = -1; | |||
GLTFSkinIndex skin = -1; | |||
GLTFSkeletonIndex skeleton = -1; | |||
int multimesh_translation = -1; | |||
int multimesh_rotation = -1; | |||
int multimesh_scale = -1; |
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 should be done with an extension, instead of adding properties to GLTFNode.
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.
Does that mean i have to create new GLTFDocumentExtension subclass for parsing(and maybe processing extension's things), or just to use has/get/set_additional_data() in GLTFDocument instead of accessing those fields?
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.
A new GLTFDocumentExtension subclass, which uses the additional data functions. However, this isn't currently possible to do in a safe way with accessors. I've been working on refactoring these to support this, and opened PRs #108302 and #108320 so far, with more still to come... sorry to still ask you to wait longer.
return nullptr; | ||
} | ||
Ref<GLTFBufferView> buffer_view = p_state->buffer_views[accessor->buffer_view]; | ||
translation_ptr = (Vector3 *)(p_state->buffers[buffer_view->get_buffer()].ptr() + buffer_view->get_byte_offset()); |
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 isn't a safe usage of accessors, and will fail for many many cases. However, currently we don't expose APIs for using accessors safely. Coincidentally, I was planning on working on that as my next PR very soon. I know this is unfortunate to hear, but I'm going to ask you to please wait a few weeks.
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.
Sure, i can wait. It is actually less blocker for my workflow than option to enable extension itself.
What exactly those unsafe cases? Can buffer in accessor be not aligned with its description? Or is it about pointer generally not being safe, for threading and similar things?
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.
For example, this will fail if the accessor primitive isn't float32, and will fail if Godot is compiled with doubles.
Is GLTFDocumentExtensionConvertImporterMesh meant to do main conversion and code in _generate_meshes - whatever multimeshes been created by user extensions?
I might try to look export, since i've got some time for that(but probably after main fixes) |
Allows to import MultiMeshInstance3D objects through EXT_mesh_gpu_instancing GLTF extension: https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Vendor/EXT_mesh_gpu_instancing/README.md
Depends on #107672 for blender. Will work by itself for pure GLTF files(if exporter option enabled)
Implementation notes:
Adds 3 fields to GLTFNode - multimesh_translation, multimesh_rotation, multimesh_scale. All of this is referencing accessors indices in Gltf document.
Adds ImporterMeshInstance3D::multimesh. It is created and filled in GLTFDocument::_generate_mesh_instance - nearby ImporterMeshInstance3D creation.
(I am not sure about that decision - almost every resource parsed/created separately from nodes(and assigned later), but instances info stored in node description and not in json's root, so maybe its ok)
Actual MultiMeshInstance3D creation happens in ResourceImporterScene::_pre_fix_node - nearby other nodes creation(and suffix parsing)
Currenly there is no condition to create MultiMeshInstance3D - it just checks whether it has or not valid multimesh.
I think ideally there should be suffix condition, OR at least code should check other conditions first - like col/colonly - whatever might be more important to have.
(for that reason MultiMeshInstance3D is not created early in GLTFDocument)(there is also some mesh material manipulation which duplication we might want to avoid)
Suffixes might be tricky, however - blender will set name of instance node based on name of main node - not on the name of children node in editor.
to trigger multimesh creation, code need at least one of three accessors. Since blender creates all of them, i only tested that case.
On import there is some warnings like "Instance count must be 0 to change the transform format". I think it is related more to copying MultimeshInstance3D and/or scene creation, than to creation code itself.
There is also some work on GDScript properties and docs left(if rest is even desirable implementation)