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:
Diffstat (limited to 'source/blender/blenloader/intern/versioning_300.c')
-rw-r--r--source/blender/blenloader/intern/versioning_300.c138
1 files changed, 126 insertions, 12 deletions
diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c
index 4c6b70982a4..6b57bdf9a9c 100644
--- a/source/blender/blenloader/intern/versioning_300.c
+++ b/source/blender/blenloader/intern/versioning_300.c
@@ -47,6 +47,7 @@
#include "BKE_action.h"
#include "BKE_animsys.h"
+#include "BKE_armature.h"
#include "BKE_asset.h"
#include "BKE_collection.h"
#include "BKE_deform.h"
@@ -1097,6 +1098,112 @@ static void version_geometry_nodes_add_attribute_input_settings(NodesModifierDat
}
}
+/* Copy of the function before the fixes. */
+static void legacy_vec_roll_to_mat3_normalized(const float nor[3],
+ const float roll,
+ float r_mat[3][3])
+{
+ const float SAFE_THRESHOLD = 1.0e-5f; /* theta above this value has good enough precision. */
+ const float CRITICAL_THRESHOLD = 1.0e-9f; /* above this is safe under certain conditions. */
+ const float THRESHOLD_SQUARED = CRITICAL_THRESHOLD * CRITICAL_THRESHOLD;
+
+ const float x = nor[0];
+ const float y = nor[1];
+ const float z = nor[2];
+
+ const float theta = 1.0f + y; /* remapping Y from [-1,+1] to [0,2]. */
+ const float theta_alt = x * x + z * z; /* Helper value for matrix calculations.*/
+ float rMatrix[3][3], bMatrix[3][3];
+
+ BLI_ASSERT_UNIT_V3(nor);
+
+ /* When theta is close to zero (nor is aligned close to negative Y Axis),
+ * we have to check we do have non-null X/Z components as well.
+ * Also, due to float precision errors, nor can be (0.0, -0.99999994, 0.0) which results
+ * in theta being close to zero. This will cause problems when theta is used as divisor.
+ */
+ if (theta > SAFE_THRESHOLD || (theta > CRITICAL_THRESHOLD && theta_alt > THRESHOLD_SQUARED)) {
+ /* nor is *not* aligned to negative Y-axis (0,-1,0). */
+
+ bMatrix[0][1] = -x;
+ bMatrix[1][0] = x;
+ bMatrix[1][1] = y;
+ bMatrix[1][2] = z;
+ bMatrix[2][1] = -z;
+
+ if (theta > SAFE_THRESHOLD) {
+ /* nor differs significantly from negative Y axis (0,-1,0): apply the general case. */
+ bMatrix[0][0] = 1 - x * x / theta;
+ bMatrix[2][2] = 1 - z * z / theta;
+ bMatrix[2][0] = bMatrix[0][2] = -x * z / theta;
+ }
+ else {
+ /* nor is close to negative Y axis (0,-1,0): apply the special case. */
+ bMatrix[0][0] = (x + z) * (x - z) / -theta_alt;
+ bMatrix[2][2] = -bMatrix[0][0];
+ bMatrix[2][0] = bMatrix[0][2] = 2.0f * x * z / theta_alt;
+ }
+ }
+ else {
+ /* nor is very close to negative Y axis (0,-1,0): use simple symmetry by Z axis. */
+ unit_m3(bMatrix);
+ bMatrix[0][0] = bMatrix[1][1] = -1.0;
+ }
+
+ /* Make Roll matrix */
+ axis_angle_normalized_to_mat3(rMatrix, nor, roll);
+
+ /* Combine and output result */
+ mul_m3_m3m3(r_mat, rMatrix, bMatrix);
+}
+
+static void correct_bone_roll_value(const float head[3],
+ const float tail[3],
+ const float check_x_axis[3],
+ const float check_y_axis[3],
+ float *r_roll)
+{
+ const float SAFE_THRESHOLD = 1.0e-5f;
+ float vec[3], bone_mat[3][3], vec2[3];
+
+ /* Compute the Y axis vector. */
+ sub_v3_v3v3(vec, tail, head);
+ normalize_v3(vec);
+
+ /* Only correct when in the danger zone. */
+ if (1.0f + vec[1] < SAFE_THRESHOLD * 2 && (vec[0] || vec[2])) {
+ /* Use the armature matrix to double-check if adjustment is needed.
+ * This should minimize issues if the file is bounced back and forth between
+ * 2.92 and 2.91, provided Edit Mode isn't entered on the armature in 2.91. */
+ vec_roll_to_mat3(vec, *r_roll, bone_mat);
+
+ BLI_assert(dot_v3v3(bone_mat[1], check_y_axis) > 0.999f);
+
+ if (dot_v3v3(bone_mat[0], check_x_axis) < 0.999f) {
+ /* Recompute roll using legacy code to interpret the old value. */
+ legacy_vec_roll_to_mat3_normalized(vec, *r_roll, bone_mat);
+ mat3_to_vec_roll(bone_mat, vec2, r_roll);
+ BLI_assert(compare_v3v3(vec, vec2, FLT_EPSILON));
+ }
+ }
+}
+
+/* Update the armature Bone roll fields for bones very close to -Y direction. */
+static void do_version_bones_roll(ListBase *lb)
+{
+ LISTBASE_FOREACH (Bone *, bone, lb) {
+ /* Parent-relative orientation (used for posing). */
+ correct_bone_roll_value(
+ bone->head, bone->tail, bone->bone_mat[0], bone->bone_mat[1], &bone->roll);
+
+ /* Absolute orientation (used for Edit mode). */
+ correct_bone_roll_value(
+ bone->arm_head, bone->arm_tail, bone->arm_mat[0], bone->arm_mat[1], &bone->arm_roll);
+
+ do_version_bones_roll(&bone->childbase);
+ }
+}
+
/* NOLINTNEXTLINE: readability-function-size */
void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
{
@@ -1839,18 +1946,7 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
- /**
- * Versioning code until next subversion bump goes here.
- *
- * \note Be sure to check when bumping the version:
- * - "versioning_userdef.c", #blo_do_versions_userdef
- * - "versioning_userdef.c", #do_versions_theme
- *
- * \note Keep this message at the bottom of the function.
- */
- {
- /* Keep this block, even when empty. */
-
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 36)) {
/* Update the `idnames` for renamed geometry and function nodes. */
LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
if (ntree->type != NTREE_GEOMETRY) {
@@ -1871,5 +1967,23 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
version_node_id(ntree, GEO_NODE_SET_MATERIAL, "GeometryNodeSetMaterial");
version_node_id(ntree, GEO_NODE_SPLIT_EDGES, "GeometryNodeSplitEdges");
}
+
+ /* Update bone roll after a fix to vec_roll_to_mat3_normalized. */
+ LISTBASE_FOREACH (bArmature *, arm, &bmain->armatures) {
+ do_version_bones_roll(&arm->bonebase);
+ }
+ }
+
+ /**
+ * Versioning code until next subversion bump goes here.
+ *
+ * \note Be sure to check when bumping the version:
+ * - "versioning_userdef.c", #blo_do_versions_userdef
+ * - "versioning_userdef.c", #do_versions_theme
+ *
+ * \note Keep this message at the bottom of the function.
+ */
+ {
+ /* Keep this block, even when empty. */
}
}