diff options
-rw-r--r-- | intern/cycles/test/CMakeLists.txt | 1 | ||||
-rw-r--r-- | intern/cycles/test/util_transform_test.cpp | 53 | ||||
-rw-r--r-- | intern/cycles/util/util_math_float4.h | 18 | ||||
-rw-r--r-- | intern/cycles/util/util_transform.cpp | 28 | ||||
-rw-r--r-- | intern/cycles/util/util_transform.h | 11 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_action.h | 5 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/action.c | 49 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/armature.c | 2 | ||||
-rw-r--r-- | source/blender/blenloader/intern/readfile.c | 4 | ||||
-rw-r--r-- | source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc | 8 | ||||
-rw-r--r-- | source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc | 21 | ||||
-rw-r--r-- | source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.h | 5 | ||||
-rw-r--r-- | source/blender/editors/armature/armature_relations.c | 1 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_action_types.h | 3 |
14 files changed, 190 insertions, 19 deletions
diff --git a/intern/cycles/test/CMakeLists.txt b/intern/cycles/test/CMakeLists.txt index 6dcc7f7b3dd..07b345baff8 100644 --- a/intern/cycles/test/CMakeLists.txt +++ b/intern/cycles/test/CMakeLists.txt @@ -112,3 +112,4 @@ set_source_files_properties(util_avxf_avx_test.cpp PROPERTIES COMPILE_FLAGS "${C CYCLES_TEST(util_avxf_avx "cycles_util;bf_intern_numaapi;${OPENIMAGEIO_LIBRARIES};${BOOST_LIBRARIES}") set_source_files_properties(util_avxf_avx2_test.cpp PROPERTIES COMPILE_FLAGS "${CYCLES_AVX2_KERNEL_FLAGS}") CYCLES_TEST(util_avxf_avx2 "cycles_util;bf_intern_numaapi;${OPENIMAGEIO_LIBRARIES};${BOOST_LIBRARIES}") +CYCLES_TEST(util_transform "cycles_util;${OPENIMAGEIO_LIBRARIES};${BOOST_LIBRARIES}") diff --git a/intern/cycles/test/util_transform_test.cpp b/intern/cycles/test/util_transform_test.cpp new file mode 100644 index 00000000000..58ce0fdfee4 --- /dev/null +++ b/intern/cycles/test/util_transform_test.cpp @@ -0,0 +1,53 @@ +/* + * Copyright 2011-2020 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "testing/testing.h" + +#include "util/util_transform.h" +#include "util/util_vector.h" + +CCL_NAMESPACE_BEGIN + +TEST(transform_motion_decompose, Degenerated) +{ + // Simple case: single degenerated matrix. + { + vector<Transform> motion = {transform_scale(0.0f, 0.0f, 0.0f)}; + vector<DecomposedTransform> decomp(motion.size()); + transform_motion_decompose(decomp.data(), motion.data(), motion.size()); + EXPECT_TRUE(transform_decomposed_isfinite_safe(&decomp[0])); + } + + // Copy from previous to current. + { + vector<Transform> motion = {transform_rotate(M_PI_4_F, make_float3(1.0f, 1.0f, 1.0f)), + transform_scale(0.0f, 0.0f, 0.0f)}; + vector<DecomposedTransform> decomp(motion.size()); + transform_motion_decompose(decomp.data(), motion.data(), motion.size()); + EXPECT_NEAR(len(decomp[1].x - decomp[0].x), 0.0f, 1e-6f); + } + + // Copy from next to current. + { + vector<Transform> motion = {transform_scale(0.0f, 0.0f, 0.0f), + transform_rotate(M_PI_4_F, make_float3(1.0f, 1.0f, 1.0f))}; + vector<DecomposedTransform> decomp(motion.size()); + transform_motion_decompose(decomp.data(), motion.data(), motion.size()); + EXPECT_NEAR(len(decomp[0].x - decomp[1].x), 0.0f, 1e-6f); + } +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/util/util_math_float4.h b/intern/cycles/util/util_math_float4.h index cd4b3e3b74c..ec5328adb31 100644 --- a/intern/cycles/util/util_math_float4.h +++ b/intern/cycles/util/util_math_float4.h @@ -477,6 +477,24 @@ ccl_device_inline float4 safe_divide_float4_float(const float4 a, const float b) return (b != 0.0f) ? a / b : make_float4(0.0f, 0.0f, 0.0f, 0.0f); } +ccl_device_inline bool isfinite4_safe(float4 v) +{ + return isfinite_safe(v.x) && isfinite_safe(v.y) && isfinite_safe(v.z) && isfinite_safe(v.w); +} + +ccl_device_inline float4 ensure_finite4(float4 v) +{ + if (!isfinite_safe(v.x)) + v.x = 0.0f; + if (!isfinite_safe(v.y)) + v.y = 0.0f; + if (!isfinite_safe(v.z)) + v.z = 0.0f; + if (!isfinite_safe(v.w)) + v.w = 0.0f; + return v; +} + CCL_NAMESPACE_END #endif /* __UTIL_MATH_FLOAT4_H__ */ diff --git a/intern/cycles/util/util_transform.cpp b/intern/cycles/util/util_transform.cpp index 101122740d7..6417752f704 100644 --- a/intern/cycles/util/util_transform.cpp +++ b/intern/cycles/util/util_transform.cpp @@ -269,17 +269,17 @@ static void transform_decompose(DecomposedTransform *decomp, const Transform *tf /* extract scale and shear first */ float3 scale, shear; scale.x = len(colx); - colx /= scale.x; + colx = safe_divide_float3_float(colx, scale.x); shear.z = dot(colx, coly); coly -= shear.z * colx; scale.y = len(coly); - coly /= scale.y; + coly = safe_divide_float3_float(coly, scale.y); shear.y = dot(colx, colz); colz -= shear.y * colx; shear.x = dot(coly, colz); colz -= shear.x * coly; scale.z = len(colz); - colz /= scale.z; + colz = safe_divide_float3_float(colz, scale.z); transform_set_column(&M, 0, colx); transform_set_column(&M, 1, coly); @@ -300,6 +300,7 @@ static void transform_decompose(DecomposedTransform *decomp, const Transform *tf void transform_motion_decompose(DecomposedTransform *decomp, const Transform *motion, size_t size) { + /* Decompose and correct rotation. */ for (size_t i = 0; i < size; i++) { transform_decompose(decomp + i, motion + i); @@ -310,6 +311,27 @@ void transform_motion_decompose(DecomposedTransform *decomp, const Transform *mo decomp[i].x = -decomp[i].x; } } + + /* Copy rotation to decomposed transform where scale is degenerate. This avoids weird object + * rotation interpolation when the scale goes to 0 for a time step. + * + * Note that this is very simple and naive implementation, which only deals with degenerated + * scale happening only on one frame. It is possible to improve it further by interpolating + * rotation into s degenerated range using rotation from timesteps from adjacent non-degenerated + * time steps. */ + for (size_t i = 0; i < size; i++) { + const float3 scale = make_float3(decomp[i].y.w, decomp[i].z.w, decomp[i].w.w); + if (!is_zero(scale)) { + continue; + } + + if (i > 0) { + decomp[i].x = decomp[i - 1].x; + } + else if (i < size - 1) { + decomp[i].x = decomp[i + 1].x; + } + } } Transform transform_from_viewplane(BoundBox2D &viewplane) diff --git a/intern/cycles/util/util_transform.h b/intern/cycles/util/util_transform.h index d0a6264d5cf..d8bbd389aa6 100644 --- a/intern/cycles/util/util_transform.h +++ b/intern/cycles/util/util_transform.h @@ -466,6 +466,17 @@ ccl_device void transform_motion_array_interpolate(Transform *tfm, transform_compose(tfm, &decomp); } +ccl_device_inline bool transform_isfinite_safe(Transform *tfm) +{ + return isfinite4_safe(tfm->x) && isfinite4_safe(tfm->y) && isfinite4_safe(tfm->z); +} + +ccl_device_inline bool transform_decomposed_isfinite_safe(DecomposedTransform *decomp) +{ + return isfinite4_safe(decomp->x) && isfinite4_safe(decomp->y) && isfinite4_safe(decomp->z) && + isfinite4_safe(decomp->w); +} + #ifndef __KERNEL_GPU__ class BoundBox2D; diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h index b7904ce1879..c3cfd4b33ea 100644 --- a/source/blender/blenkernel/BKE_action.h +++ b/source/blender/blenkernel/BKE_action.h @@ -129,6 +129,8 @@ void BKE_pose_channel_free(struct bPoseChannel *pchan); void BKE_pose_channel_free_ex(struct bPoseChannel *pchan, bool do_id_user); void BKE_pose_channel_runtime_reset(struct bPoseChannel_Runtime *runtime); +void BKE_pose_channel_runtime_reset_on_copy(struct bPoseChannel_Runtime *runtime); + void BKE_pose_channel_runtime_free(struct bPoseChannel_Runtime *runtime); void BKE_pose_channel_free_bbone_cache(struct bPoseChannel_Runtime *runtime); @@ -153,12 +155,15 @@ void BKE_pose_copy_data_ex(struct bPose **dst, const bool copy_constraints); void BKE_pose_copy_data(struct bPose **dst, const struct bPose *src, const bool copy_constraints); void BKE_pose_channel_copy_data(struct bPoseChannel *pchan, const struct bPoseChannel *pchan_from); +void BKE_pose_channel_session_uuid_generate(struct bPoseChannel *pchan); struct bPoseChannel *BKE_pose_channel_find_name(const struct bPose *pose, const char *name); struct bPoseChannel *BKE_pose_channel_active(struct Object *ob); struct bPoseChannel *BKE_pose_channel_active_or_first_selected(struct Object *ob); struct bPoseChannel *BKE_pose_channel_verify(struct bPose *pose, const char *name); struct bPoseChannel *BKE_pose_channel_get_mirrored(const struct bPose *pose, const char *name); +void BKE_pose_check_uuids_unique_and_report(const struct bPose *pose); + #ifndef NDEBUG bool BKE_pose_channels_is_valid(const struct bPose *pose); #endif diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index fa7eee83a68..85ac2c693cb 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -37,6 +37,7 @@ #include "BLI_blenlib.h" #include "BLI_ghash.h" #include "BLI_math.h" +#include "BLI_session_uuid.h" #include "BLI_string_utils.h" #include "BLI_utildefines.h" @@ -482,6 +483,11 @@ void action_groups_clear_tempflags(bAction *act) /* *************** Pose channels *************** */ +void BKE_pose_channel_session_uuid_generate(bPoseChannel *pchan) +{ + pchan->runtime.session_uuid = BLI_session_uuid_generate(); +} + /** * Return a pointer to the pose channel of the given name * from this pose. @@ -524,6 +530,8 @@ bPoseChannel *BKE_pose_channel_verify(bPose *pose, const char *name) /* If not, create it and add it */ chan = MEM_callocN(sizeof(bPoseChannel), "verifyPoseChannel"); + BKE_pose_channel_session_uuid_generate(chan); + BLI_strncpy(chan->name, name, sizeof(chan->name)); chan->custom_scale = 1.0f; @@ -698,6 +706,10 @@ void BKE_pose_copy_data_ex(bPose **dst, id_us_plus((ID *)pchan->custom); } + if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) { + BKE_pose_channel_session_uuid_generate(pchan); + } + /* warning, O(n2) here, if done without the hash, but these are rarely used features. */ if (pchan->custom_tx) { pchan->custom_tx = BKE_pose_channel_find_name(outPose, pchan->custom_tx->name); @@ -726,7 +738,7 @@ void BKE_pose_copy_data_ex(bPose **dst, pchan->draw_data = NULL; /* Drawing cache, no need to copy. */ /* Runtime data, no need to copy. */ - memset(&pchan->runtime, 0, sizeof(pchan->runtime)); + BKE_pose_channel_runtime_reset_on_copy(&pchan->runtime); } /* for now, duplicate Bone Groups too when doing this */ @@ -956,6 +968,14 @@ void BKE_pose_channel_runtime_reset(bPoseChannel_Runtime *runtime) memset(runtime, 0, sizeof(*runtime)); } +/* Reset all non-persistent fields. */ +void BKE_pose_channel_runtime_reset_on_copy(bPoseChannel_Runtime *runtime) +{ + const SessionUUID uuid = runtime->session_uuid; + memset(runtime, 0, sizeof(*runtime)); + runtime->session_uuid = uuid; +} + /** Deallocates runtime cache of a pose channel */ void BKE_pose_channel_runtime_free(bPoseChannel_Runtime *runtime) { @@ -1692,3 +1712,30 @@ void what_does_obaction(Object *ob, BKE_animsys_evaluate_animdata(&workob->id, &adt, anim_eval_context, ADT_RECALC_ANIM, false); } } + +void BKE_pose_check_uuids_unique_and_report(const bPose *pose) +{ + if (pose == NULL) { + return; + } + + struct GSet *used_uuids = BLI_gset_new( + BLI_session_uuid_ghash_hash, BLI_session_uuid_ghash_compare, "sequencer used uuids"); + + LISTBASE_FOREACH (bPoseChannel *, pchan, &pose->chanbase) { + const SessionUUID *session_uuid = &pchan->runtime.session_uuid; + if (!BLI_session_uuid_is_generated(session_uuid)) { + printf("Pose channel %s does not have UUID generated.\n", pchan->name); + continue; + } + + if (BLI_gset_lookup(used_uuids, session_uuid) != NULL) { + printf("Pose channel %s has duplicate UUID generated.\n", pchan->name); + continue; + } + + BLI_gset_insert(used_uuids, (void *)session_uuid); + } + + BLI_gset_free(used_uuids, NULL); +} diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index c977ebe4ae2..631ce4edd20 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -2205,7 +2205,7 @@ static void pose_proxy_sync(Object *ob, Object *from, int layer_protected) pchan->mpath = NULL; /* Reset runtime data, we don't want to share that with the proxy. */ - BKE_pose_channel_runtime_reset(&pchanw.runtime); + BKE_pose_channel_runtime_reset_on_copy(&pchanw.runtime); /* this is freed so copy a copy, else undo crashes */ if (pchanw.prop) { diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 398598a3fb6..6d220d1fd1d 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -5145,6 +5145,9 @@ static void direct_link_pose(BlendDataReader *reader, bPose *pose) pose->chan_array = NULL; for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { + BKE_pose_channel_runtime_reset(&pchan->runtime); + BKE_pose_channel_session_uuid_generate(pchan); + pchan->bone = NULL; BLO_read_data_address(reader, &pchan->parent); BLO_read_data_address(reader, &pchan->child); @@ -5170,7 +5173,6 @@ static void direct_link_pose(BlendDataReader *reader, bPose *pose) CLAMP(pchan->rotmode, ROT_MODE_MIN, ROT_MODE_MAX); pchan->draw_data = NULL; - BKE_pose_channel_runtime_reset(&pchan->runtime); } pose->ikdata = NULL; if (pose->ikparam != NULL) { diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc index 9956391a2d7..89df41944e5 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc @@ -288,6 +288,14 @@ bool id_copy_inplace_no_main(const ID *id, ID *newid) { const ID *id_for_copy = id; + if (G.debug & G_DEBUG_DEPSGRAPH_UUID) { + const ID_Type id_type = GS(id_for_copy->name); + if (id_type == ID_OB) { + const Object *object = reinterpret_cast<const Object *>(id_for_copy); + BKE_pose_check_uuids_unique_and_report(object->pose); + } + } + #ifdef NESTED_ID_NASTY_WORKAROUND NestedIDHackTempStorage id_hack_storage; id_for_copy = nested_id_hack_get_discarded_pointers(&id_hack_storage, id); diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc index e0957a10cb1..88334e41192 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc @@ -85,11 +85,11 @@ void ObjectRuntimeBackup::backup_pose_channel_runtime_data(Object *object) { if (object->pose != nullptr) { LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { - /* This is nullptr in Edit mode. */ - if (pchan->orig_pchan != nullptr) { - pose_channel_runtime_data.add(pchan->orig_pchan, pchan->runtime); - BKE_pose_channel_runtime_reset(&pchan->runtime); - } + const SessionUUID &session_uuid = pchan->runtime.session_uuid; + BLI_assert(BLI_session_uuid_is_generated(&session_uuid)); + + pose_channel_runtime_data.add(session_uuid, pchan->runtime); + BKE_pose_channel_runtime_reset(&pchan->runtime); } } } @@ -171,13 +171,10 @@ void ObjectRuntimeBackup::restore_pose_channel_runtime_data(Object *object) { if (object->pose != nullptr) { LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { - /* This is nullptr in Edit mode. */ - if (pchan->orig_pchan != nullptr) { - optional<bPoseChannel_Runtime> runtime = pose_channel_runtime_data.pop_try( - pchan->orig_pchan); - if (runtime.has_value()) { - pchan->runtime = *runtime; - } + const SessionUUID &session_uuid = pchan->runtime.session_uuid; + optional<bPoseChannel_Runtime> runtime = pose_channel_runtime_data.pop_try(session_uuid); + if (runtime.has_value()) { + pchan->runtime = *runtime; } } } diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.h index 04d7fb1bc22..a10f15634ce 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.h @@ -24,6 +24,9 @@ #pragma once #include "DNA_object_types.h" +#include "DNA_session_uuid_types.h" + +#include "BLI_session_uuid.h" #include "intern/eval/deg_eval_runtime_backup_modifier.h" #include "intern/eval/deg_eval_runtime_backup_pose.h" @@ -54,7 +57,7 @@ class ObjectRuntimeBackup { short base_flag; unsigned short base_local_view_bits; ModifierRuntimeDataBackup modifier_runtime_data; - Map<bPoseChannel *, bPoseChannel_Runtime> pose_channel_runtime_data; + Map<SessionUUID, bPoseChannel_Runtime> pose_channel_runtime_data; }; } // namespace deg diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c index 0dd35fb9fdc..a737916e9a2 100644 --- a/source/blender/editors/armature/armature_relations.c +++ b/source/blender/editors/armature/armature_relations.c @@ -384,6 +384,7 @@ int ED_armature_join_objects_exec(bContext *C, wmOperator *op) BLI_remlink(curarm->edbo, curbone); BLI_addtail(arm->edbo, curbone); + /* Pose channel is moved from one storage to another, its UUID is still unique. */ BLI_remlink(&opose->chanbase, pchan); BLI_addtail(&pose->chanbase, pchan); BKE_pose_channels_hash_free(opose); diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h index 98e858dbf41..74293e25c5c 100644 --- a/source/blender/makesdna/DNA_action_types.h +++ b/source/blender/makesdna/DNA_action_types.h @@ -30,6 +30,7 @@ #include "DNA_ID.h" #include "DNA_listBase.h" +#include "DNA_session_uuid_types.h" #include "DNA_userdef_types.h" /* ThemeWireColor */ #include "DNA_vec_types.h" #include "DNA_view2d_types.h" @@ -188,6 +189,8 @@ struct DualQuat; struct Mat4; typedef struct bPoseChannel_Runtime { + SessionUUID session_uuid; + /* Cached dual quaternion for deformation. */ struct DualQuat deform_dual_quat; |