From a394b58d83b3aaa688ecc91939f9c148b4101f91 Mon Sep 17 00:00:00 2001 From: Julien Duroure Date: Thu, 25 Jun 2026 15:32:28 +0200 Subject: [PATCH] Remove one level when exporting instance collection Currently, we export instance collection => Collection => Objects with the collection and the Collection is not needed to be exported Now, we export instance collection => Objects within the collection --- addons/io_scene_gltf2/blender/exp/tree.py | 32 +++++++++++++++-------- tests/test/test.js | 4 +-- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/addons/io_scene_gltf2/blender/exp/tree.py b/addons/io_scene_gltf2/blender/exp/tree.py index 46eab2b70..5d57c32bd 100644 --- a/addons/io_scene_gltf2/blender/exp/tree.py +++ b/addons/io_scene_gltf2/blender/exp/tree.py @@ -216,9 +216,10 @@ def recursive_node_traverse( if parent_uuid is not None: self.add_children(parent_uuid, node.uuid) - # 2 cases where we will need to store the fact that children are in collection or a real children + # 3 cases where we will need to store the fact that children are in collection or a real children # 1. GN instance # 2. Old Dupli vertices feature + # 3. Instance collection # For any other case, children are real children if (self.nodes[parent_uuid].blender_type == VExportNode.INST_COLLECTION or original_object is not None) or (self.nodes[parent_uuid].blender_type != VExportNode.COLLECTION and self.nodes[parent_uuid].blender_object is not None and self.nodes[parent_uuid].blender_object.is_instancer is True): @@ -414,19 +415,28 @@ def recursive_node_traverse( is_collection=True) else: # Manage children objects - self.recursive_node_traverse( - blender_object.instance_collection, - None, - node.uuid, - node.matrix_world, - new_delta or delta, - blender_children, - is_collection=True, - is_children_in_collection=True) + # Do not loop on children of the instance collection, + # But on the children of the collection itself + + ref_collection = blender_object.instance_collection + collection_objects = set(ref_collection.objects) + for child in _sort_by_name(collection_objects): + # On Collection, .objects returns all objects & instance collection + # Not only the direct children + + # Keep only object if it has no parent, or parent is not in the collection + if child.parent is not None and len(child.parent.users_collection) > 0 \ + and len(child.users_collection) > 0 \ + and child.users_collection[0].name == child.parent.users_collection[0].name: + continue + + self.recursive_node_traverse(child, None, node.uuid, node.matrix_world, + new_delta or delta, blender_children, is_children_in_collection=True) + # Some objects are parented to instance collection for child in _sort_by_name(blender_children[blender_object]): self.recursive_node_traverse(child, None, node.uuid, parent_coll_matrix_world, - new_delta or delta, blender_children, is_children_in_collection=True) + new_delta or delta, blender_children) # Manage children collections for child in _sort_by_name(blender_object.instance_collection.children): self.recursive_node_traverse( diff --git a/tests/test/test.js b/tests/test/test.js index 55e08059a..5acd6c11e 100644 --- a/tests/test/test.js +++ b/tests/test/test.js @@ -284,14 +284,14 @@ describe('Exporter', function () { let gltfPath = path.resolve(outDirPath, '01_linked_collection.gltf'); const asset = JSON.parse(fs.readFileSync(gltfPath)); - assert.strictEqual(asset.nodes.length, 4); + assert.strictEqual(asset.nodes.length, 3); }); it('can export all collection instances', function () { let gltfPath = path.resolve(outDirPath, '01_multiple_collection_instances.gltf'); const asset = JSON.parse(fs.readFileSync(gltfPath)); - assert.strictEqual(asset.nodes.length, 9); + assert.strictEqual(asset.nodes.length, 7); }); it('can export a base color', function () {