DLR-RM / BlenderProc

A procedural Blender pipeline for photorealistic training image generation
GNU General Public License v3.0
2.82k stars 451 forks source link

Function bproc.object.sample_poses() seems not to work with child objects #1064

Open ErikDerGute opened 9 months ago

ErikDerGute commented 9 months ago

Describe the issue

Hello guys,

i would like to use the bproc.object.sample_poses() function to arrange my objects without collisions to run the physics simulation afterwards. When ich use my "default" objects everything works fine. As soon as i add to an object a child object an error occurs. Some models for example are in the .zip archive, because git don't support .blend files.

The error:

Could not place Cube without a collision. Error: Python: Traceback (most recent call last): File "/Users/eriktzschoppe/Documents/Masterarbeit/datengenerierung/pipeline.py", line 104, in bp.object.sample_poses(instrument_model, sample_pose_func=sample_pose) File "/Users/eriktzschoppe/BlenderProc/blenderproc/python/object/ObjectPoseSampler.py", line 76, in sample_poses no_collision = CollisionUtility.check_intersections(obj, bvh_cache, cur_objects_to_check_collisions, []) File "/Users/eriktzschoppe/BlenderProc/blenderproc/python/utility/CollisionUtility.py", line 50, in check_intersections intersection, bvh_cache = CollisionUtility.check_mesh_intersection(obj, collision_obj, File "/Users/eriktzschoppe/BlenderProc/blenderproc/python/utility/CollisionUtility.py", line 162, in check_mesh_intersection inter = CollisionUtility.is_point_inside_object(obj1, obj1_BVHtree, File "/Users/eriktzschoppe/BlenderProc/blenderproc/python/utility/CollisionUtility.py", line 199, in is_point_inside_object p2 = nearest - point AttributeError: Vector subtraction: (NoneType - Vector) invalid type for this operation

Thanks!

Minimal code example

import blenderproc as bp
import numpy as np
import bpy
import os

bp.init()

def load_blender_files_from_path(data_path):
    instruments = []
    file_name = []

    for name in os.listdir(data_path):

        if name.endswith(".blend"):
            file_name.append(os.path.join(data_path, name)) 

    for i in range(len(file_name)):
        objs = file_name[i]
        tmp = bp.loader.load_blend(objs, obj_types=['MESH'])

        checker = False
        for parts in tmp:
            if 'part' in parts.get_name():
                checker = True 
        print(checker)
        if checker is True:
            for counter, parts in enumerate(tmp):
                if 'part' in parts.get_name():
                    tmp_move_part = counter
                elif 'part' and 'kp' not in parts.get_name():
                    tmp_rigid_part = counter
                if 'nadel_halter' in parts.get_name():
                    max_rotation = 15
                else:
                    max_rotation = 55
            rotation = 30 #np.random.uniform(0, max_rotation, 1)

            tmp[tmp_move_part].set_rotation_euler([0, 0, np.deg2rad(rotation)])
            # get all parent objects
            key_points = tmp[tmp_move_part].get_children()
            for key_point in key_points:
                # set new parent to rigid part
                key_point.set_parent(tmp[tmp_rigid_part])
            tmp[tmp_rigid_part].join_with_other_objects([tmp[tmp_move_part]])

            instruments.extend([tmp[tmp_rigid_part]])
        else:
            for counter, parts in enumerate(tmp):
                if 'kp' not in parts.get_name():
                    adult_id = counter
            key_points = tmp[adult_id].get_children()
            for key_point in key_points:
                key_point.set_parent(tmp[adult_id])
            instruments.extend([tmp[adult_id]])

    return instruments

def sample_pose(obj: bp.types.MeshObject):
    obj.set_location(np.random.uniform([-0.05, -0.05, 0], [0.05, 0.05, 0]))
    obj.set_rotation_euler(bp.sampler.uniformSO3())

instrument_model = load_blender_files_from_path(data_path)

bp.object.sample_poses(instrument_model, sample_pose_func=sample_pose)

Files required to run the code

Archiv.zip

Expected behavior

Place the objects without collision.

BlenderProc version

2.7.0

ErikDerGute commented 9 months ago

Edit: Maybe I forgot to mention that also with the param "objects_to_check_collisions" set to the child objects it doesn't work.

tsrobcvai commented 7 months ago

I also met this problem. Hi, have you figured out the solution? Thanks!

ErikDerGute commented 7 months ago

Hi, unfortunately not really, but there's a quick and dirty workaround. As the child objects are paired to the corresponding parent object, there is no need to set the location separately. My workaround was to simply skip the child objects inside the function. In my case I know the names of my child objects, so is just customized the function like:

    for obj in objects_to_sample:
        if 'kp' in obj.get_name():
            continue
        # Store the obejct's initial pose in case we need to place it back
        if mode_on_failure == 'initial_pose':
            initial_location = obj.get_location()
            initial_rotation = obj.get_rotation_euler()

in ObjectPoseSample.py line 54. If you don't know your child object names, it should also be possible to do something like: if obj is "child object" -> continue. Hope this is useful for you.

cornerfarmer commented 7 months ago

Hey @ErikDerGute,

I think the main problem at least with the example you gave in your initial post is that you are using objects with no volume (the circle) which are not supported by blenders collision check. If the circle should not take part in the collision checks at all, then I recommend to remove it from the objects_to_sample and also the objects_to_check_collisions parameter.

ErikDerGute commented 7 months ago

Thanks for your reply. As I said in my previous edit I removed the child objects from the objects_to_check_collisions and also only sample the parent objects. Maybe I did something wrong back then. Regardless of this it's not a problem for me anymore.