自定义数据创建动画
时间
假如你的FrameRate是30,当前为第20帧,那么当前时间为 20/30
关键帧名称
可以直接创建一个prefab然后以文本的方式打开获得,观察下面yaml格式
position对应的是m_LocalPosition.x,m_LocalPosition.y,m_LocalPosition.z
rotation对应的是m_LocalRotation.x,m_LocalRotation.y,m_LocalRotation.z,m_LocalRotation.w
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &4496430131825855203
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 4038476264630772384}
m_Layer: 0
m_Name: GameObject
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &4038476264630772384
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4496430131825855203}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: -0.119914055, y: -2.430935, z: 2.2560377}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
设置动画曲线
动画是按照对象路径查找的,例如说A对象下B对象需要移动,那么路径只需要填写 B 即可。如果路径为空默认为根对象。
第二个参数为需要改变的类型
第三个参数填写修改的关键帧名字
第四个参数是动画曲线。例如创建一个线性插值的曲线 AnimationCurve.Linear(0,0,2,100)
clip.SetCurve("", typeof(Transform), "localPosition.x", curve);
创建一个动画
class Curve
{
public string path;
public System.Type type;
public string name;
public Keyframe[] keyframes;
}
class AnimationClipUtility
{
public AnimationClip CreateAsset(Curve [] curves, WrapMode mode, float frameRate, AnimationClipSettings settings)
{
AnimationClip clip = new AnimationClip();
//legacy为true时无法使用状态机
clip.legacy = false;
clip.wrapMode = mode;
clip.frameRate = frameRate;
AnimationUtility.SetAnimationClipSettings(clip, settings);
for (int i=0;i< curves.Length;i++)
{
var curve = curves[i];
clip.SetCurve(curve.path, curve.type, curve.name, new AnimationCurve(curve.keyframes));
}
return clip;
}
}
给人形骨骼创建Avatar
public class AvatarTool
{
public static Dictionary<string, string> map = new Dictionary<string, string>
{
{"Hips","Hips"},
{"Upper_Leg_L","LeftUpperLeg"},
{"Upper_Leg_R","RightUpperLeg"},
{"Lower_Leg_L","LeftLowerLeg"},
{"Lower_Leg_R","RightLowerLeg"},
{"Foot_L","LeftFoot"},
{"Foot_R","RightFoot"},
{"Spine","Spine"},
{"Chest","Chest"},
{"Neck","Neck"},
{"Head","Head"},
{"Clavicle_L","LeftShoulder"},
{"Clavicle_R","RightShoulder"},
{"Upper_Arm_L","LeftUpperArm"},
{"Upper_Arm_R","RightUpperArm"},
{"Lower_Arm_L","LeftLowerArm"},
{"Lower_Arm_R","RightLowerArm"},
{"Hand_L","LeftHand"},
{"Hand_R","RightHand"},
{"Eye_L","LeftEye"},
{"Eye_R","RightEye"},
{"Finger_L_Thumb_Proximal","Left Thumb Proximal"},
{"Finger_L_Thumb_Intermediate","Left Thumb Intermediate"},
{"Finger_L_Thumb_Distal","Left Thumb Distal"},
{"Finger_L_Index_Proximal","Left Index Proximal"},
{"Finger_L_Index_Intermediate","Left Index Intermediate"},
{"Finger_L_Middle_Proximal","Left Middle Proximal"},
{"Finger_L_Middle_Intermediate","Left Middle Intermediate"},
{"Finger_L_Ring_Proximal","Left Ring Proximal"},
{"Finger_L_Ring_Intermediate","Left Ring Intermediate"},
{"Finger_L_Pinky_Proximal","Left Little Proximal"},
{"Finger_L_Pinky_Intermediate","Left Little Intermediate"},
{"Finger_R_Thumb_Proximal","Right Thumb Proximal"},
{"Finger_R_Thumb_Intermediate","Right Thumb Intermediate"},
{"Finger_R_Thumb_Distal","Right Thumb Distal"},
{"Finger_R_Index_Proximal","Right Index Proximal"},
{"Finger_R_Index_Intermediate","Right Index Intermediate"},
{"Finger_R_Middle_Proximal","Right Middle Proximal"},
{"Finger_R_Middle_Intermediate","Right Middle Intermediate"},
{"Finger_R_Ring_Proximal","Right Ring Proximal"},
{"Finger_R_Ring_Intermediate","Right Ring Intermediate"},
{"Finger_R_Pinky_Proximal","Right Little Proximal"},
{"Finger_R_Pinky_Intermediate","Right Little Intermediate"},
{"Upper_Chest","UpperChest"},
{"Toes_L","LeftToes"},
{"Toes_R","RightToes"},
{"Finger_L_Index_Distal","Left Index Distal"},
{"Finger_L_Middle_Distal","Left Middle Distal"},
{"Finger_L_Ring_Distal","Left Ring Distal"},
{"Finger_L_Pinky_Distal","Left Little Distal"},
{"Finger_R_Index_Distal","Right Index Distal"},
{"Finger_R_Middle_Distal","Right Middle Distal"},
{"Finger_R_Ring_Distal","Right Ring Distal"},
{"Finger_R_Pinky_Distal","Right Little Distal"},
{"Jaw","Jaw"}
};
static SkeletonBone[] CreateKeleton(GameObject go)
{
var type = typeof(SkeletonBone);
FieldInfo fieldInfo=type.GetField("parentName", BindingFlags.Instance | BindingFlags.NonPublic);
Transform[] transforms = go.GetComponentsInChildren<Transform>();
SkeletonBone[] skeletonBones = new SkeletonBone[transforms.Length];
for (int i = 0; i < transforms.Length; i++)
{
var transform = transforms[i];
var bone = new SkeletonBone
{
name = transform.name,
position = transform.localPosition,
rotation = transform.localRotation,
scale = transform.localScale
};
object o = bone;
fieldInfo.SetValue(bone, transform.parent.name);
bone = (SkeletonBone)o;
skeletonBones[i] = bone;
}
return skeletonBones;
}
static HumanBone[] CreateHuman(GameObject go, Dictionary<string, string> map)
{
Transform[] transforms = go.GetComponentsInChildren<Transform>();
List<HumanBone> humanBones = new List<HumanBone>();
foreach (Transform transform in transforms)
{
if (map.TryGetValue(transform.name, out string name))
{
var humanBone = new HumanBone
{
boneName = transform.name,
humanName = name,
limit = new HumanLimit()
};
humanBone.limit.useDefaultValues = true;
humanBones.Add(humanBone);
}
}
return humanBones.ToArray();
}
public static Avatar CreateAvatar(GameObject go, Dictionary<string, string> map)
{
return AvatarBuilder.BuildHumanAvatar(go, new HumanDescription
{
armStretch = 0.05f,
feetSpacing = 0f,
hasTranslationDoF = false,
legStretch = 0.05f,
lowerArmTwist = 0.5f,
lowerLegTwist = 0.5f,
upperArmTwist = 0.5f,
upperLegTwist = 0.5f,
skeleton = CreateKeleton(go),
human = CreateHuman(go, map)
});
}
}
根据骨骼名称拆分动画
假如你设置了Avatar动画融合看起来还是很奇怪。那么你可以手动对动画拆分。例如行走动画拆成下半身走动,攻击动画拆成上半身攻击。对拆分后的动画规划到同一个层。运行起来的时候就是一边攻击一边走路
public static class AnimationClipUtitlty
{
public static AnimationClip CreateClip(AnimationClip clip,string[] bones)
{
var resultClip = new AnimationClip();
resultClip.legacy = clip.legacy;
resultClip.wrapMode = clip.wrapMode;
resultClip.frameRate = clip.frameRate;
var setting = AnimationUtility.GetAnimationClipSettings(clip);
AnimationUtility.SetAnimationClipSettings(resultClip, setting);
foreach (var binding in AnimationUtility.GetCurveBindings(clip))
{
if (bones.Contains(Path.GetFileName(binding.path)))
{
var curve = AnimationUtility.GetEditorCurve(clip, binding);
resultClip.SetCurve(binding.path, binding.type, binding.propertyName, curve);
}
}
return resultClip;
}
}
No Comments