WuhuIslandTesting/Library/PackageCache/com.stresslevelzero.marrow.sdk@1.2.0/Scripts/SLZ.Marrow/SLZ.VRMK/AvatarSoftBody.cs
2025-01-07 02:06:59 +01:00

343 lines
No EOL
18 KiB
C#

using UnityEngine;
namespace SLZ.VRMK
{
public partial class Avatar : MonoBehaviour
{
[System.Serializable]
public struct SoftEllipse
{
public struct Constants
{
public const float RadiusMin = 0.01f;
public const float RadiusMax = 0.1f;
public const float RadiusDefault = 0.03f;
public const float BiasMin = -1f;
public const float BiasMax = 1f;
public const float BiasDefault = 0f;
}
[Range(Constants.RadiusMin, Constants.RadiusMax)]
public float XRadius;
[Range(Constants.BiasMin, Constants.BiasMax)]
public float XBias;
[Range(Constants.RadiusMin, Constants.RadiusMax)]
public float ZRadius;
[Range(Constants.BiasMin, Constants.BiasMax)]
public float ZBias;
public SoftEllipse(float xRadius = Constants.RadiusDefault, float xBias = Constants.BiasDefault, float zRadius = Constants.RadiusDefault, float zBias = Constants.BiasDefault)
{
XRadius = xRadius;
XBias = xBias;
ZRadius = zRadius;
ZBias = zBias;
}
}
[System.Serializable]
public class SoftBulge
{
[Range(0f, 90f)]
public float apexX;
[Range(.01f, .99f)]
public float apexY;
[Range(0f, .08f)]
public float apexZ;
[Range(0f, 1f)]
public float upperY;
[Range(0f, 1f)]
public float lowerY;
[Range(0f, 80f)]
public float innerX;
[Range(0f, 80f)]
public float outerX;
[Range(0f, 1f)]
public float roundUpperInner;
[Range(0f, 1f)]
public float roundUpperOuter;
[Range(0f, 1f)]
public float roundLowerInner;
[Range(0f, 1f)]
public float roundLowerOuter;
[Range(0f, .5f)]
public float swellUpper;
[Range(0f, .5f)]
public float swellLower;
[Range(0f, .5f)]
public float swellInner;
[Range(0f, .5f)]
public float swellOuter;
[Range(0f, 1f)]
public float rigidity;
public Transform primaryRt;
public Transform secondaryLf;
public Vector3 ComputeBulge(float yPerc, Vector2 sin, float bulgeYTop, float bulgeYBot, bool onBack)
{
float apexYAbs = Mathf.LerpUnclamped(bulgeYTop, bulgeYBot, apexY);
float topToBotDiff = bulgeYBot - bulgeYTop;
float minY = apexYAbs - (topToBotDiff * apexY) * upperY;
float maxY = apexYAbs + (topToBotDiff * (1f - apexY)) * lowerY;
if (onBack)
sin.y = -sin.y;
if (yPerc > maxY || yPerc < minY)
return Vector3.zero;
float yMultInv = 0f;
float xMultInv = 0f;
float xOffset = 0f;
float yOffset = 0f;
float zOffset = 0f;
float innerRadians = (apexX - innerX) * Mathf.Deg2Rad;
float apexRadians = apexX * Mathf.Deg2Rad;
float outerRadians = (apexX + outerX) * Mathf.Deg2Rad;
float innerSin = Mathf.Sin(innerRadians);
float apexCos = Mathf.Cos(apexRadians);
float apexSin = Mathf.Sin(apexRadians);
float outerCos = Mathf.Cos(outerRadians);
if (yPerc < apexYAbs)
{
float yMult = Mathf.InverseLerp(apexYAbs, minY, yPerc);
yMultInv = 1f - yMult;
if (sin.y < apexCos)
{
float xMult = Mathf.InverseLerp(apexCos, Mathf.LerpUnclamped(outerCos, apexCos, yMult * yMult * roundUpperOuter), sin.y);
xMultInv = 1f - xMult;
float swellXMult = Mathf.Abs(xMult - .5f) * 2f;
swellXMult = 1f - (swellXMult * swellXMult);
float swellX = swellOuter * apexZ * swellXMult * yMultInv;
zOffset += swellX;
xOffset += swellX;
}
else
{
float xMult = Mathf.InverseLerp(apexSin, Mathf.LerpUnclamped(innerSin, apexSin, yMult * yMult * roundUpperInner), Mathf.Abs(sin.x));
xMultInv = 1f - xMult;
float swellXMult = Mathf.Abs(xMult - .5f) * 2f;
swellXMult = 1f - (swellXMult * swellXMult);
float swellX = swellInner * apexZ * swellXMult * yMultInv;
zOffset += swellX;
xOffset -= swellX;
}
float swellYMult = Mathf.Abs(yMult - .5f) * 2f;
swellYMult = 1f - (swellYMult * swellYMult);
float swellY = swellUpper * apexZ * swellYMult * xMultInv;
zOffset += swellY;
yOffset += swellY;
}
else
{
float yMult = Mathf.InverseLerp(apexYAbs, maxY, yPerc);
yMultInv = 1f - yMult;
if (sin.y < apexCos)
{
float xMult = Mathf.InverseLerp(apexCos, Mathf.LerpUnclamped(outerCos, apexCos, yMult * yMult * roundLowerOuter), sin.y);
xMultInv = 1f - xMult;
float swellXMult = Mathf.Abs(xMult - .5f) * 2f;
swellXMult = 1f - (swellXMult * swellXMult);
float swellX = swellOuter * apexZ * swellXMult * yMultInv;
zOffset += swellX;
xOffset += swellX;
}
else
{
float xMult = Mathf.InverseLerp(apexSin, Mathf.LerpUnclamped(innerSin, apexSin, yMult * yMult * roundLowerInner), Mathf.Abs(sin.x));
xMultInv = 1f - xMult;
float swellXMult = Mathf.Abs(xMult - .5f) * 2f;
swellXMult = 1f - (swellXMult * swellXMult);
float swellX = swellInner * apexZ * swellXMult * yMultInv;
zOffset += swellX;
xOffset -= swellX;
}
float swellYMult = Mathf.Abs(yMult - .5f) * 2f;
swellYMult = 1f - (swellYMult * swellYMult);
float swellY = swellLower * apexZ * swellYMult * xMultInv;
zOffset += swellY;
yOffset -= swellY;
}
Vector3 softOffset = new Vector3((apexZ * yMultInv * xMultInv + zOffset) * sin.x, yOffset, (apexZ * yMultInv * xMultInv + zOffset) * sin.y);
softOffset.x += xOffset * sin.y * Mathf.Sign(sin.x);
softOffset.z += xOffset * sin.x * Mathf.Sign(sin.x);
if (onBack)
softOffset.z = -softOffset.z;
return softOffset;
}
public SoftBulge()
{
this.apexX = 26f;
this.apexY = .5f;
this.apexZ = 0f;
this.upperY = 1f;
this.lowerY = 1f;
this.innerX = 26f;
this.outerX = 32f;
this.roundUpperInner = .1f;
this.roundUpperOuter = 0f;
this.roundLowerInner = .9f;
this.roundLowerOuter = .4f;
this.swellUpper = .1f;
this.swellLower = .2f;
this.swellInner = .2f;
this.swellOuter = .1f;
this.rigidity = .5f;
}
public void Copy(SoftBulge bulge)
{
apexX = bulge.apexX;
apexY = bulge.apexY;
apexZ = bulge.apexZ;
upperY = bulge.upperY;
lowerY = bulge.lowerY;
innerX = bulge.innerX;
outerX = bulge.outerX;
roundUpperInner = bulge.roundUpperInner;
roundUpperOuter = bulge.roundUpperOuter;
roundLowerInner = bulge.roundLowerInner;
roundLowerOuter = bulge.roundLowerOuter;
swellUpper = bulge.swellUpper;
swellLower = bulge.swellLower;
swellInner = bulge.swellInner;
swellOuter = bulge.swellOuter;
rigidity = bulge.rigidity;
}
}
public Vector3 GetSoftTorso(float yPerc, Vector2 sin, AnimationCurve ellipseX, AnimationCurve ellipseZ, AnimationCurve ellipseNegZ, out Vector3 softDisplacement)
{
float x = ellipseX.Evaluate(yPerc);
float xDeriv = Derivative(ellipseX, yPerc);
float z;
float zDeriv;
if (sin.y >= 0f)
{
z = ellipseZ.Evaluate(yPerc);
zDeriv = Derivative(ellipseZ, yPerc);
}
else
{
z = ellipseNegZ.Evaluate(yPerc);
zDeriv = Derivative(ellipseNegZ, yPerc);
}
Vector3 torsoCoords = new Vector3(x * sin.x, 0f, z * sin.y);
Vector3 breastDisplacement = bulgeBreast.ComputeBulge(yPerc, sin, 0f, UnderbustY, false);
torsoCoords += breastDisplacement * bulgeBreast.rigidity;
softDisplacement = breastDisplacement * (1f - bulgeBreast.rigidity);
Vector3 upperBackDisplacement = bulgeUpperBack.ComputeBulge(yPerc, sin, 0f, UnderbustY, true);
torsoCoords += upperBackDisplacement * bulgeUpperBack.rigidity;
softDisplacement += upperBackDisplacement * (1f - bulgeUpperBack.rigidity);
Vector3 abdomenDisplacement = bulgeAbdomen.ComputeBulge(yPerc, sin, UnderbustY, HighHipsY, false);
torsoCoords += abdomenDisplacement * bulgeAbdomen.rigidity;
softDisplacement += abdomenDisplacement * (1f - bulgeAbdomen.rigidity);
Vector3 lowBackDisplacement = bulgeLowerBack.ComputeBulge(yPerc, sin, UnderbustY, HighHipsY, true);
torsoCoords += lowBackDisplacement * bulgeLowerBack.rigidity;
softDisplacement += lowBackDisplacement * (1f - bulgeLowerBack.rigidity);
Vector3 groinDisplacement = bulgeGroin.ComputeBulge(yPerc, sin, HighHipsY, 2f, false);
torsoCoords += groinDisplacement * bulgeGroin.rigidity;
softDisplacement += groinDisplacement * (1f - bulgeGroin.rigidity);
Vector3 buttDisplacement = bulgeButt.ComputeBulge(yPerc, sin, HighHipsY, 2f, true);
torsoCoords += buttDisplacement * bulgeButt.rigidity;
softDisplacement += buttDisplacement * (1f - bulgeButt.rigidity);
return torsoCoords;
}
public AnimationCurve GenerateSpineCurve(float eyeHeight, Vector3 t7Local, Vector3 l1Local, Vector3 l3Local, Vector3 sacrumLocal, Vector3 sternumOffsetPerc, Vector3 hipsOffsetPerc, float t1HeightPerc)
{
float neckT = Mathf.Lerp(0f, -1f, -sternumOffsetPerc.y / (1f - (t1HeightPerc + sternumOffsetPerc.y)));
neckT = Mathf.Min(neckT, -.15f);
float jawT = Mathf.Lerp(-1f, 0f, _chinY * .6f / (1f - (t1HeightPerc + sternumOffsetPerc.y)));
jawT = Mathf.Min(jawT, neckT - .05f);
float divByEyeHeight = 1f / eyeHeight;
Vector3 t7Perc = t7Local * divByEyeHeight;
Vector3 l1Perc = l1Local * divByEyeHeight;
Vector3 l3Perc = l3Local * divByEyeHeight;
Vector3 sacrumPerc = sacrumLocal * divByEyeHeight;
Vector3 t7PercLessSacrum = -sternumOffsetPerc + t7Perc;
Vector3 totalThorLumbar = t7Perc + l1Perc + l3Perc + sacrumPerc;
Vector3 totalSternumToHip = -sternumOffsetPerc + totalThorLumbar + hipsOffsetPerc;
float upperChestT = t7PercLessSacrum.y / totalSternumToHip.y;
Vector3 upperChestOffset = t7PercLessSacrum - (totalSternumToHip * upperChestT);
float chestT = (t7PercLessSacrum.y + l1Perc.y) / totalSternumToHip.y;
Vector3 chestOffset = t7PercLessSacrum + l1Perc - (totalSternumToHip * chestT);
float spineT = (t7PercLessSacrum.y + l1Perc.y + l3Perc.y) / totalSternumToHip.y;
Vector3 spineOffset = t7PercLessSacrum + l1Perc + l3Perc - (totalSternumToHip * spineT);
_t7Y = upperChestT;
_t7OffsetZ = upperChestOffset.z;
_l1Y = chestT;
_l1OffsetZ = chestOffset.z;
_l3Y = spineT;
_l3OffsetZ = spineOffset.z;
float underbustZOffset = (_chestEllipseZ - _chestEllipseNegZ) * .2f;
float waistZOffset = (_waistEllipseZ - _waistEllipseNegZ) * .4f;
float highHipsZOffset = (_highHipsEllipseZ - _highHipsEllipseNegZ) * .4f;
AnimationCurve spine = new AnimationCurve(new Keyframe(-2f, 0f, 0f, 0f, 0f, 0f), new Keyframe(-1.4f, 0f, 0f, 0f, 0f, 0f), new Keyframe(jawT, 0f, 0f, 0f, 0f, 0f), new Keyframe(neckT, 0f, 0f, 0f, 0f, 0f), new Keyframe(0f, 0f, 0f, 0f, 0f, 0f), new Keyframe(_underbustY, underbustZOffset, 0f, 0f, 0f, 0f), new Keyframe(_waistY, waistZOffset, 0f, 0f, 0f, 0f), new Keyframe(_highHipY, highHipsZOffset, 0f, 0f, 0f, 0f), new Keyframe(1f, 0f, 0f, 0f, 0f, 0f), new Keyframe(2f, 0f, 0f, 0f, 0f, 0f));
return spine;
}
public AnimationCurve GenerateTorsoZCurve(Vector3 sternumOffsetPerc, float t1HeightPerc, AnimationCurve spineZ)
{
(float neckT, float jawT) = GetNeckAndJawT(sternumOffsetPerc, t1HeightPerc);
var ellipseZ = new AnimationCurve(new Keyframe(-2f, .003f, _headEllipseZ * 3.141f, _headEllipseZ * 3.141f), new Keyframe(-1.4f, _headEllipseZ - spineZ.Evaluate(-1.4f), 0f, 0f), new Keyframe(jawT, _jawEllipseZ - spineZ.Evaluate(jawT), 0f, 0f), new Keyframe(neckT, _neckEllipseZ - spineZ.Evaluate(neckT), 0f, 0f), new Keyframe(0f, _sternumEllipseZ - spineZ.Evaluate(0f), (_neckEllipseZ - _sternumEllipseZ) / neckT, (_chestEllipseZ - _sternumEllipseZ) / _underbustY), new Keyframe(_underbustY, _chestEllipseZ - spineZ.Evaluate(_underbustY), 0f, 0f), new Keyframe(_waistY, _waistEllipseZ - spineZ.Evaluate(_waistY), 0f, 0f), new Keyframe(_highHipY, _highHipsEllipseZ - spineZ.Evaluate(_highHipY), 0f, 0f), new Keyframe(1f, _hipsEllipseZ - spineZ.Evaluate(1f), (_hipsEllipseZ - _highHipsEllipseZ) * (1f - _highHipY) * 4f, (_hipsEllipseZ - _highHipsEllipseZ) * (2f - 1f)), new Keyframe(2f, .003f, _hipsEllipseZ * -3.141f, _hipsEllipseZ * -3.141f));
return ellipseZ;
}
public AnimationCurve GenerateTorsoNegZCurve(Vector3 sternumOffsetPerc, float t1HeightPerc, AnimationCurve spineZ)
{
(float neckT, float jawT) = GetNeckAndJawT(sternumOffsetPerc, t1HeightPerc);
var ellipseNegZ = new AnimationCurve(new Keyframe(-2f, .003f, _headEllipseNegZ * 3.141f, _headEllipseNegZ * 3.141f), new Keyframe(-1.4f, _headEllipseNegZ + spineZ.Evaluate(-1.4f), 0f, 0f), new Keyframe(jawT, _jawEllipseNegZ + spineZ.Evaluate(jawT), 0f, 0f), new Keyframe(neckT, _neckEllipseNegZ + spineZ.Evaluate(neckT), 0f, 0f), new Keyframe(0f, _sternumEllipseNegZ + spineZ.Evaluate(0f), 0f, 0f), new Keyframe(_underbustY, _chestEllipseNegZ + spineZ.Evaluate(_underbustY), 0f, 0f), new Keyframe(_waistY, _waistEllipseNegZ + spineZ.Evaluate(_waistY), 0f, 0f), new Keyframe(_highHipY, _highHipsEllipseNegZ + spineZ.Evaluate(_highHipY), 0f, 0f), new Keyframe(1f, _hipsEllipseNegZ + spineZ.Evaluate(1f), 0f, 0f), new Keyframe(2f, .003f, _hipsEllipseNegZ * -3.141f, _hipsEllipseNegZ * -3.141f));
return ellipseNegZ;
}
public AnimationCurve GenerateTorsoXCurve(float sternumEllipseX, float hipEllipseX, Vector3 sternumOffsetPerc, float t1HeightPerc)
{
(float neckT, float jawT) = GetNeckAndJawT(sternumOffsetPerc, t1HeightPerc);
var ellipseX = new AnimationCurve(new Keyframe(-2f, .003f, _headEllipseX * 3.141f, _headEllipseX * 3.141f), new Keyframe(-1.4f, _headEllipseX, 0f, 0f), new Keyframe(jawT, _jawEllipseX, 0f, 0f), new Keyframe(neckT, _neckEllipseX, 0f, 0f), new Keyframe(0f, sternumEllipseX, 0f, 0f), new Keyframe(_underbustY, _chestEllipseX, 0f, 0f), new Keyframe(_waistY, _waistEllipseX, 0f, 0f), new Keyframe(_highHipY, _highHipsEllipseX, 0f, 0f), new Keyframe(1f, _hipsEllipseX, 0f, 0f), new Keyframe(2f, hipEllipseX, (_hipsEllipseX - hipEllipseX) * -3.141f, (_hipsEllipseX - hipEllipseX) * -3.141f));
return ellipseX;
}
private (float, float) GetNeckAndJawT(Vector3 sternumOffsetPerc, float t1HeightPerc)
{
float neckT = Mathf.Lerp(0f, -1f, -sternumOffsetPerc.y / (1f - (t1HeightPerc + sternumOffsetPerc.y)));
neckT = Mathf.Min(neckT, -.15f);
float jawT = Mathf.Lerp(-1f, 0f, _chinY * .6f / (1f - (t1HeightPerc + sternumOffsetPerc.y)));
jawT = Mathf.Min(jawT, neckT - .05f);
return (neckT, jawT);
}
public float Derivative(AnimationCurve self, float time)
{
if (self == null)
return 0.0f;
for (int i = 0; i < self.length - 1; i++)
{
if (time < self[i].time)
continue;
if (time > self[i + 1].time)
continue;
return Derivative(self[i], self[i + 1], (time - self[i].time) / (self[i + 1].time - self[i].time));
}
return 0.0f;
}
private float Derivative(Keyframe from, Keyframe to, float lerp)
{
float dt = to.time - from.time;
float m0 = from.outTangent * dt;
float m1 = to.inTangent * dt;
float lerp2 = lerp * lerp;
float a = 6.0f * lerp2 - 6.0f * lerp;
float b = 3.0f * lerp2 - 4.0f * lerp + 1.0f;
float c = 3.0f * lerp2 - 2.0f * lerp;
float d = -a;
return a * from.value + b * m0 + c * m1 + d * to.value;
}
}
}