Depsgraph: Run rigid body after modifiers are ready
This makes it so modifiers are using object transform prior to the rigid body simulation, and then result of modifier stack is fed to the solver. Solves dependency cycle which was happening when object's modifier was dependent on the modifier transform. While now it is not possible to change simulation, things are somewhat more clear and reliable in other ways. For example previously, solver was using derives mesh from a previous step in time, which causes unfixable simulation issues (with intersections and such) Fixex T57589: 2.79 Rigid Body Sim. Does Not Behave The Same In 2.8 Fixex T61256: Compositing scenes causes crash, but rendering separately does not Fixes T61262: Armature and rigid body crash Fixes T61346: Rigid body with modifiers incorrect work
This commit is contained in:
@@ -285,13 +285,23 @@ void DepsgraphRelationBuilder::add_modifier_to_transform_relation(
|
|||||||
/* Geometry operation, this is where relation will be wired to. */
|
/* Geometry operation, this is where relation will be wired to. */
|
||||||
OperationNode *geometry_operation_node =
|
OperationNode *geometry_operation_node =
|
||||||
handle->node->get_entry_operation();
|
handle->node->get_entry_operation();
|
||||||
BLI_assert(geometry_operation_node->owner->type == NodeType::GEOMETRY);
|
ComponentNode *geometry_component = geometry_operation_node->owner;
|
||||||
|
BLI_assert(geometry_component->type == NodeType::GEOMETRY);
|
||||||
|
IDNode *id_node = geometry_component->owner;
|
||||||
/* Transform operation, the source of the relation. */
|
/* Transform operation, the source of the relation. */
|
||||||
|
ComponentNode *transform_component =
|
||||||
|
id_node->find_component(NodeType::TRANSFORM);
|
||||||
ID *id = geometry_operation_node->owner->owner->id_orig;
|
ID *id = geometry_operation_node->owner->owner->id_orig;
|
||||||
ComponentKey transform_component_key(id, NodeType::TRANSFORM);
|
BLI_assert(GS(id->name) == ID_OB);
|
||||||
Node *transform_node = get_node(transform_component_key);
|
Object *object = reinterpret_cast<Object *>(id);
|
||||||
OperationNode *transform_operation_node =
|
OperationNode *transform_operation_node = NULL;
|
||||||
transform_node->get_exit_operation();
|
if (object->rigidbody_object == NULL) {
|
||||||
|
transform_operation_node = transform_component->get_exit_operation();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
transform_operation_node = transform_component->get_operation(
|
||||||
|
OperationCode::TRANSFORM_EVAL);
|
||||||
|
}
|
||||||
/* Wire up the actual relation. */
|
/* Wire up the actual relation. */
|
||||||
add_operation_relation(
|
add_operation_relation(
|
||||||
transform_operation_node, geometry_operation_node, description);
|
transform_operation_node, geometry_operation_node, description);
|
||||||
@@ -657,14 +667,7 @@ void DepsgraphRelationBuilder::build_object(Base *base, Object *object)
|
|||||||
add_relation(ob_eval_key, final_transform_key, "Eval");
|
add_relation(ob_eval_key, final_transform_key, "Eval");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* NOTE: Keep an eye here, we skip some relations here to "streamline"
|
add_relation(base_op_key, ob_eval_key, "Eval");
|
||||||
* dependencies and avoid transitive relations which causes overhead.
|
|
||||||
* But once we get rid of uber eval node this will need reconsideration. */
|
|
||||||
if (object->rigidbody_object == NULL) {
|
|
||||||
/* Rigid body will hook up another node in between, so skip
|
|
||||||
* relation here to avoid transitive relation. */
|
|
||||||
add_relation(base_op_key, ob_eval_key, "Eval");
|
|
||||||
}
|
|
||||||
add_relation(ob_eval_key, final_transform_key, "Eval");
|
add_relation(ob_eval_key, final_transform_key, "Eval");
|
||||||
}
|
}
|
||||||
/* Animation data */
|
/* Animation data */
|
||||||
@@ -1619,84 +1622,80 @@ void DepsgraphRelationBuilder::build_world(World *world)
|
|||||||
void DepsgraphRelationBuilder::build_rigidbody(Scene *scene)
|
void DepsgraphRelationBuilder::build_rigidbody(Scene *scene)
|
||||||
{
|
{
|
||||||
RigidBodyWorld *rbw = scene->rigidbody_world;
|
RigidBodyWorld *rbw = scene->rigidbody_world;
|
||||||
|
OperationKey rb_init_key(&scene->id,
|
||||||
OperationKey init_key(&scene->id, NodeType::TRANSFORM, OperationCode::RIGIDBODY_REBUILD);
|
NodeType::TRANSFORM,
|
||||||
OperationKey sim_key(&scene->id, NodeType::TRANSFORM, OperationCode::RIGIDBODY_SIM);
|
OperationCode::RIGIDBODY_REBUILD);
|
||||||
|
OperationKey rb_simulate_key(&scene->id,
|
||||||
/* rel between the two sim-nodes */
|
NodeType::TRANSFORM,
|
||||||
add_relation(init_key, sim_key, "Rigidbody [Init -> SimStep]");
|
OperationCode::RIGIDBODY_SIM);
|
||||||
|
/* Simulation depends on time. */
|
||||||
/* set up dependencies between these operations and other builtin nodes --------------- */
|
TimeSourceKey time_src_key;
|
||||||
|
add_relation(time_src_key, rb_init_key, "TimeSrc -> Rigidbody Init");
|
||||||
/* effectors */
|
/* Simulation should always be run after initialization. */
|
||||||
|
/* NOTE: It is possible in theory to have dependency cycle which involves
|
||||||
|
* this relation. We never want it to be killed. */
|
||||||
|
add_relation(rb_init_key,
|
||||||
|
rb_simulate_key,
|
||||||
|
"Rigidbody [Init -> SimStep]",
|
||||||
|
RELATION_FLAG_GODMODE);
|
||||||
|
/* Effectors should be evaluated at the time simulation is being
|
||||||
|
* initialized.
|
||||||
|
* TODO(sergey): Verify that it indeed goes to initialization and not to a
|
||||||
|
* simulation. */
|
||||||
ListBase *relations = build_effector_relations(graph_, rbw->effector_weights->group);
|
ListBase *relations = build_effector_relations(graph_, rbw->effector_weights->group);
|
||||||
LISTBASE_FOREACH (EffectorRelation *, relation, relations) {
|
LISTBASE_FOREACH (EffectorRelation *, relation, relations) {
|
||||||
ComponentKey eff_key(&relation->ob->id, NodeType::TRANSFORM);
|
ComponentKey effector_transform_key(
|
||||||
add_relation(eff_key, init_key, "RigidBody Field");
|
&relation->ob->id, NodeType::TRANSFORM);
|
||||||
// FIXME add relations so pointache is marked as outdated when effectors are modified
|
add_relation(effector_transform_key, rb_init_key, "RigidBody Field");
|
||||||
}
|
}
|
||||||
|
/* Objects. */
|
||||||
/* time dependency */
|
|
||||||
TimeSourceKey time_src_key;
|
|
||||||
add_relation(time_src_key, init_key, "TimeSrc -> Rigidbody Reset/Rebuild (Optional)");
|
|
||||||
|
|
||||||
/* objects - simulation participants */
|
|
||||||
if (rbw->group != NULL) {
|
if (rbw->group != NULL) {
|
||||||
build_collection(NULL, NULL, rbw->group);
|
build_collection(NULL, NULL, rbw->group);
|
||||||
|
|
||||||
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object)
|
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object)
|
||||||
{
|
{
|
||||||
if (object->type != OB_MESH) {
|
if (object->type != OB_MESH) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
OperationKey rb_transform_copy_key(
|
||||||
/* hook up evaluation order...
|
&object->id,
|
||||||
* 1) flushing rigidbody results follows base transforms being applied
|
NodeType::TRANSFORM,
|
||||||
* 2) rigidbody flushing can only be performed after simulation has been run
|
OperationCode::RIGIDBODY_TRANSFORM_COPY);
|
||||||
*
|
/* Rigid body synchronization depends on the actual simulation. */
|
||||||
* 3) simulation needs to know base transforms to figure out what to do
|
add_relation(rb_simulate_key,
|
||||||
* XXX: there's probably a difference between passive and active
|
rb_transform_copy_key,
|
||||||
* - passive don't change, so may need to know full transform... */
|
"Rigidbody Sim Eval -> RBO Sync");
|
||||||
OperationKey rbo_key(&object->id, NodeType::TRANSFORM, OperationCode::RIGIDBODY_TRANSFORM_COPY);
|
/* Simulation uses object transformation after parenting and solving
|
||||||
|
* contraints. */
|
||||||
OperationCode trans_opcode = object->parent ? OperationCode::TRANSFORM_PARENT
|
OperationKey object_transform_eval_key(
|
||||||
: OperationCode::TRANSFORM_LOCAL;
|
&object->id,
|
||||||
OperationKey trans_op(&object->id, NodeType::TRANSFORM, trans_opcode);
|
NodeType::TRANSFORM,
|
||||||
|
OperationCode::TRANSFORM_EVAL);
|
||||||
add_relation(sim_key, rbo_key, "Rigidbody Sim Eval -> RBO Sync");
|
add_relation(object_transform_eval_key,
|
||||||
|
rb_simulate_key,
|
||||||
/* Geometry must be known to create the rigid body. RBO_MESH_BASE uses the non-evaluated
|
"Object Transform -> Rigidbody Sim Eval");
|
||||||
* mesh, so then the evaluation is unnecessary. */
|
/* Geometry must be known to create the rigid body. RBO_MESH_BASE
|
||||||
if (object->rigidbody_object != NULL && object->rigidbody_object->mesh_source != RBO_MESH_BASE) {
|
* uses the non-evaluated mesh, so then the evaluation is
|
||||||
ComponentKey geom_key(&object->id, NodeType::GEOMETRY);
|
* unnecessary. */
|
||||||
add_relation(geom_key, init_key, "Object Geom Eval -> Rigidbody Rebuild");
|
if (object->rigidbody_object != NULL &&
|
||||||
|
object->rigidbody_object->mesh_source != RBO_MESH_BASE)
|
||||||
|
{
|
||||||
|
/* NOTE: We prefer this relation to be never killed, to avoid
|
||||||
|
* access partially evaluated mesh from solver. */
|
||||||
|
ComponentKey object_geometry_key(
|
||||||
|
&object->id, NodeType::GEOMETRY);
|
||||||
|
add_relation(object_geometry_key,
|
||||||
|
rb_simulate_key,
|
||||||
|
"Object Geom Eval -> Rigidbody Rebuild",
|
||||||
|
RELATION_FLAG_GODMODE);
|
||||||
}
|
}
|
||||||
|
/* Final transform is whetever solver gave to us. */
|
||||||
/* if constraints exist, those depend on the result of the rigidbody sim
|
OperationKey object_transform_final_key(
|
||||||
* - This allows constraints to modify the result of the sim (i.e. clamping)
|
&object->id,
|
||||||
* while still allowing the sim to depend on some changes to the objects.
|
NodeType::TRANSFORM,
|
||||||
* Also, since constraints are hooked up to the final nodes, this link
|
OperationCode::TRANSFORM_FINAL);
|
||||||
* means that we can also fit in there too...
|
add_relation(rb_transform_copy_key,
|
||||||
* - Later, it might be good to include a constraint in the stack allowing us
|
object_transform_final_key,
|
||||||
* to control whether rigidbody eval gets interleaved into the constraint stack */
|
"Rigidbody Sync -> Transform Final");
|
||||||
if (object->constraints.first) {
|
|
||||||
OperationKey constraint_key(&object->id,
|
|
||||||
NodeType::TRANSFORM,
|
|
||||||
OperationCode::TRANSFORM_CONSTRAINTS);
|
|
||||||
add_relation(rbo_key, constraint_key, "RBO Sync -> Ob Constraints");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* Transform evaluation depends on rigidbody. */
|
|
||||||
OperationKey transform_eval_key(&object->id,
|
|
||||||
NodeType::TRANSFORM,
|
|
||||||
OperationCode::TRANSFORM_EVAL);
|
|
||||||
add_relation(rbo_key,
|
|
||||||
transform_eval_key,
|
|
||||||
"RBO Sync -> Transform Eval");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Needed to get correct base values. */
|
|
||||||
add_relation(trans_op, sim_key, "Base Ob Transform -> Rigidbody Sim Eval");
|
|
||||||
}
|
}
|
||||||
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
|
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
|
||||||
}
|
}
|
||||||
@@ -1706,7 +1705,8 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene)
|
|||||||
{
|
{
|
||||||
RigidBodyCon *rbc = object->rigidbody_constraint;
|
RigidBodyCon *rbc = object->rigidbody_constraint;
|
||||||
if (rbc == NULL || rbc->ob1 == NULL || rbc->ob2 == NULL) {
|
if (rbc == NULL || rbc->ob1 == NULL || rbc->ob2 == NULL) {
|
||||||
/* When either ob1 or ob2 is NULL, the constraint doesn't work. */
|
/* When either ob1 or ob2 is NULL, the constraint doesn't
|
||||||
|
* work. */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* Make sure indirectly linked objects are fully built. */
|
/* Make sure indirectly linked objects are fully built. */
|
||||||
@@ -1716,13 +1716,21 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene)
|
|||||||
/* final result of the constraint object's transform controls how
|
/* final result of the constraint object's transform controls how
|
||||||
* the constraint affects the physics sim for these objects. */
|
* the constraint affects the physics sim for these objects. */
|
||||||
ComponentKey trans_key(&object->id, NodeType::TRANSFORM);
|
ComponentKey trans_key(&object->id, NodeType::TRANSFORM);
|
||||||
OperationKey ob1_key(&rbc->ob1->id, NodeType::TRANSFORM, OperationCode::RIGIDBODY_TRANSFORM_COPY);
|
OperationKey ob1_key(&rbc->ob1->id,
|
||||||
OperationKey ob2_key(&rbc->ob2->id, NodeType::TRANSFORM, OperationCode::RIGIDBODY_TRANSFORM_COPY);
|
NodeType::TRANSFORM,
|
||||||
|
OperationCode::RIGIDBODY_TRANSFORM_COPY);
|
||||||
|
OperationKey ob2_key(&rbc->ob2->id,
|
||||||
|
NodeType::TRANSFORM,
|
||||||
|
OperationCode::RIGIDBODY_TRANSFORM_COPY);
|
||||||
/* Constrained-objects sync depends on the constraint-holder. */
|
/* Constrained-objects sync depends on the constraint-holder. */
|
||||||
add_relation(trans_key, ob1_key, "RigidBodyConstraint -> RBC.Object_1");
|
add_relation(
|
||||||
add_relation(trans_key, ob2_key, "RigidBodyConstraint -> RBC.Object_2");
|
trans_key, ob1_key, "RigidBodyConstraint -> RBC.Object_1");
|
||||||
|
add_relation(
|
||||||
|
trans_key, ob2_key, "RigidBodyConstraint -> RBC.Object_2");
|
||||||
/* Ensure that sim depends on this constraint's transform. */
|
/* Ensure that sim depends on this constraint's transform. */
|
||||||
add_relation(trans_key, sim_key, "RigidBodyConstraint Transform -> RB Simulation");
|
add_relation(trans_key,
|
||||||
|
rb_simulate_key,
|
||||||
|
"RigidBodyConstraint Transform -> RB Simulation");
|
||||||
}
|
}
|
||||||
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
|
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user