基本上我有一个 ik 脚本附加到 2 个手臂上,将它们连接到武器上,但是当我播放射击动画时,网格会奇怪地变形(只是网格而不是骨骼)。
这是 ik 求解器代码:
using System.Collections;
使用 System.Collections.Generic;使用 UnityEngine;
公共类 IKcomponent : MonoBehaviour { public int ChainLength = 2;
public Transform target;
public Transform pole;
[Header("Solver Params")]
public int iterations = 10;
public float Delta = 0.001f;
[Range(0, 1)]
public float SnapBackStrength = 1f;
protected float[] BonesLength;
protected float CompleteLength;
protected Transform[] Bones;
protected Vector3[] Positions;
protected Vector3[] StartDirectionSucc;
protected Quaternion[] StartRotationBone;
protected Quaternion StartRotationTarget;
protected Quaternion StartRotationRoot;
private void Awake()
{
Init();
}
void Init()
{
Bones = new Transform[ChainLength + 1];
Positions = new Vector3[ChainLength + 1];
BonesLength = new float[ChainLength];
StartDirectionSucc = new Vector3[ChainLength + 1];
StartRotationBone = new Quaternion[ChainLength + 1];
StartRotationTarget = target.rotation;
CompleteLength = 0;
var current = transform;
for(var i = Bones.Length - 1; i >= 0; i--)
{
Bones[i] = current;
StartRotationBone[i] = current.rotation;
if(i == Bones.Length - 1)
{
StartDirectionSucc[i] = target.position - current.position;
}
else
{
StartDirectionSucc[i] = Bones[i + 1].position - current.position;
BonesLength[i] = StartDirectionSucc[i].magnitude;
CompleteLength += BonesLength[i];
}
current = current.parent;
}
}
private void LateUpdate()
{
ResolveIK();
}
private void ResolveIK()
{
if (target == null)
return;
if (Bones.Length != ChainLength)
Init();
for (int i = 0; i < Bones.Length; i++)
Positions[i] = Bones[i].position;
var RootRot = (Bones[0].parent != null) ? Bones[0].parent.rotation : Quaternion.identity;
var RootRotDiff = RootRot * Quaternion.Inverse(StartRotationRoot);
if ((target.position - Bones[0].position).sqrMagnitude >= CompleteLength * CompleteLength)
{
var direction = (target.position - Positions[0]).normalized;
for (int i = 1; i < Positions.Length; i++)
Positions[i] = Positions[i - 1] + direction * BonesLength[i - 1];
}
else
{
for (int i = 0; i < Positions.Length - 1; i++)
Positions[i + 1] = Vector3.Lerp(Positions[i + 1], Positions[i] + RootRotDiff * StartDirectionSucc[i], SnapBackStrength);
for(int iteration = 0; iteration < iterations; iteration++)
{
for (int i = Positions.Length - 1; i > 0; i--)
{
if (i == Positions.Length - 1)
Positions[i] = target.position;
else
Positions[i] = Positions[i + 1] + (Positions[i] - Positions[i + 1]).normalized * BonesLength[i];
}
for(int i = 1; i < Positions.Length; i++)
Positions[i] = Positions[i - 1] + (Positions[i] - Positions[i - 1]).normalized * BonesLength[i-1];
if ((Positions[Positions.Length - 1] - target.position).sqrMagnitude < Delta * Delta)
break;
}
}
if(pole != null)
{
for(int i = 1; i < Positions.Length - 1; i++)
{
var plane = new Plane(Positions[i + 1] - Positions[i - 1], Positions[i - 1]);
var projectedPole = plane.ClosestPointOnPlane(pole.position);
var projectedBone = plane.ClosestPointOnPlane(Positions[i]);
var angle = Vector3.SignedAngle(projectedBone - Positions[i - 1], projectedPole - Positions[i - 1], plane.normal);
Positions[i] = Quaternion.AngleAxis(angle, plane.normal) * (Positions[i] - Positions[i - 1]) + Positions[i - 1];
}
}
for (int i = 0; i < Positions.Length; i++)
{
if (i == Positions.Length - 1)
Bones[i].rotation = target.rotation * Quaternion.Inverse(StartRotationTarget) * StartRotationBone[i];
else
Bones[i].rotation = Quaternion.FromToRotation(StartDirectionSucc[i], Positions[i + 1] - Positions[i]) * StartRotationBone[i];
Bones[i].position = Positions[i];
}
}
}