Skip to content

Commit

Permalink
Refactor BindPose code
Browse files Browse the repository at this point in the history
  • Loading branch information
thojmr committed May 8, 2022
1 parent b338daa commit 4bf69bd
Show file tree
Hide file tree
Showing 8 changed files with 243 additions and 231 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ internal async Task<bool> GetFilteredVerticieIndexes(SkinnedMeshRenderer smr, st

//Since the z limit check is done on the unskinned verts, we need to apply any bindpose scale to the limit to make it match the real unskinned vert positions
// Note: I bet rotated meshes are similarily affected, but that's a lot of math to correct
var bindPoseScaleZ = Matrix.GetScale(MeshSkinning.GetBindPoseScale(smr).inverse).z;
var bindPoseScaleZ = Matrix.GetScale(BindPose.GetScale(smr).inverse).z;
//The distance backwards from characters center that verts are allowed to be modified
var backExtent = bindPoseScaleZ * -bellyInfo.ZLimit;
var debugAnyVerts = PregnancyPlusPlugin.MakeBalloon.Value || PregnancyPlusPlugin.DebugVerts.Value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -387,9 +387,9 @@ internal async Task ComputeBindPoseMesh(SkinnedMeshRenderer smr, SkinnedMeshRend
//Plugin config option lets us visalize bindpose positions
if (PregnancyPlusPlugin.ShowBindPose.Value)
{
MeshSkinning.ShowBindPose(ChaControl, smr, bindPoseList);
PostInflationDebug.ShowBindPose(ChaControl, smr, bindPoseList);
//The raw bindpose is the original one, that is not aligned by Preg+ yet
MeshSkinning.ShowRawBindPose(smr);
PostInflationDebug.ShowRawBindPose(smr);
}

//Matricies used to compute the T-pose mesh
Expand All @@ -410,7 +410,7 @@ internal async Task ComputeBindPoseMesh(SkinnedMeshRenderer smr, SkinnedMeshRend

//Since the z limit check is done on the unskinned verts, we need to apply any bindpose scale to the limit to make it match the real unskinned vert positions
// Note: I bet rotated meshes are similarily affected, but that's a lot of math to correct
var bindPoseScaleZ = Matrix.GetScale(MeshSkinning.GetBindPoseScale(smr).inverse).z;
var bindPoseScaleZ = Matrix.GetScale(BindPose.GetScale(smr).inverse).z;
//The distance backwards from characters center that verts are allowed to be modified
var backExtent = bindPoseScaleZ * -bellyInfo.ZLimit;

Expand Down Expand Up @@ -771,7 +771,11 @@ internal async Task ComputeDeltas(SkinnedMeshRenderer smr, string rendererName,
if (_md.HasDeltas && !meshInflateFlags.OverWriteMesh) return;

//When SMR has local rotation undo it in the deltas, Or if a bindpose is rotated undo that as well
var rotationUndo = Matrix4x4.TRS(Vector3.zero, smr.transform.localRotation, Vector3.one).inverse * Matrix4x4.TRS(Vector3.zero, MeshSkinning.GetBindPoseRotation(smr), Vector3.one);
var bindPoseRotation = BindPose.GetAverageRotation(smr);
if (PregnancyPlusPlugin.DebugLog.Value && bindPoseRotation != Quaternion.identity)
PregnancyPlusPlugin.Logger.LogWarning($" {smr.name} has bindpose rotation {bindPoseRotation}");

var rotationUndo = Matrix4x4.TRS(Vector3.zero, smr.transform.localRotation, Vector3.one).inverse * Matrix4x4.TRS(Vector3.zero, bindPoseRotation, Vector3.one);

//Get the virtual inflated mesh with normal, and tangent recalculation applied
var inflatedMesh = PrepForBlendShape(smr, rendererName, rotationUndo);
Expand All @@ -780,7 +784,7 @@ internal async Task ComputeDeltas(SkinnedMeshRenderer smr, string rendererName,
if (PregnancyPlusPlugin.DebugCalcs.Value) PregnancyPlusPlugin.Logger.LogInfo($" Compute BlendShape Deltas for {smr.name}");

//When a smr bindpose has scale, we need to undo it in the delta similar to rotation
var scaleUndo = MeshSkinning.GetBindPoseScale(smr).inverse;
var scaleUndo = BindPose.GetScale(smr).inverse;
var undoTfMatrix = rotationUndo * scaleUndo;

// if (PregnancyPlusPlugin.DebugLog.Value && scaleUndo != Matrix4x4.identity)
Expand Down
1 change: 1 addition & 0 deletions PregnancyPlus/PregnancyPlus.Core/Shared.projitems
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
<Compile Include="..\PregnancyPlus.Core\tools\Smoothing\SmoothMesh.cs" />
<Compile Include="..\PregnancyPlus.Core\Tools\MeshInflateFlags.cs" />
<Compile Include="..\PregnancyPlus.Core\Tools\BindPose\Matrix.cs" />
<Compile Include="..\PregnancyPlus.Core\Tools\BindPose\BindPose.cs" />
<Compile Include="..\PregnancyPlus.Core\Tools\MeshData.cs" />
<Compile Include="..\PregnancyPlus.Core\Tools\BindPose\MeshSkinning.cs" />
<Compile Include="..\PregnancyPlus.Core\Tools\BindPose\BindPoseList.cs" />
Expand Down
90 changes: 90 additions & 0 deletions PregnancyPlus/PregnancyPlus.Core/tools/BindPose/BindPose.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
using UnityEngine;


//Contains methods to extract bindpose data from a mesh
public static class BindPose
{

/// <summary>
/// Get a bindpose matrix of a single SMR bone
/// </summary>
public static Matrix4x4 GetBindPose(Matrix4x4 smrMatrix, Matrix4x4 bindPose)
{
return smrMatrix * bindPose.inverse;
}

//Overload for the above using a SMR directly
public static Matrix4x4 GetBindPose(SkinnedMeshRenderer smr, Matrix4x4 bindPose)
{
return GetBindPose(smr.transform.localToWorldMatrix, bindPose);
}


/// <summary>
/// Get the scale from the first bindpose matrix
/// </summary>
public static Matrix4x4 GetScale(SkinnedMeshRenderer smr)
{
if (smr == null)
return Matrix4x4.identity;

//For a bindpose check for scale (just grab the first if any exists)
var bindposes = smr.sharedMesh.bindposes;
if (bindposes.Length <= 0)
return Matrix4x4.identity;

//Note: This assumes the scale is the same for all bindposes. It's worked so far ...
return Matrix.GetScaleOnlyMatrix(bindposes[0]);
}


/// <summary>
/// Get the worldspace rotation of a bindpose
/// </summary>
public static Quaternion GetRotation(SkinnedMeshRenderer smr, Matrix4x4 bindpose)
{
return Matrix.GetRotation(smr.transform.localToWorldMatrix * bindpose.inverse);
}


/// <summary>
/// Get the average rotation of all the bindposes in localspace
/// </summary>
public static Quaternion GetAverageRotation(SkinnedMeshRenderer smr)
{
//For a bindpose check for any non 0 rotation repeated more than a few times
var bindposes = smr.sharedMesh.bindposes;
var totalX = 0f;
var totalY = 0f;
var totalZ = 0f;
var totalW = 0f;

//Add up all the rotations for each bindpose
for (int i = 0; i < bindposes.Length; i++)
{
var bindposeRotation = GetRotation(smr, bindposes[i]);
//We want to ignore character rotation, so convert to local rotation
var localRotation = Quaternion.Inverse(smr.transform.rotation) * bindposeRotation;

//Round them to the nearest 90 degree axis since most offset rotations are at 90 degree intervals
var currentRotation = Rotation.AxisRound(localRotation);
totalX+=currentRotation.x;
totalY+=currentRotation.y;
totalZ+=currentRotation.z;
totalW+=currentRotation.w;
}

//Compute the average rotation
var averageRotation = new Quaternion(
x: totalX/bindposes.Length,
y: totalY/bindposes.Length,
z: totalZ/bindposes.Length,
w: totalW/bindposes.Length
);

//Round the final rotation to the nearest 90 degree axis
var roundedRotation = Rotation.AxisRound(averageRotation);

return roundedRotation;
}
}
97 changes: 46 additions & 51 deletions PregnancyPlus/PregnancyPlus.Core/tools/BindPose/Matrix.cs
Original file line number Diff line number Diff line change
@@ -1,57 +1,52 @@
using UnityEngine;

namespace KK_PregnancyPlus
{

//Typical matrix methods, but some of these do not exist in unity 5.2 (KK)
public static class Matrix
{

/// <summary>
/// Returns the position Vector3 of a Matrix4x4
/// </summary>
public static Vector3 GetPosition(Matrix4x4 matrix)
{
return matrix.GetColumn(3);
}


/// <summary>
/// Returns the rotation Quaternion of a Matrix4x4
/// </summary>
public static Quaternion GetRotation(Matrix4x4 matrix)
{
return Quaternion.LookRotation(matrix.GetColumn(2), matrix.GetColumn(1));
}


/// <summary>
/// Returns the scale Vector3 of a Matrix4x4
/// </summary>
public static Vector3 GetScale(Matrix4x4 matrix)
{
var scaleMatrix = GetScaleMatrix(matrix);
return new Vector3(scaleMatrix.m00, scaleMatrix.m11, scaleMatrix.m22);
}


/// <summary>
/// Returns the scale of a Matrix4x4, excluding position and rotation
/// </summary>
public static Matrix4x4 GetScaleMatrix(Matrix4x4 matrix)
{
return GetPositionAndRotationMatrrix(matrix).inverse * matrix;
}


/// <summary>
/// Get position and rotation, excluding scale of a Matrix4x4
/// </summary>
public static Matrix4x4 GetPositionAndRotationMatrrix(Matrix4x4 matrix)
{
return Matrix4x4.TRS(GetPosition(matrix), GetRotation(matrix), Vector3.one);
}

//Typical matrix methods, but some of these do not exist in unity 5.2 (KK)
public static class Matrix
{
/// <summary>
/// Returns the position in Vector3 of a Matrix4x4
/// </summary>
public static Vector3 GetPosition(Matrix4x4 matrix)
{
return matrix.GetColumn(3);
}


/// <summary>
/// Returns the rotation as Quaternion of a Matrix4x4
/// </summary>
public static Quaternion GetRotation(Matrix4x4 matrix)
{
return Quaternion.LookRotation(matrix.GetColumn(2), matrix.GetColumn(1));
}


/// <summary>
/// Returns the scale as Vector3 of a scale only Matrix4x4
/// </summary>
public static Vector3 GetScale(Matrix4x4 matrix)
{
var scaleMatrix = GetScaleOnlyMatrix(matrix);
return new Vector3(scaleMatrix.m00, scaleMatrix.m11, scaleMatrix.m22);
}


/// <summary>
/// Returns the scale of a Matrix4x4, excluding position and rotation
/// </summary>
public static Matrix4x4 GetScaleOnlyMatrix(Matrix4x4 matrix)
{
return GetPositionAndRotationMatrix(matrix).inverse * matrix;
}


/// <summary>
/// Get position and rotation, excluding scale of a Matrix4x4
/// </summary>
public static Matrix4x4 GetPositionAndRotationMatrix(Matrix4x4 matrix)
{
return Matrix4x4.TRS(GetPosition(matrix), GetRotation(matrix), Vector3.one);
}

}
Loading

0 comments on commit 4bf69bd

Please sign in to comment.