Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Tönne <lukas.toenne@gmail.com>2022-06-22 08:37:45 +0300
committerLukas Tönne <lukas.toenne@gmail.com>2022-06-22 08:37:45 +0300
commitf4d8382c86ba760c5fccf7096ca50d6572b208bd (patch)
tree229e2a16e7dbe330b353552cc30eac67233a101e
parent75f0aaab3d37f9eac61d5cea2b42b16adabff304 (diff)
Rigid body physics: Move effector force update into substep loop.
The substep loop for rigid bodies causes unequal effects of force fields depedending on the substep setting, larger substep counts cause a diminishing effect of force fields. This is because the force to apply on a body is reset in Bullet after each step and needs to be recomputed. Without this the body will just coast with constant velocity after the first substep. Since the per-step impulse with larger substep counts is smaller, the effect is that more substeps cause a smaller total impulse. The fix is to move external force calculation into the substep loop and update forces for each substep. Note that this may be considered a breaking change, because the breaking commit rB1aa54d4921c2 has been in master for a long time and after this fix force fields will generally have a much larger effect on rigid bodies (10x for the default setting of 10 substeps). Differential Revision: https://developer.blender.org/D15173
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c124
1 files changed, 70 insertions, 54 deletions
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index 60cc4ce83af..2f20b1e661b 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -1712,54 +1712,6 @@ static void rigidbody_update_sim_ob(
RB_body_set_mass(rbo->shared->physics_object, 0.0f);
}
- /* update influence of effectors - but don't do it on an effector */
- /* only dynamic bodies need effector update */
- else if (rbo->type == RBO_TYPE_ACTIVE &&
- ((ob->pd == NULL) || (ob->pd->forcefield == PFIELD_NULL))) {
- EffectorWeights *effector_weights = rbw->effector_weights;
- EffectedPoint epoint;
- ListBase *effectors;
-
- /* get effectors present in the group specified by effector_weights */
- effectors = BKE_effectors_create(depsgraph, ob, NULL, effector_weights, false);
- if (effectors) {
- float eff_force[3] = {0.0f, 0.0f, 0.0f};
- float eff_loc[3], eff_vel[3];
-
- /* create dummy 'point' which represents last known position of object as result of sim */
- /* XXX: this can create some inaccuracies with sim position,
- * but is probably better than using un-simulated values? */
- RB_body_get_position(rbo->shared->physics_object, eff_loc);
- RB_body_get_linear_velocity(rbo->shared->physics_object, eff_vel);
-
- pd_point_from_loc(scene, eff_loc, eff_vel, 0, &epoint);
-
- /* Calculate net force of effectors, and apply to sim object:
- * - we use 'central force' since apply force requires a "relative position"
- * which we don't have... */
- BKE_effectors_apply(effectors, NULL, effector_weights, &epoint, eff_force, NULL, NULL);
- if (G.f & G_DEBUG) {
- printf("\tapplying force (%f,%f,%f) to '%s'\n",
- eff_force[0],
- eff_force[1],
- eff_force[2],
- ob->id.name + 2);
- }
- /* activate object in case it is deactivated */
- if (!is_zero_v3(eff_force)) {
- RB_body_activate(rbo->shared->physics_object);
- }
- RB_body_apply_central_force(rbo->shared->physics_object, eff_force);
- }
- else if (G.f & G_DEBUG) {
- printf("\tno forces to apply to '%s'\n", ob->id.name + 2);
- }
-
- /* cleanup */
- BKE_effectors_free(effectors);
- }
- /* NOTE: passive objects don't need to be updated since they don't move */
-
/* NOTE: no other settings need to be explicitly updated here,
* since RNA setters take care of the rest :)
*/
@@ -1986,6 +1938,69 @@ static void rigidbody_update_kinematic_obj_substep(ListBase *substep_targets, fl
}
}
+static void rigidbody_update_external_forces(Depsgraph *depsgraph,
+ Scene *scene,
+ RigidBodyWorld *rbw)
+{
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->group, ob) {
+ /* only update if rigid body exists */
+ RigidBodyOb *rbo = ob->rigidbody_object;
+ if (ob->type != OB_MESH || rbo->shared->physics_object == NULL) {
+ continue;
+ }
+
+ /* update influence of effectors - but don't do it on an effector */
+ /* only dynamic bodies need effector update */
+ if (rbo->type == RBO_TYPE_ACTIVE &&
+ ((ob->pd == NULL) || (ob->pd->forcefield == PFIELD_NULL))) {
+ EffectorWeights *effector_weights = rbw->effector_weights;
+ EffectedPoint epoint;
+ ListBase *effectors;
+
+ /* get effectors present in the group specified by effector_weights */
+ effectors = BKE_effectors_create(depsgraph, ob, NULL, effector_weights, false);
+ if (effectors) {
+ float eff_force[3] = {0.0f, 0.0f, 0.0f};
+ float eff_loc[3], eff_vel[3];
+
+ /* create dummy 'point' which represents last known position of object as result of sim
+ */
+ /* XXX: this can create some inaccuracies with sim position,
+ * but is probably better than using un-simulated values? */
+ RB_body_get_position(rbo->shared->physics_object, eff_loc);
+ RB_body_get_linear_velocity(rbo->shared->physics_object, eff_vel);
+
+ pd_point_from_loc(scene, eff_loc, eff_vel, 0, &epoint);
+
+ /* Calculate net force of effectors, and apply to sim object:
+ * - we use 'central force' since apply force requires a "relative position"
+ * which we don't have... */
+ BKE_effectors_apply(effectors, NULL, effector_weights, &epoint, eff_force, NULL, NULL);
+ if (G.f & G_DEBUG) {
+ printf("\tapplying force (%f,%f,%f) to '%s'\n",
+ eff_force[0],
+ eff_force[1],
+ eff_force[2],
+ ob->id.name + 2);
+ }
+ /* activate object in case it is deactivated */
+ if (!is_zero_v3(eff_force)) {
+ RB_body_activate(rbo->shared->physics_object);
+ }
+ RB_body_apply_central_force(rbo->shared->physics_object, eff_force);
+ }
+ else if (G.f & G_DEBUG) {
+ printf("\tno forces to apply to '%s'\n", ob->id.name + 2);
+ }
+
+ /* cleanup */
+ BKE_effectors_free(effectors);
+ }
+ /* NOTE: passive objects don't need to be updated since they don't move */
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+}
+
static void rigidbody_free_substep_data(ListBase *substep_targets)
{
LISTBASE_FOREACH (LinkData *, link, substep_targets) {
@@ -2220,26 +2235,27 @@ void BKE_rigidbody_do_simulation(Depsgraph *depsgraph, Scene *scene, float ctime
BKE_ptcache_write(&pid, startframe);
}
- /* update and validate simulation */
- rigidbody_update_simulation(depsgraph, scene, rbw, false);
-
const float frame_diff = ctime - rbw->ltime;
/* calculate how much time elapsed since last step in seconds */
const float timestep = 1.0f / (float)FPS * frame_diff * rbw->time_scale;
const float substep = timestep / rbw->substeps_per_frame;
- ListBase substep_targets = rigidbody_create_substep_data(rbw);
+ ListBase kinematic_substep_targets = rigidbody_create_substep_data(rbw);
const float interp_step = 1.0f / rbw->substeps_per_frame;
float cur_interp_val = interp_step;
+ /* update and validate simulation */
+ rigidbody_update_simulation(depsgraph, scene, rbw, false);
+
for (int i = 0; i < rbw->substeps_per_frame; i++) {
- rigidbody_update_kinematic_obj_substep(&substep_targets, cur_interp_val);
+ rigidbody_update_external_forces(depsgraph, scene, rbw);
+ rigidbody_update_kinematic_obj_substep(&kinematic_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_free_substep_data(&kinematic_substep_targets);
rigidbody_update_simulation_post_step(depsgraph, rbw);