From 766b6da21a0da75271cec8031721f68cd580efd3 Mon Sep 17 00:00:00 2001 From: kubric-team Date: Wed, 27 Nov 2024 23:07:37 +0000 Subject: [PATCH 1/8] Adds the ability to use parenting instead of joining when loading GLB. NOTE: Intentionally left out "glb_" prefix to option as this could eventually be applied to other filetypes on load, for example, USD. PiperOrigin-RevId: 700816151 --- kubric/core/objects.py | 7 ++++ kubric/renderer/blender.py | 71 +++++++++++++++++++++++++------------- 2 files changed, 54 insertions(+), 24 deletions(-) diff --git a/kubric/core/objects.py b/kubric/core/objects.py index cd06f665..0e8c229e 100644 --- a/kubric/core/objects.py +++ b/kubric/core/objects.py @@ -284,4 +284,11 @@ class FileBasedObject(PhysicalObject): # UI, minus a 90 degree X-axis rotation applied after loading. glb_do_transform_apply_after_import = tl.Bool(False) + # If true, uses a parenting approach instead of a join so that the asset + # represents a top-level Empty node in the scene. All existing objects + # without parents will be parented to this object. Any transform applied to + # this object will be applied to all children. For more details, see + # https://docs.blender.org/manual/en/latest/scene_layout/object/editing/parent.html + use_parenting_instead_of_join = tl.Bool(False) + # TODO: trigger error when changing filenames or asset-id after the fact diff --git a/kubric/renderer/blender.py b/kubric/renderer/blender.py index 0d9df4b7..a0240baa 100644 --- a/kubric/renderer/blender.py +++ b/kubric/renderer/blender.py @@ -36,6 +36,17 @@ logger = logging.getLogger(__name__) +def add_top_level_empty_parent() -> Any: + """Adds an empty parent to scene and makes it the parent of all objects.""" + parent_obj = bpy.data.objects.new("Empty", None) + parent_obj.rotation_mode = "QUATERNION" + bpy.context.scene.collection.objects.link(parent_obj) + for obj in bpy.context.scene.objects: + if obj != parent_obj and obj.parent is None: + obj.parent = parent_obj + return parent_obj + + # noinspection PyUnresolvedReferences class Blender(core.View): """ An implementation of a rendering backend in Blender/Cycles.""" @@ -422,29 +433,40 @@ def _add_asset(self, obj: core.FileBasedObject): location=True, rotation=True, scale=True ) - # gltf files often contain "Empty" objects as placeholders for camera / lights etc. - # here we are interested only in the meshes, we filter these out and join all meshes into one. - mesh = [m for m in bpy.context.selected_objects if m.type == "MESH"] - assert mesh - for ob in mesh: - ob.select_set(state=True) - bpy.context.view_layer.objects.active = ob - - # make sure one of the objects is active, otherwise join() fails. - # see https://blender.stackexchange.com/questions/132266/joining-all-meshes-in-any-context-gets-error - bpy.context.view_layer.objects.active = mesh[0] - bpy.ops.object.join() - - # Make sure to delete all remaining non-mesh objects. Note that for - # some reason deleting the non-mesh objets before joining removes - # parts of the meshes in some cases. - non_mesh_objects = [ - obj - for obj in bpy.context.selected_objects - if obj.type != "MESH" - ] - with bpy.context.temp_override(selected_objects=non_mesh_objects): - bpy.ops.object.delete() + if obj.use_parenting_instead_of_join: + parent_obj = add_top_level_empty_parent() + bpy.ops.object.select_all(action="DESELECT") + parent_obj.select_set(state=True) + else: + # Legacy loader which relies on JOIN. NOTE: This will destroy + # things like animations. + # gltf files often contain "Empty" objects as placeholders for + # camera / lights etc. + # here we are interested only in the meshes, we filter these out + # and join all meshes into one. + mesh = [ + m for m in bpy.context.selected_objects if m.type == "MESH" + ] + assert mesh + for ob in mesh: + ob.select_set(state=True) + bpy.context.view_layer.objects.active = ob + + # make sure one of the objects is active, otherwise join() fails. + # see https://blender.stackexchange.com/questions/132266/joining-all-meshes-in-any-context-gets-error + bpy.context.view_layer.objects.active = mesh[0] + bpy.ops.object.join() + + # Make sure to delete all remaining non-mesh objects. Note that + # for some reason deleting the non-mesh objets before joining + # removes parts of the meshes in some cases. + non_mesh_objects = [ + obj + for obj in bpy.context.selected_objects + if obj.type != "MESH" + ] + with bpy.context.temp_override(selected_objects=non_mesh_objects): + bpy.ops.object.delete() assert len(bpy.context.selected_objects) == 1 blender_obj = bpy.context.selected_objects[0] @@ -473,7 +495,8 @@ def _add_asset(self, obj: core.FileBasedObject): # deactivate auto_smooth because for some reason it lead to no smoothing at all # TODO: make smoothing configurable - blender_obj.data.use_auto_smooth = False + if hasattr(blender_obj.data, "use_auto_smooth"): + blender_obj.data.use_auto_smooth = False register_object3d_setters(obj, blender_obj) obj.observe(AttributeSetter(blender_obj, "active_material", From 971fedcedf1e0a2dad8e0d6e95a5f71fa4c19f81 Mon Sep 17 00:00:00 2001 From: Matthew Prasad Burruss Date: Thu, 28 Nov 2024 22:59:55 -0500 Subject: [PATCH 2/8] Update objects.py --- kubric/core/objects.py | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/kubric/core/objects.py b/kubric/core/objects.py index 0e8c229e..7064b4d3 100644 --- a/kubric/core/objects.py +++ b/kubric/core/objects.py @@ -1,17 +1,3 @@ -# Copyright 2024 The Kubric Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - """Kubric objects.""" import itertools @@ -289,6 +275,15 @@ class FileBasedObject(PhysicalObject): # without parents will be parented to this object. Any transform applied to # this object will be applied to all children. For more details, see # https://docs.blender.org/manual/en/latest/scene_layout/object/editing/parent.html + # + # Parenting avoids destroying things like animations and can preven + # accidental deletion of objects from the scene. + # + # This will break certain features of kubric like assigning meterials to + # assets or other functions that expect the asset to be a mesh. Also + # when used with PyBullet for simulations, the non-animated collision mesh is + # used which can lead to unexpected behavior when an animated object is used + # in a physics simulation. use_parenting_instead_of_join = tl.Bool(False) # TODO: trigger error when changing filenames or asset-id after the fact From 9e9dd14f0edc8d04b799bcf350481bd6f1ad00f7 Mon Sep 17 00:00:00 2001 From: Matthew Prasad Burruss Date: Thu, 28 Nov 2024 23:01:18 -0500 Subject: [PATCH 3/8] Update blender.py --- kubric/renderer/blender.py | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/kubric/renderer/blender.py b/kubric/renderer/blender.py index a0240baa..b53b76aa 100644 --- a/kubric/renderer/blender.py +++ b/kubric/renderer/blender.py @@ -1,17 +1,3 @@ -# Copyright 2024 The Kubric Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - import collections from contextlib import redirect_stdout import functools @@ -36,9 +22,16 @@ logger = logging.getLogger(__name__) -def add_top_level_empty_parent() -> Any: - """Adds an empty parent to scene and makes it the parent of all objects.""" - parent_obj = bpy.data.objects.new("Empty", None) +def add_top_level_empty_parent(name: str = "Empty") -> bpy.types.Object: + """Adds an empty parent to scene and makes it the parent of all objects. + + Args: + name: The name of the empty parent. + + Returns: + The newly created empty parent. + """ + parent_obj = bpy.data.objects.new(name, None) parent_obj.rotation_mode = "QUATERNION" bpy.context.scene.collection.objects.link(parent_obj) for obj in bpy.context.scene.objects: @@ -434,7 +427,7 @@ def _add_asset(self, obj: core.FileBasedObject): ) if obj.use_parenting_instead_of_join: - parent_obj = add_top_level_empty_parent() + parent_obj = add_top_level_empty_parent(obj.uid) bpy.ops.object.select_all(action="DESELECT") parent_obj.select_set(state=True) else: From 635a9025e80c35c1e313bb50ad5ef6ebf0c7150d Mon Sep 17 00:00:00 2001 From: Matthew Prasad Burruss Date: Thu, 28 Nov 2024 23:02:11 -0500 Subject: [PATCH 4/8] Adds licenses back to blender.py --- kubric/renderer/blender.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/kubric/renderer/blender.py b/kubric/renderer/blender.py index b53b76aa..deaf4354 100644 --- a/kubric/renderer/blender.py +++ b/kubric/renderer/blender.py @@ -1,3 +1,16 @@ +# Copyright 2024 The Kubric Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. import collections from contextlib import redirect_stdout import functools From f830c93cebac37d84e0c64e8f038161f23f43200 Mon Sep 17 00:00:00 2001 From: Matthew Prasad Burruss Date: Thu, 28 Nov 2024 23:03:22 -0500 Subject: [PATCH 5/8] Adds licenses back to objects.py --- kubric/core/objects.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/kubric/core/objects.py b/kubric/core/objects.py index 7064b4d3..2149e8ee 100644 --- a/kubric/core/objects.py +++ b/kubric/core/objects.py @@ -1,3 +1,16 @@ +# Copyright 2024 The Kubric Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. """Kubric objects.""" import itertools From 02a612f0dbfaae429aae21c53ac37be5c75b61a2 Mon Sep 17 00:00:00 2001 From: Matthew Prasad Burruss Date: Thu, 28 Nov 2024 23:03:39 -0500 Subject: [PATCH 6/8] Adds newline to objects --- kubric/core/objects.py | 1 + 1 file changed, 1 insertion(+) diff --git a/kubric/core/objects.py b/kubric/core/objects.py index 2149e8ee..49015f5c 100644 --- a/kubric/core/objects.py +++ b/kubric/core/objects.py @@ -11,6 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. + """Kubric objects.""" import itertools From 2b5e32f3bbbf9f3e2c1a605c4c7ac0edc45a25d2 Mon Sep 17 00:00:00 2001 From: Matthew Prasad Burruss Date: Thu, 28 Nov 2024 23:11:06 -0500 Subject: [PATCH 7/8] Update objects.py comment --- kubric/core/objects.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/kubric/core/objects.py b/kubric/core/objects.py index 49015f5c..d47993e3 100644 --- a/kubric/core/objects.py +++ b/kubric/core/objects.py @@ -294,10 +294,12 @@ class FileBasedObject(PhysicalObject): # accidental deletion of objects from the scene. # # This will break certain features of kubric like assigning meterials to - # assets or other functions that expect the asset to be a mesh. Also - # when used with PyBullet for simulations, the non-animated collision mesh is - # used which can lead to unexpected behavior when an animated object is used - # in a physics simulation. + # assets or other functions that expect the asset to be a mesh. For + # example, when assigning segmentation_ids you may want to reconstruct + # kb.Asset recursively on the top-level empty and set the `segmentation_id`. + # Also when used with PyBullet for simulations, the non-animated collision + # mesh is used which can lead to unexpected behavior when an animated object + # is used in a physics simulation. use_parenting_instead_of_join = tl.Bool(False) # TODO: trigger error when changing filenames or asset-id after the fact From d9b547e7ae396ce6f128e9f7544f7469203f068d Mon Sep 17 00:00:00 2001 From: Matthew Prasad Burruss Date: Thu, 28 Nov 2024 23:16:21 -0500 Subject: [PATCH 8/8] Remove space --- kubric/renderer/blender.py | 1 + 1 file changed, 1 insertion(+) diff --git a/kubric/renderer/blender.py b/kubric/renderer/blender.py index deaf4354..b3d53f14 100644 --- a/kubric/renderer/blender.py +++ b/kubric/renderer/blender.py @@ -11,6 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. + import collections from contextlib import redirect_stdout import functools