Files
2026-03-04 09:37:33 +08:00

106 lines
2.9 KiB
C#

using System;
using UnityEngine;
namespace RootMotion.FinalIK
{
public class PenetrationAvoidance : OffsetModifier
{
[Serializable]
public class Avoider
{
[Serializable]
public class EffectorLink
{
[Tooltip("Effector to apply the offset to.")]
public FullBodyBipedEffector effector;
[Tooltip("Multiplier of the offset value, can be negative.")]
public float weight;
}
[Tooltip("Bones to start the raycast from. Multiple raycasts can be used by assigning more than 1 bone.")]
public Transform[] raycastFrom;
[Tooltip("The Transform to raycast towards. Usually the body part that you want to keep from penetrating.")]
public Transform raycastTo;
[Tooltip("If 0, will use simple raycasting, if > 0, will use sphere casting (better, but slower).")]
[Range(0f, 1f)]
public float raycastRadius;
[Tooltip("Linking this to FBBIK effectors.")]
public EffectorLink[] effectors;
[Tooltip("The time of smooth interpolation of the offset value to avoid penetration.")]
public float smoothTimeIn = 0.1f;
[Tooltip("The time of smooth interpolation of the offset value blending out of penetration avoidance.")]
public float smoothTimeOut = 0.3f;
[Tooltip("Layers to keep penetrating from.")]
public LayerMask layers;
private Vector3 offset;
private Vector3 offsetTarget;
private Vector3 offsetV;
public void Solve(IKSolverFullBodyBiped solver, float weight)
{
offsetTarget = GetOffsetTarget(solver);
float smoothTime = ((offsetTarget.sqrMagnitude > offset.sqrMagnitude) ? smoothTimeIn : smoothTimeOut);
offset = Vector3.SmoothDamp(offset, offsetTarget, ref offsetV, smoothTime);
EffectorLink[] array = effectors;
foreach (EffectorLink effectorLink in array)
{
solver.GetEffector(effectorLink.effector).positionOffset += offset * weight * effectorLink.weight;
}
}
private Vector3 GetOffsetTarget(IKSolverFullBodyBiped solver)
{
Vector3 zero = Vector3.zero;
Transform[] array = raycastFrom;
foreach (Transform transform in array)
{
zero += Raycast(transform.position, raycastTo.position + zero);
}
return zero;
}
private Vector3 Raycast(Vector3 from, Vector3 to)
{
Vector3 direction = to - from;
float magnitude = direction.magnitude;
RaycastHit hitInfo;
if (raycastRadius <= 0f)
{
Physics.Raycast(from, direction, out hitInfo, magnitude, layers);
}
else
{
Physics.SphereCast(from, raycastRadius, direction, out hitInfo, magnitude, layers);
}
if (hitInfo.collider == null)
{
return Vector3.zero;
}
return Vector3.Project(-direction.normalized * (magnitude - hitInfo.distance), hitInfo.normal);
}
}
[Tooltip("Definitions of penetration avoidances.")]
public Avoider[] avoiders;
protected override void OnModifyOffset()
{
Avoider[] array = avoiders;
for (int i = 0; i < array.Length; i++)
{
array[i].Solve(ik.solver, weight);
}
}
}
}