您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
207 行
6.3 KiB
207 行
6.3 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.Experimental.Animations;
|
|
|
|
public struct TwoBoneIKJob : IAnimationJob
|
|
{
|
|
TransformStreamHandle m_EndHandle;
|
|
TransformStreamHandle m_StartHandle;
|
|
TransformStreamHandle m_MidHandle;
|
|
TransformSceneHandle m_EffectorSceneHandle;
|
|
TransformStreamHandle m_EffectorStreamHandle;
|
|
PropertySceneHandle m_WeightHandle;
|
|
PropertyStreamHandle m_AnimatorWeight;
|
|
PropertySceneHandle m_AnimatorWeightOffset;
|
|
|
|
IkType m_IkType;
|
|
AvatarIKGoal m_HumanLimb;
|
|
|
|
Vector3 m_TargetOffset;
|
|
// float m_TargetOffsetX;
|
|
// float m_TargetOffsetY;
|
|
// float m_TargetOffsetZ;
|
|
//
|
|
bool m_UseStreamEffector;
|
|
bool m_UseAnimatorProperty;
|
|
|
|
public enum TargetType
|
|
{
|
|
Scene,
|
|
Stream
|
|
}
|
|
|
|
public enum IkType
|
|
{
|
|
Generic,
|
|
Humanoid
|
|
}
|
|
|
|
[Serializable]
|
|
public struct WeightProperty
|
|
{
|
|
[Range(0f, 1f)]
|
|
public float value;
|
|
public bool useAnimatorProperty;
|
|
public string propertyName;
|
|
[Range(-1f, 1f)]
|
|
public float propertyOffset;
|
|
}
|
|
|
|
[Serializable]
|
|
public struct Target
|
|
{
|
|
public Transform target;
|
|
public TargetType readFrom;
|
|
public Vector3 offset;
|
|
}
|
|
|
|
[Serializable]
|
|
public struct Driven
|
|
{
|
|
public IkType type;
|
|
public Transform genericEndJoint;
|
|
public AvatarIKGoal humanoidLimb;
|
|
}
|
|
|
|
|
|
[Serializable]
|
|
public struct IkChain
|
|
{
|
|
public Target target;
|
|
public Driven driven;
|
|
public WeightProperty weight;
|
|
|
|
public bool HasValidData()
|
|
{
|
|
if (driven.type == IkType.Generic)
|
|
{
|
|
return target.target != null && driven.genericEndJoint != null && driven.genericEndJoint.parent != null && driven.genericEndJoint.parent.parent != null;
|
|
}
|
|
if (driven.type == IkType.Humanoid)
|
|
{
|
|
return target.target != null;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public bool Setup(Animator animator, IkChain chain, Type componentType, string weightProperty, string weightOffsetProperty, string targetOffsetProperty)
|
|
{
|
|
if (!chain.HasValidData())
|
|
return false;
|
|
|
|
// Target
|
|
m_TargetOffset = chain.target.offset;
|
|
|
|
if (chain.target.readFrom == TargetType.Stream)
|
|
{
|
|
m_EffectorStreamHandle = animator.BindStreamTransform(chain.target.target);
|
|
m_UseStreamEffector = true;
|
|
}
|
|
else
|
|
{
|
|
m_EffectorSceneHandle = animator.BindSceneTransform(chain.target.target);
|
|
m_UseStreamEffector = false;
|
|
}
|
|
|
|
|
|
// Weight
|
|
if (chain.weight.useAnimatorProperty && chain.weight.propertyName != "")
|
|
{
|
|
m_AnimatorWeight = animator.BindStreamProperty(animator.transform, typeof(Animator), chain.weight.propertyName);
|
|
m_UseAnimatorProperty = true;
|
|
}
|
|
|
|
m_WeightHandle = animator.BindSceneProperty(animator.transform, componentType, weightProperty);
|
|
m_AnimatorWeightOffset = animator.BindSceneProperty(animator.transform, componentType, weightOffsetProperty);
|
|
|
|
|
|
// Driven
|
|
m_IkType = chain.driven.type;
|
|
|
|
if (m_IkType == IkType.Generic)
|
|
{
|
|
var end = chain.driven.genericEndJoint;
|
|
var mid = end.parent;
|
|
var start = mid.parent;
|
|
|
|
m_StartHandle = animator.BindStreamTransform(start);
|
|
m_MidHandle = animator.BindStreamTransform(mid);
|
|
m_EndHandle = animator.BindStreamTransform(end);
|
|
}
|
|
else
|
|
{
|
|
m_HumanLimb = chain.driven.humanoidLimb;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public void ProcessRootMotion(AnimationStream stream) { }
|
|
|
|
public void ProcessAnimation(AnimationStream stream)
|
|
{
|
|
float weight;
|
|
if (m_UseAnimatorProperty)
|
|
{
|
|
weight = m_AnimatorWeight.GetFloat(stream);
|
|
weight += m_AnimatorWeightOffset.GetFloat(stream);
|
|
weight = Mathf.Clamp01(weight);
|
|
m_WeightHandle.SetFloat(stream, weight);
|
|
}
|
|
else
|
|
{
|
|
weight = m_WeightHandle.GetFloat(stream);
|
|
}
|
|
|
|
weight = 1f;
|
|
|
|
Vector3 effectorPosition;
|
|
Quaternion effectorRotation;
|
|
if (m_UseStreamEffector)
|
|
{
|
|
effectorPosition = m_EffectorStreamHandle.GetPosition(stream);
|
|
effectorRotation = m_EffectorStreamHandle.GetRotation(stream);
|
|
}
|
|
else
|
|
{
|
|
effectorPosition = m_EffectorSceneHandle.GetPosition(stream);
|
|
effectorRotation = m_EffectorSceneHandle.GetRotation(stream);
|
|
}
|
|
|
|
effectorRotation *= Quaternion.Euler(m_TargetOffset);
|
|
|
|
// Changes to the stream seems to kill the foot ik data in the stream.
|
|
// TODO: (sunek) Get rid of this workaround once fixed in release
|
|
if (stream.isHumanStream)
|
|
{
|
|
var humanStream = stream.AsHuman();
|
|
humanStream.SetGoalPosition(AvatarIKGoal.LeftFoot, humanStream.GetGoalPosition(AvatarIKGoal.LeftFoot));
|
|
humanStream.SetGoalRotation(AvatarIKGoal.LeftFoot, humanStream.GetGoalRotation(AvatarIKGoal.LeftFoot));
|
|
humanStream.SetGoalPosition(AvatarIKGoal.RightFoot, humanStream.GetGoalPosition(AvatarIKGoal.RightFoot));
|
|
humanStream.SetGoalRotation(AvatarIKGoal.RightFoot, humanStream.GetGoalRotation(AvatarIKGoal.RightFoot));
|
|
}
|
|
|
|
|
|
if (m_IkType == IkType.Generic)
|
|
{
|
|
AnimJobUtilities.SolveTwoBoneIK(stream, m_StartHandle, m_MidHandle, m_EndHandle, effectorPosition, effectorRotation, weight, weight);
|
|
}
|
|
|
|
else if (m_IkType == IkType.Humanoid)
|
|
{
|
|
if (stream.isHumanStream)
|
|
{
|
|
var humanStream = stream.AsHuman();
|
|
|
|
humanStream.SetGoalPosition(m_HumanLimb, effectorPosition);
|
|
humanStream.SetGoalRotation(m_HumanLimb, effectorRotation);
|
|
humanStream.SetGoalWeightPosition(m_HumanLimb, weight);
|
|
humanStream.SetGoalWeightRotation(m_HumanLimb, weight);
|
|
humanStream.SolveIK();
|
|
}
|
|
}
|
|
}
|
|
}
|