0
$\begingroup$

I want to simulate and visualize some situation, there are many people walking inside a big room, with walls and doors. I simply model each person as a ball or a cylinder, and write python code to move it. the question is, how can I make the model (ball or cylinder) not going through the walls and each other? that is, they can have physics collision. I have set the feature of rigid body, active and passive, etc, not work. some suggest is using force, but it is difficult to control. have tried BGE/UPBGE, it is ok for one ball, but I do not know how to generate many balls which can "walk" by themselves.

snapshot, wall is passive rigid body snapshot, wall is passive rigid body

snapshot, ball is active rigid body snapshot, ball is active rigid body the ball will fall, but not move video captured

if set animation, as this:if set animation, as this then the ball will move, but it will not fall, and not stop at the wall (pass through):video captured

$\endgroup$
2
  • $\begingroup$ can you maybe post a screen recording of your problem? That might help us help you figure out your problem better. $\endgroup$
    – Jakemoyo
    Commented Apr 22, 2022 at 11:03
  • $\begingroup$ I think Blender is not a good tool for making such simulations. Unity, as an example, has ready to use nav mesh systems with collision detection. youtube.com/watch?v=atCOd4o7tG4 $\endgroup$
    – Crantisz
    Commented Apr 22, 2022 at 14:37

1 Answer 1

1
$\begingroup$

enter image description here

You can run the script to get scene

import bpy
from mathutils import Vector

# select and delete all object
if bpy.context.object:
    bpy.ops.object.mode_set(mode='OBJECT')
    bpy.ops.object.select_all(action = "SELECT")
    bpy.ops.object.delete(use_global=True, confirm=False)

unit_settings = bpy.context.scene.unit_settings
unit_settings.system            = 'METRIC'
unit_settings.scale_length      = 1
unit_settings.length_unit       = 'METERS'
unit_settings.mass_unit         = 'KILOGRAMS'
unit_settings.time_unit         = 'SECONDS'
bpy.context.scene.use_gravity   = True
bpy.context.scene.gravity[0]    = 0
bpy.context.scene.gravity[1]    = 0
bpy.context.scene.gravity[2]    = -9.81
bpy.context.scene.render.fps    = 60
bpy.context.scene.frame_set(1)

bpy.ops.mesh.primitive_plane_add(size=5, enter_editmode=False, align='WORLD', location=(0, 0, 0), scale=(1, 1, 1))
bpy.context.object.name = "floor"
bpy.ops.rigidbody.object_add()
bpy.context.object.rigid_body.type = 'PASSIVE'
bpy.context.object.rigid_body.collision_shape = 'BOX'
bpy.context.object.rigid_body.friction = 0.02
bpy.context.object.rigid_body.restitution = 0.9

bpy.ops.mesh.primitive_cube_add(size=5, enter_editmode=False, align='WORLD', location=(5, 0, 0), scale=(1, 1, 1))
bpy.context.object.name = "wall_0"
bpy.ops.rigidbody.object_add()
bpy.context.object.rigid_body.type = 'PASSIVE'
bpy.context.object.rigid_body.collision_shape = 'BOX'
bpy.context.object.rigid_body.friction = 0.02
bpy.context.object.rigid_body.restitution = 0.9

bpy.ops.mesh.primitive_cube_add(size=5, enter_editmode=False, align='WORLD', location=(-5, 0, 0), scale=(1, 1, 1))
bpy.context.object.name = "wall_1"
bpy.ops.rigidbody.object_add()
bpy.context.object.rigid_body.type = 'PASSIVE'
bpy.context.object.rigid_body.collision_shape = 'BOX'
bpy.context.object.rigid_body.friction = 0.02
bpy.context.object.rigid_body.restitution = 0.9

bpy.ops.mesh.primitive_cube_add(size=5, enter_editmode=False, align='WORLD', location=(0, 5, 0), scale=(1, 1, 1))
bpy.context.object.name = "wall_2"
bpy.ops.rigidbody.object_add()
bpy.context.object.rigid_body.type = 'PASSIVE'
bpy.context.object.rigid_body.collision_shape = 'BOX'
bpy.context.object.rigid_body.friction = 0.02
bpy.context.object.rigid_body.restitution = 0.9

x = -1
balls = []
for r in range(10):
    bpy.ops.mesh.primitive_uv_sphere_add(radius=0.1, enter_editmode=False, align='WORLD', location=(x, 0, 0.101), scale=(1, 1, 1))
    bpy.context.object.name = f"ball_{r}"
    bpy.ops.object.shade_smooth()
    bpy.ops.rigidbody.object_add()
    oj = bpy.context.object
    balls.append(oj)
    oj.rigid_body.type = 'ACTIVE'
    oj.rigid_body.kinematic = True
    oj.rigid_body.collision_shape = 'MESH'
    bpy.context.object.rigid_body.collision_margin = 0.001
    bpy.context.object.rigid_body.friction = 0.02
    bpy.context.object.rigid_body.restitution = 0.9
    bpy.ops.rigidbody.mass_calculate(material='Iron', density=7874)
    oj.keyframe_insert(data_path="location", frame=1)
    oj.keyframe_insert(data_path="rigid_body.kinematic", frame=1)
    oj["control_by_rigid_body"] = False
    x += 0.2

def inside_room(x, y):
    if -2.3 < x < 2.3:
        if -2.5 < y < 2.3: return True
    return False


speed = 0.05
v = [
    Vector((-1.0, 0.0)).normalized() * speed,
    Vector((-0.9, 0.2)).normalized() * speed,
    Vector((-0.8, 0.4)).normalized() * speed,
    Vector((-0.6, 0.6)).normalized() * speed,
    Vector((-0.4, 0.7)).normalized() * speed,
    Vector((-0.1, 1.0)).normalized() * speed,
    Vector((0.1, 1.0)).normalized() * speed,
    Vector((0.3, 0.8)).normalized() * speed,
    Vector((0.5, 0.5)).normalized() * speed,
    Vector((1.0, 0.0)).normalized() * speed,
]


for r in range(2, 121):
    # bpy.context.scene.frame_set(r)
    for i, b in enumerate(balls):
        if b["control_by_rigid_body"] == False:
            b.location[0] += v[i][0]
            b.location[1] += v[i][1]
            if inside_room(b.location[0], b.location[1]):
                b.keyframe_insert(data_path="location", frame=r)
            else:
                b.rigid_body.kinematic = False
                b.keyframe_insert(data_path="rigid_body.kinematic", frame=r)
                b["control_by_rigid_body"] = True

To do this, first you need to know when to hit the wall. In my case, if location[0] of the ball > 2.4 will hit the right side (depends on the wall position).
if near the wall, keyframe the "rigid_body.kinematic". Then control by the Rigid Body.

enter image description here

$\endgroup$
3
  • $\begingroup$ thanks for detail demo. it is helpful. however, your basic idea is to make collision (between ball and wall) by code. which could be done by blender itself? for example, there are different walls for different case... $\endgroup$
    – Franson Wu
    Commented Apr 24, 2022 at 8:37
  • $\begingroup$ In blender, the common way to do collision simulation is keyframe the object, see what time will collision. And then keyframe the (is Animated). I think there is not exist a convenient method to do that today in blender unlike some game engine. $\endgroup$
    – X Y
    Commented Apr 24, 2022 at 9:43
  • $\begingroup$ when you free control the object (keyframe the object position). It cannot do the physic simulation. Otherwise, it break the laws of Physics. $\endgroup$
    – X Y
    Commented Apr 24, 2022 at 9:53

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .