Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/rigidbody.c
| Show First 20 Lines • Show All 992 Lines • ▼ Show 20 Lines | |||||
| /* set default settings */ | /* set default settings */ | ||||
| rbw->effector_weights = BKE_effector_add_weights(NULL); | rbw->effector_weights = BKE_effector_add_weights(NULL); | ||||
| rbw->ltime = PSFRA; | rbw->ltime = PSFRA; | ||||
| rbw->time_scale = 1.0f; | rbw->time_scale = 1.0f; | ||||
| rbw->steps_per_second = 60; /* Bullet default (60 Hz) */ | /* Most high quality Bullet example files has an internal framerate of 240hz. | ||||
| * The blender default scene has a frame rate of 24, so take 10 substeps (24fps * 10). | |||||
| */ | |||||
| rbw->substeps_per_frame = 10; | |||||
| rbw->num_solver_iterations = 10; /* 10 is bullet default */ | rbw->num_solver_iterations = 10; /* 10 is bullet default */ | ||||
| rbw->shared->pointcache = BKE_ptcache_add(&(rbw->shared->ptcaches)); | rbw->shared->pointcache = BKE_ptcache_add(&(rbw->shared->ptcaches)); | ||||
| rbw->shared->pointcache->step = 1; | rbw->shared->pointcache->step = 1; | ||||
| /* return this sim world */ | /* return this sim world */ | ||||
| return rbw; | return rbw; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 454 Lines • ▼ Show 20 Lines | |||||
| /* update object array in case there are changes */ | /* update object array in case there are changes */ | ||||
| rigidbody_update_ob_array(rbw); | rigidbody_update_ob_array(rbw); | ||||
| } | } | ||||
| static void rigidbody_update_sim_ob( | static void rigidbody_update_sim_ob( | ||||
| Depsgraph *depsgraph, Scene *scene, RigidBodyWorld *rbw, Object *ob, RigidBodyOb *rbo) | Depsgraph *depsgraph, Scene *scene, RigidBodyWorld *rbw, Object *ob, RigidBodyOb *rbo) | ||||
| { | { | ||||
| float loc[3]; | |||||
| float rot[4]; | |||||
| float scale[3]; | |||||
| /* only update if rigid body exists */ | /* only update if rigid body exists */ | ||||
| if (rbo->shared->physics_object == NULL) { | if (rbo->shared->physics_object == NULL) { | ||||
| return; | return; | ||||
| } | } | ||||
| ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph); | ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph); | ||||
| Base *base = BKE_view_layer_base_find(view_layer, ob); | Base *base = BKE_view_layer_base_find(view_layer, ob); | ||||
| const bool is_selected = base ? (base->flag & BASE_SELECTED) != 0 : false; | const bool is_selected = base ? (base->flag & BASE_SELECTED) != 0 : false; | ||||
| Show All 9 Lines | |||||
| (float *)mvert, | (float *)mvert, | ||||
| totvert, | totvert, | ||||
| sizeof(MVert), | sizeof(MVert), | ||||
| bb->vec[0], | bb->vec[0], | ||||
| bb->vec[6]); | bb->vec[6]); | ||||
| } | } | ||||
| } | } | ||||
| mat4_decompose(loc, rot, scale, ob->obmat); | float scale[3]; | ||||
| mat4_to_size(scale, ob->obmat); | |||||
zeddb: Reminder: Only do this check at this point for non kinematic objects! | |||||
| /* update scale for all objects */ | /* update scale for all objects */ | ||||
| RB_body_set_scale(rbo->shared->physics_object, scale); | RB_body_set_scale(rbo->shared->physics_object, scale); | ||||
| /* compensate for embedded convex hull collision margin */ | /* compensate for embedded convex hull collision margin */ | ||||
| if (!(rbo->flag & RBO_FLAG_USE_MARGIN) && rbo->shape == RB_SHAPE_CONVEXH) { | if (!(rbo->flag & RBO_FLAG_USE_MARGIN) && rbo->shape == RB_SHAPE_CONVEXH) { | ||||
| RB_shape_set_margin(rbo->shared->physics_shape, | RB_shape_set_margin(rbo->shared->physics_shape, | ||||
| RBO_GET_MARGIN(rbo) * MIN3(scale[0], scale[1], scale[2])); | RBO_GET_MARGIN(rbo) * MIN3(scale[0], scale[1], scale[2])); | ||||
| } | } | ||||
| /* Make transformed objects temporarily kinmatic | /* Make transformed objects temporarily kinmatic | ||||
| * so that they can be moved by the user during simulation. */ | * so that they can be moved by the user during simulation. */ | ||||
| if (is_selected && (G.moving & G_TRANSFORM_OBJ)) { | if (is_selected && (G.moving & G_TRANSFORM_OBJ)) { | ||||
| RB_body_set_kinematic_state(rbo->shared->physics_object, true); | RB_body_set_kinematic_state(rbo->shared->physics_object, true); | ||||
| RB_body_set_mass(rbo->shared->physics_object, 0.0f); | RB_body_set_mass(rbo->shared->physics_object, 0.0f); | ||||
| } | } | ||||
| /* update rigid body location and rotation for kinematic bodies */ | |||||
| if (rbo->flag & RBO_FLAG_KINEMATIC || (is_selected && (G.moving & G_TRANSFORM_OBJ))) { | |||||
| RB_body_activate(rbo->shared->physics_object); | |||||
| RB_body_set_loc_rot(rbo->shared->physics_object, loc, rot); | |||||
| } | |||||
| /* update influence of effectors - but don't do it on an effector */ | /* update influence of effectors - but don't do it on an effector */ | ||||
| /* only dynamic bodies need effector update */ | /* only dynamic bodies need effector update */ | ||||
| else if (rbo->type == RBO_TYPE_ACTIVE && | else if (rbo->type == RBO_TYPE_ACTIVE && | ||||
| ((ob->pd == NULL) || (ob->pd->forcefield == PFIELD_NULL))) { | ((ob->pd == NULL) || (ob->pd->forcefield == PFIELD_NULL))) { | ||||
| EffectorWeights *effector_weights = rbw->effector_weights; | EffectorWeights *effector_weights = rbw->effector_weights; | ||||
| EffectedPoint epoint; | EffectedPoint epoint; | ||||
| ListBase *effectors; | ListBase *effectors; | ||||
| ▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | |||||
| * | * | ||||
| * \param rebuild: Rebuild entire simulation | * \param rebuild: Rebuild entire simulation | ||||
| */ | */ | ||||
| static void rigidbody_update_simulation(Depsgraph *depsgraph, | static void rigidbody_update_simulation(Depsgraph *depsgraph, | ||||
| Scene *scene, | Scene *scene, | ||||
| RigidBodyWorld *rbw, | RigidBodyWorld *rbw, | ||||
| bool rebuild) | bool rebuild) | ||||
| { | { | ||||
| float ctime = DEG_get_ctime(depsgraph); | |||||
| /* update world */ | /* update world */ | ||||
| /* Note physics_world can get NULL when undoing the deletion of the last object in it (see | /* Note physics_world can get NULL when undoing the deletion of the last object in it (see | ||||
| * T70667). */ | * T70667). */ | ||||
| if (rebuild || rbw->shared->physics_world == NULL) { | if (rebuild || rbw->shared->physics_world == NULL) { | ||||
| BKE_rigidbody_validate_sim_world(scene, rbw, rebuild); | BKE_rigidbody_validate_sim_world(scene, rbw, rebuild); | ||||
| } | } | ||||
| rigidbody_update_sim_world(scene, rbw); | rigidbody_update_sim_world(scene, rbw); | ||||
| Show All 16 Lines | |||||
| FOREACH_COLLECTION_OBJECT_RECURSIVE_END; | FOREACH_COLLECTION_OBJECT_RECURSIVE_END; | ||||
| } | } | ||||
| /* update objects */ | /* update objects */ | ||||
| FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->group, ob) { | FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->group, ob) { | ||||
| if (ob->type == OB_MESH) { | if (ob->type == OB_MESH) { | ||||
| /* validate that we've got valid object set up here... */ | /* validate that we've got valid object set up here... */ | ||||
| RigidBodyOb *rbo = ob->rigidbody_object; | RigidBodyOb *rbo = ob->rigidbody_object; | ||||
| /* Update transformation matrix of the object | |||||
| * so we don't get a frame of lag for simple animations. */ | |||||
| BKE_object_where_is_calc_time(depsgraph, scene, ob, ctime); | |||||
| /* TODO remove this whole block once we are sure we never get NULL rbo here anymore. */ | /* TODO remove this whole block once we are sure we never get NULL rbo here anymore. */ | ||||
| /* This cannot be done in CoW evaluation context anymore... */ | /* This cannot be done in CoW evaluation context anymore... */ | ||||
| if (rbo == NULL) { | if (rbo == NULL) { | ||||
| BLI_assert(!"CoW object part of RBW object collection without RB object data, " | BLI_assert(!"CoW object part of RBW object collection without RB object data, " | ||||
| "should not happen.\n"); | "should not happen.\n"); | ||||
| /* Since this object is included in the sim group but doesn't have | /* Since this object is included in the sim group but doesn't have | ||||
| * rigid body settings (perhaps it was added manually), add! | * rigid body settings (perhaps it was added manually), add! | ||||
| ▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | |||||
| /* update constraints */ | /* update constraints */ | ||||
| if (rbw->constraints == NULL) { /* no constraints, move on */ | if (rbw->constraints == NULL) { /* no constraints, move on */ | ||||
| return; | return; | ||||
| } | } | ||||
| FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->constraints, ob) { | FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->constraints, ob) { | ||||
| /* validate that we've got valid object set up here... */ | /* validate that we've got valid object set up here... */ | ||||
| RigidBodyCon *rbc = ob->rigidbody_constraint; | RigidBodyCon *rbc = ob->rigidbody_constraint; | ||||
| /* Update transformation matrix of the object | |||||
| * so we don't get a frame of lag for simple animations. */ | |||||
| BKE_object_where_is_calc_time(depsgraph, scene, ob, ctime); | |||||
| /* TODO remove this whole block once we are sure we never get NULL rbo here anymore. */ | /* TODO remove this whole block once we are sure we never get NULL rbo here anymore. */ | ||||
| /* This cannot be done in CoW evaluation context anymore... */ | /* This cannot be done in CoW evaluation context anymore... */ | ||||
| if (rbc == NULL) { | if (rbc == NULL) { | ||||
| BLI_assert(!"CoW object part of RBW constraints collection without RB constraint data, " | BLI_assert(!"CoW object part of RBW constraints collection without RB constraint data, " | ||||
| "should not happen.\n"); | "should not happen.\n"); | ||||
| /* Since this object is included in the group but doesn't have | /* Since this object is included in the group but doesn't have | ||||
| * constraint settings (perhaps it was added manually), add! | * constraint settings (perhaps it was added manually), add! | ||||
| Show All 13 Lines | |||||
| rigidbody_validate_sim_constraint(rbw, ob, false); | rigidbody_validate_sim_constraint(rbw, ob, false); | ||||
| } | } | ||||
| } | } | ||||
| rbc->flag &= ~RBC_FLAG_NEEDS_VALIDATE; | rbc->flag &= ~RBC_FLAG_NEEDS_VALIDATE; | ||||
| } | } | ||||
| FOREACH_COLLECTION_OBJECT_RECURSIVE_END; | FOREACH_COLLECTION_OBJECT_RECURSIVE_END; | ||||
| } | } | ||||
| typedef struct kinematic_substep_data { | |||||
| void *physics_object; | |||||
| float old_pos[3]; | |||||
| float new_pos[3]; | |||||
| float old_rot[4]; | |||||
| float new_rot[4]; | |||||
Done Inline ActionsIs there a reason scale is not interpolated for substeps, while position and rotation are? brecht: Is there a reason scale is not interpolated for substeps, while position and rotation are? | |||||
| } kinematic_substep_data; | |||||
| static ListBase rigidbody_create_substep_data(RigidBodyWorld *rbw) | |||||
| { | |||||
| /* Objects that we want to update substep location/rotation for. */ | |||||
| ListBase substep_targets = {NULL, NULL}; | |||||
| FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->group, ob) { | |||||
| RigidBodyOb *rbo = ob->rigidbody_object; | |||||
| /* only update if rigid body exists */ | |||||
| if (!rbo || rbo->shared->physics_object == NULL) { | |||||
| continue; | |||||
| } | |||||
| if (rbo->flag & RBO_FLAG_KINEMATIC) { | |||||
| float loc[3], rot[4]; | |||||
| kinematic_substep_data *data = MEM_callocN(sizeof(kinematic_substep_data), | |||||
| "RigidBody Substep data"); | |||||
| data->physics_object = rbo->shared->physics_object; | |||||
| RB_body_get_position(rbo->shared->physics_object, loc); | |||||
| RB_body_get_orientation(rbo->shared->physics_object, rot); | |||||
| copy_v3_v3(data->old_pos, loc); | |||||
| copy_v4_v4(data->old_rot, rot); | |||||
| mat4_to_loc_quat(loc, rot, ob->obmat); | |||||
| copy_v3_v3(data->new_pos, loc); | |||||
| copy_v4_v4(data->new_rot, rot); | |||||
| LinkData *ob_link = BLI_genericNodeN(data); | |||||
| BLI_addtail(&substep_targets, ob_link); | |||||
| } | |||||
| } | |||||
| FOREACH_COLLECTION_OBJECT_RECURSIVE_END; | |||||
| return substep_targets; | |||||
| } | |||||
| static void rigidbody_update_kinematic_obj_substep(ListBase *substep_targets, float interp_fac) | |||||
| { | |||||
| for (LinkData *data_link = substep_targets->first; data_link != NULL; | |||||
Done Inline ActionsLISTBASE_FOREACH JacquesLucke: `LISTBASE_FOREACH` | |||||
| data_link = data_link->next) { | |||||
| kinematic_substep_data *data = data_link->data; | |||||
Done Inline Actionssnake case JacquesLucke: snake case | |||||
| float loc[3], rot[4]; | |||||
| interp_v3_v3v3(loc, data->old_pos, data->new_pos, interp_fac); | |||||
| interp_qt_qtqt(rot, data->old_rot, data->new_rot, interp_fac); | |||||
| RB_body_activate(data->physics_object); | |||||
| RB_body_set_loc_rot(data->physics_object, loc, rot); | |||||
| } | |||||
| } | |||||
| static void rigidbody_free_substep_data(ListBase *substep_targets) | |||||
| { | |||||
| for (LinkData *data_link = substep_targets->first; data_link != NULL; | |||||
| data_link = data_link->next) { | |||||
| kinematic_substep_data *data = data_link->data; | |||||
| MEM_freeN(data); | |||||
| } | |||||
| BLI_freelistN(substep_targets); | |||||
| } | |||||
| static void rigidbody_update_simulation_post_step(Depsgraph *depsgraph, RigidBodyWorld *rbw) | static void rigidbody_update_simulation_post_step(Depsgraph *depsgraph, RigidBodyWorld *rbw) | ||||
| { | { | ||||
| ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph); | ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph); | ||||
| FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->group, ob) { | FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->group, ob) { | ||||
| Base *base = BKE_view_layer_base_find(view_layer, ob); | Base *base = BKE_view_layer_base_find(view_layer, ob); | ||||
| RigidBodyOb *rbo = ob->rigidbody_object; | RigidBodyOb *rbo = ob->rigidbody_object; | ||||
| /* Reset kinematic state for transformed objects. */ | /* Reset kinematic state for transformed objects. */ | ||||
| ▲ Show 20 Lines • Show All 218 Lines • ▼ Show 20 Lines | |||||
| /* write cache for first frame when on second frame */ | /* write cache for first frame when on second frame */ | ||||
| if (rbw->ltime == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact == 0)) { | if (rbw->ltime == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact == 0)) { | ||||
| BKE_ptcache_write(&pid, startframe); | BKE_ptcache_write(&pid, startframe); | ||||
| } | } | ||||
| /* update and validate simulation */ | /* update and validate simulation */ | ||||
| rigidbody_update_simulation(depsgraph, scene, rbw, false); | rigidbody_update_simulation(depsgraph, scene, rbw, false); | ||||
| float frame_diff = ctime - rbw->ltime; | |||||
| /* calculate how much time elapsed since last step in seconds */ | /* calculate how much time elapsed since last step in seconds */ | ||||
| timestep = 1.0f / (float)FPS * (ctime - rbw->ltime) * rbw->time_scale; | timestep = 1.0f / (float)FPS * frame_diff * rbw->time_scale; | ||||
| /* Step simulation by the requested timestep, | /* Step simulation by the requested timestep, | ||||
| * steps per second are adjusted to take time scale into account. */ | * steps per second are adjusted to take time scale into account. */ | ||||
JacquesLuckeUnsubmitted Done Inline Actionsprobably outdated comment JacquesLucke: probably outdated comment | |||||
| RB_dworld_step_simulation(rbw->shared->physics_world, | |||||
| timestep, | float substep = timestep / rbw->substeps_per_frame; | ||||
| INT_MAX, | |||||
Done Inline Actionsconst JacquesLucke: `const` | |||||
| 1.0f / (float)rbw->steps_per_second * min_ff(rbw->time_scale, 1.0f)); | ListBase substep_targets = rigidbody_create_substep_data(rbw); | ||||
| float interp_step = 1.0f / rbw->substeps_per_frame; | |||||
| float cur_interp_val = interp_step; | |||||
| for (int i = 0; i < rbw->substeps_per_frame; i++) { | |||||
| rigidbody_update_kinematic_obj_substep(&substep_targets, cur_interp_val); | |||||
| RB_dworld_step_simulation(rbw->shared->physics_world, substep, 0, substep); | |||||
| cur_interp_val += interp_step; | |||||
| } | |||||
| rigidbody_free_substep_data(&substep_targets); | |||||
| rigidbody_update_simulation_post_step(depsgraph, rbw); | rigidbody_update_simulation_post_step(depsgraph, rbw); | ||||
| /* write cache for current frame */ | /* write cache for current frame */ | ||||
| BKE_ptcache_validate(cache, (int)ctime); | BKE_ptcache_validate(cache, (int)ctime); | ||||
| BKE_ptcache_write(&pid, (unsigned int)ctime); | BKE_ptcache_write(&pid, (unsigned int)ctime); | ||||
| rbw->ltime = ctime; | rbw->ltime = ctime; | ||||
| ▲ Show 20 Lines • Show All 142 Lines • Show Last 20 Lines | |||||
Reminder: Only do this check at this point for non kinematic objects!