Fix T90246: Full Copy'ing a scene confuses physics in the original scene.

Handling of RigidBody data in duplicate of scenes/collections was very
wrong. This commit:
 - Add handling of duplication of RB collections when fully duplicating
   a scene.
 - Fix Object duplication trying to add duplicated RB objects to
   matching RBW collections.

While the later behavior is desired when only duplicated objects, when
duplicating their collections and/or scenes it is actually very bad, as
it would add back new object duplicates to old (RBW) collections.
This commit is contained in:
Bastien Montagne 2021-09-30 15:22:16 +02:00
parent 779ea49af7
commit 1a72744ddc
Notes: blender-bot 2023-02-14 10:11:54 +01:00
Referenced by issue #90246, Full Copy'ing a scene confuses physics in the original scene
6 changed files with 60 additions and 27 deletions

View File

@ -133,6 +133,9 @@ enum {
LIB_ID_COPY_SHAPEKEY = 1 << 26,
/** EXCEPTION! Specific deep-copy of node trees used e.g. for rendering purposes. */
LIB_ID_COPY_NODETREE_LOCALIZE = 1 << 27,
/** EXCEPTION! Specific handling of RB objects regarding collections differs depending whether we
duplicate scene/collections, or objects. */
LIB_ID_COPY_RIGID_BODY_NO_COLLECTION_HANDLING = 1 << 28,
/* *** Helper 'defines' gathering most common flag sets. *** */
/** Shapekeys are not real ID's, more like local data to geometry IDs... */
@ -261,7 +264,8 @@ struct ID *BKE_id_copy_ex(struct Main *bmain,
const int flag);
struct ID *BKE_id_copy_for_duplicate(struct Main *bmain,
struct ID *id,
const uint duplicate_flags);
const uint duplicate_flags,
const int copy_flags);
void BKE_lib_id_swap(struct Main *bmain, struct ID *id_a, struct ID *id_b);
void BKE_lib_id_swap_full(struct Main *bmain, struct ID *id_a, struct ID *id_b);

View File

@ -597,7 +597,7 @@ static Collection *collection_duplicate_recursive(Main *bmain,
}
else if (collection_old->id.newid == NULL) {
collection_new = (Collection *)BKE_id_copy_for_duplicate(
bmain, (ID *)collection_old, duplicate_flags);
bmain, (ID *)collection_old, duplicate_flags, LIB_ID_COPY_DEFAULT);
if (collection_new == collection_old) {
return collection_new;

View File

@ -674,7 +674,10 @@ ID *BKE_id_copy(Main *bmain, const ID *id)
* Invokes the appropriate copy method for the block and returns the result in
* newid, unless test. Returns true if the block can be copied.
*/
ID *BKE_id_copy_for_duplicate(Main *bmain, ID *id, const eDupli_ID_Flags duplicate_flags)
ID *BKE_id_copy_for_duplicate(Main *bmain,
ID *id,
const eDupli_ID_Flags duplicate_flags,
const int copy_flags)
{
if (id == NULL) {
return id;
@ -685,7 +688,7 @@ ID *BKE_id_copy_for_duplicate(Main *bmain, ID *id, const eDupli_ID_Flags duplica
return id;
}
ID *id_new = BKE_id_copy(bmain, id);
ID *id_new = BKE_id_copy_ex(bmain, id, NULL, copy_flags);
/* Copying add one user by default, need to get rid of that one. */
id_us_min(id_new);
ID_NEW_SET(id, id_new);

View File

@ -2634,10 +2634,16 @@ Object *BKE_object_duplicate(Main *bmain,
{
const bool is_subprocess = (duplicate_options & LIB_ID_DUPLICATE_IS_SUBPROCESS) != 0;
const bool is_root_id = (duplicate_options & LIB_ID_DUPLICATE_IS_ROOT_ID) != 0;
int copy_flags = LIB_ID_COPY_DEFAULT;
if (!is_subprocess) {
BKE_main_id_newptr_and_tag_clear(bmain);
}
else {
/* In case copying object is a sub-process of collection (or scene) copying, do not try to
* re-assign RB objects to existing RBW collections. */
copy_flags |= LIB_ID_COPY_RIGID_BODY_NO_COLLECTION_HANDLING;
}
if (is_root_id) {
/* In case root duplicated ID is linked, assume we want to get a local copy of it and duplicate
* all expected linked data. */
@ -2649,7 +2655,7 @@ Object *BKE_object_duplicate(Main *bmain,
Material ***matarar;
Object *obn = (Object *)BKE_id_copy_for_duplicate(bmain, &ob->id, dupflag);
Object *obn = (Object *)BKE_id_copy_for_duplicate(bmain, &ob->id, dupflag, copy_flags);
/* 0 == full linked. */
if (dupflag == 0) {
@ -2658,13 +2664,13 @@ Object *BKE_object_duplicate(Main *bmain,
if (dupflag & USER_DUP_MAT) {
for (int i = 0; i < obn->totcol; i++) {
BKE_id_copy_for_duplicate(bmain, (ID *)obn->mat[i], dupflag);
BKE_id_copy_for_duplicate(bmain, (ID *)obn->mat[i], dupflag, copy_flags);
}
}
if (dupflag & USER_DUP_PSYS) {
ParticleSystem *psys;
for (psys = obn->particlesystem.first; psys; psys = psys->next) {
BKE_id_copy_for_duplicate(bmain, (ID *)psys->part, dupflag);
BKE_id_copy_for_duplicate(bmain, (ID *)psys->part, dupflag, copy_flags);
}
}
@ -2675,77 +2681,77 @@ Object *BKE_object_duplicate(Main *bmain,
switch (obn->type) {
case OB_MESH:
if (dupflag & USER_DUP_MESH) {
id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag, copy_flags);
}
break;
case OB_CURVE:
if (dupflag & USER_DUP_CURVE) {
id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag, copy_flags);
}
break;
case OB_SURF:
if (dupflag & USER_DUP_SURF) {
id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag, copy_flags);
}
break;
case OB_FONT:
if (dupflag & USER_DUP_FONT) {
id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag, copy_flags);
}
break;
case OB_MBALL:
if (dupflag & USER_DUP_MBALL) {
id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag, copy_flags);
}
break;
case OB_LAMP:
if (dupflag & USER_DUP_LAMP) {
id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag, copy_flags);
}
break;
case OB_ARMATURE:
if (dupflag & USER_DUP_ARM) {
id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag, copy_flags);
}
break;
case OB_LATTICE:
if (dupflag != 0) {
id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag, copy_flags);
}
break;
case OB_CAMERA:
if (dupflag != 0) {
id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag, copy_flags);
}
break;
case OB_LIGHTPROBE:
if (dupflag & USER_DUP_LIGHTPROBE) {
id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag, copy_flags);
}
break;
case OB_SPEAKER:
if (dupflag != 0) {
id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag, copy_flags);
}
break;
case OB_GPENCIL:
if (dupflag & USER_DUP_GPENCIL) {
id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag, copy_flags);
}
break;
case OB_HAIR:
if (dupflag & USER_DUP_HAIR) {
id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag, copy_flags);
}
break;
case OB_POINTCLOUD:
if (dupflag & USER_DUP_POINTCLOUD) {
id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag, copy_flags);
}
break;
case OB_VOLUME:
if (dupflag & USER_DUP_VOLUME) {
id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag, copy_flags);
}
break;
}
@ -2756,7 +2762,7 @@ Object *BKE_object_duplicate(Main *bmain,
matarar = BKE_object_material_array_p(obn);
if (matarar) {
for (int i = 0; i < obn->totcol; i++) {
BKE_id_copy_for_duplicate(bmain, (ID *)(*matarar)[i], dupflag);
BKE_id_copy_for_duplicate(bmain, (ID *)(*matarar)[i], dupflag, copy_flags);
}
}
}

View File

@ -302,7 +302,7 @@ void BKE_rigidbody_object_copy(Main *bmain, Object *ob_dst, const Object *ob_src
ob_dst->rigidbody_object = rigidbody_copy_object(ob_src, flag);
ob_dst->rigidbody_constraint = rigidbody_copy_constraint(ob_src, flag);
if (flag & LIB_ID_CREATE_NO_MAIN) {
if ((flag & (LIB_ID_CREATE_NO_MAIN | LIB_ID_COPY_RIGID_BODY_NO_COLLECTION_HANDLING)) != 0) {
return;
}

View File

@ -1801,6 +1801,7 @@ Scene *BKE_scene_duplicate(Main *bmain, Scene *sce, eSceneCopyMethod type)
/* Scene duplication is always root of duplication currently. */
const bool is_subprocess = false;
const bool is_root_id = true;
const int copy_flags = LIB_ID_COPY_DEFAULT;
if (!is_subprocess) {
BKE_main_id_newptr_and_tag_clear(bmain);
@ -1816,21 +1817,40 @@ Scene *BKE_scene_duplicate(Main *bmain, Scene *sce, eSceneCopyMethod type)
/* Copy Freestyle LineStyle datablocks. */
LISTBASE_FOREACH (ViewLayer *, view_layer_dst, &sce_copy->view_layers) {
LISTBASE_FOREACH (FreestyleLineSet *, lineset, &view_layer_dst->freestyle_config.linesets) {
BKE_id_copy_for_duplicate(bmain, (ID *)lineset->linestyle, duplicate_flags);
BKE_id_copy_for_duplicate(bmain, (ID *)lineset->linestyle, duplicate_flags, copy_flags);
}
}
/* Full copy of world (included animations) */
BKE_id_copy_for_duplicate(bmain, (ID *)sce->world, duplicate_flags);
BKE_id_copy_for_duplicate(bmain, (ID *)sce->world, duplicate_flags, copy_flags);
/* Full copy of GreasePencil. */
BKE_id_copy_for_duplicate(bmain, (ID *)sce->gpd, duplicate_flags);
BKE_id_copy_for_duplicate(bmain, (ID *)sce->gpd, duplicate_flags, copy_flags);
/* Deep-duplicate collections and objects (using preferences' settings for which sub-data to
* duplicate along the object itself). */
BKE_collection_duplicate(
bmain, NULL, sce_copy->master_collection, duplicate_flags, LIB_ID_DUPLICATE_IS_SUBPROCESS);
/* Rigid body world collections may not be instantiated as scene's collections, ensure they
* also get properly duplicated. */
if (sce_copy->rigidbody_world != NULL) {
if (sce_copy->rigidbody_world->group != NULL) {
BKE_collection_duplicate(bmain,
NULL,
sce_copy->rigidbody_world->group,
duplicate_flags,
LIB_ID_DUPLICATE_IS_SUBPROCESS);
}
if (sce_copy->rigidbody_world->constraints != NULL) {
BKE_collection_duplicate(bmain,
NULL,
sce_copy->rigidbody_world->constraints,
duplicate_flags,
LIB_ID_DUPLICATE_IS_SUBPROCESS);
}
}
if (!is_subprocess) {
/* This code will follow into all ID links using an ID tagged with LIB_TAG_NEW. */
BKE_libblock_relink_to_newid(&sce_copy->id);