[DesktopVRIK] Attempt at fixing BodyHeadingOffset & IsStanding when _PLAYERLOCAL is upsidedown.

Can't really test at different angles because movement system does not rotate player on local Y axis, it is world axis always.
This commit is contained in:
NotAKidoS 2023-06-13 18:47:04 -05:00
parent d0724cc56a
commit db640b2821

View file

@ -91,10 +91,13 @@ internal class DesktopVRIKSystem : MonoBehaviour
// Let AMT handle it if available // Let AMT handle it if available
if (DesktopVRIK.EntryIntegrationAMT.Value) return true; if (DesktopVRIK.EntryIntegrationAMT.Value) return true;
// Get Upright value // Convert head position to avatar's local coordinate system
Vector3 delta = cachedSolver.Spine.headPosition - avatarTransform.position; Vector3 headPositionInAvatarLocal = avatarTransform.InverseTransformPoint(cachedSolver.Spine.headPosition);
Vector3 deltaRotated = Quaternion.Euler(0, avatarTransform.rotation.eulerAngles.y, 0) * delta;
float upright = Mathf.InverseLerp(0f, calibrationData.InitialHeadHeight * _scaleDifference, deltaRotated.y); // Get Upright value (assuming avatar's local up is its standing direction)
float distance = headPositionInAvatarLocal.y;
float upright = Mathf.InverseLerp(0f, calibrationData.InitialHeadHeight * _scaleDifference, Mathf.Abs(distance));
return upright > 0.85f; return upright > 0.85f;
} }
@ -263,6 +266,8 @@ internal class DesktopVRIKSystem : MonoBehaviour
// Apply custom VRIK solving effects // Apply custom VRIK solving effects
IKBodyLeaningOffset(_ikWeightLerp); IKBodyLeaningOffset(_ikWeightLerp);
IKBodyHeadingOffset(_ikWeightLerp); IKBodyHeadingOffset(_ikWeightLerp);
}
void IKBodyLeaningOffset(float weight) void IKBodyLeaningOffset(float weight)
{ {
@ -280,37 +285,57 @@ internal class DesktopVRIKSystem : MonoBehaviour
void IKBodyHeadingOffset(float weight) void IKBodyHeadingOffset(float weight)
{ {
// Make root heading follow within a set limit // Make root heading follow within a set limit
if (DesktopVRIK.EntryBodyHeadingLimit.Value <= 0) return; if (DesktopVRIK.EntryBodyHeadingLimit.Value <= 0)
{
// reset when value is 0
cachedSolver.Spine.rootHeadingOffset = 0f;
return;
}
// Get the real localYRotation
Vector3 projectedForward = Vector3.ProjectOnPlane(transform.forward, transform.up);
Vector3 worldProjectedForward = Vector3.ProjectOnPlane(Vector3.forward, transform.up);
float localYRotation = Vector3.SignedAngle(projectedForward, worldProjectedForward, transform.up);
if (localYRotation < 0) localYRotation += 360;
float weightedAngleLimit = DesktopVRIK.EntryBodyHeadingLimit.Value * weight; float weightedAngleLimit = DesktopVRIK.EntryBodyHeadingLimit.Value * weight;
float deltaAngleRoot = Mathf.DeltaAngle(transform.eulerAngles.y, _ikSimulatedRootAngle); float deltaAngleRoot = Mathf.DeltaAngle(_ikSimulatedRootAngle, localYRotation);
float absDeltaAngleRoot = Mathf.Abs(deltaAngleRoot);
float absDeltaAngleRoot = Mathf.Abs(deltaAngleRoot);
if (absDeltaAngleRoot > weightedAngleLimit) if (absDeltaAngleRoot > weightedAngleLimit)
{ {
deltaAngleRoot = Mathf.Sign(deltaAngleRoot) * weightedAngleLimit; deltaAngleRoot = Mathf.Sign(deltaAngleRoot) * weightedAngleLimit;
_ikSimulatedRootAngle = Mathf.MoveTowardsAngle(_ikSimulatedRootAngle, transform.eulerAngles.y, absDeltaAngleRoot - weightedAngleLimit); _ikSimulatedRootAngle = Mathf.MoveTowardsAngle(_ikSimulatedRootAngle, localYRotation, absDeltaAngleRoot - weightedAngleLimit);
} }
cachedSolver.Spine.rootHeadingOffset = deltaAngleRoot; cachedSolver.Spine.rootHeadingOffset = deltaAngleRoot;
if (DesktopVRIK.EntryPelvisHeadingWeight.Value > 0) float pelvisHeadingWeight = DesktopVRIK.EntryPelvisHeadingWeight.Value;
if (pelvisHeadingWeight > 0)
{ {
cachedSolver.Spine.pelvisRotationOffset *= Quaternion.Euler(0f, deltaAngleRoot * DesktopVRIK.EntryPelvisHeadingWeight.Value, 0f); AdjustBodyPartRotation(deltaAngleRoot * pelvisHeadingWeight, ref cachedSolver.Spine.pelvisRotationOffset);
cachedSolver.Spine.chestRotationOffset *= Quaternion.Euler(0f, -deltaAngleRoot * DesktopVRIK.EntryPelvisHeadingWeight.Value, 0f); AdjustBodyPartRotation(-deltaAngleRoot * pelvisHeadingWeight, ref cachedSolver.Spine.chestRotationOffset);
} }
if (DesktopVRIK.EntryChestHeadingWeight.Value > 0) float chestHeadingWeight = DesktopVRIK.EntryChestHeadingWeight.Value;
if (chestHeadingWeight > 0)
{ {
cachedSolver.Spine.chestRotationOffset *= Quaternion.Euler(0f, deltaAngleRoot * DesktopVRIK.EntryChestHeadingWeight.Value, 0f); AdjustBodyPartRotation(deltaAngleRoot * chestHeadingWeight, ref cachedSolver.Spine.chestRotationOffset);
} }
} }
void AdjustBodyPartRotation(float angle, ref Quaternion bodyPartRotationOffset)
{
// this has to be flipped back cause vrik dumb
Vector3 localOffset = bodyPartRotationOffset * transform.InverseTransformDirection(new Vector3(0f, angle, 0f));
bodyPartRotationOffset *= Quaternion.Euler(localOffset);
} }
public void OnPostSolverUpdate() public void OnPostSolverUpdate()
{ {
if (!DesktopVRIK.EntryNetIKPass.Value) return; if (!DesktopVRIK.EntryNetIKPass.Value) return;
Calibrator.ApplyNetIKPass(); Calibrator.ApplyNetIKPass(); // lazy cause Calibrator has humanposehandler
} }
void IKResetSolver() void IKResetSolver()