备份CatanBuilding瘦身独立工程
9
LocalPackages/FinalIK/Runtime/Baker.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 47bf04154c11c5e45b94b1aec2c0baf6
|
||||
folderAsset: yes
|
||||
timeCreated: 1516620867
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
9
LocalPackages/FinalIK/Runtime/Baker/Scripts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8d2079bf8fd63d640a121f8fea6f5c5f
|
||||
folderAsset: yes
|
||||
timeCreated: 1516620916
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 490fde02f41ae014abec4edfce28648f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,23 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace RootMotion
|
||||
{
|
||||
|
||||
public abstract class AnimationModifier : MonoBehaviour
|
||||
{
|
||||
protected Animator animator;
|
||||
protected Baker baker;
|
||||
|
||||
public virtual void OnInitiate(Baker baker, Animator animator)
|
||||
{
|
||||
this.baker = baker;
|
||||
this.animator = animator;
|
||||
}
|
||||
|
||||
public virtual void OnStartClip(AnimationClip clip) { }
|
||||
|
||||
public virtual void OnBakerUpdate(float normalizedTime) { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3f66200036e67da4998b9ac08649304f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,60 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace RootMotion
|
||||
{
|
||||
public class AnimationModifierStack : MonoBehaviour
|
||||
{
|
||||
public AnimationModifier[] modifiers = new AnimationModifier[0];
|
||||
|
||||
private Animator animator;
|
||||
private Baker baker;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
animator = GetComponent<Animator>();
|
||||
baker = GetComponent<Baker>();
|
||||
baker.OnStartClip += OnBakerStartClip;
|
||||
baker.OnUpdateClip += OnBakerUpdateClip;
|
||||
|
||||
foreach (AnimationModifier m in modifiers)
|
||||
{
|
||||
m.OnInitiate(baker, animator);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnBakerStartClip(AnimationClip clip, float normalizedTime)
|
||||
{
|
||||
foreach (AnimationModifier m in modifiers)
|
||||
{
|
||||
m.OnStartClip(clip);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnBakerUpdateClip(AnimationClip clip, float normalizedTime)
|
||||
{
|
||||
foreach (AnimationModifier m in modifiers)
|
||||
{
|
||||
if (!m.enabled) continue;
|
||||
m.OnBakerUpdate(normalizedTime);
|
||||
}
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
if (!animator.enabled && !baker.isBaking) return;
|
||||
if (baker.isBaking && baker.mode == Baker.Mode.AnimationClips) return;
|
||||
if (animator.runtimeAnimatorController == null) return;
|
||||
|
||||
AnimatorStateInfo info = animator.GetCurrentAnimatorStateInfo(0);
|
||||
float n = info.normalizedTime;
|
||||
|
||||
foreach (AnimationModifier m in modifiers)
|
||||
{
|
||||
if (!m.enabled) continue;
|
||||
m.OnBakerUpdate(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: addea154dd3a3e442abb7c12a65ebf8e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
602
LocalPackages/FinalIK/Runtime/Baker/Scripts/Baker.cs
Normal file
@@ -0,0 +1,602 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using UnityEngine.Playables;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
namespace RootMotion
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for animation bakers, handles timing, keyframing and saving AnimationClips.
|
||||
/// </summary>
|
||||
[HelpURL("http://www.root-motion.com/finalikdox/html/page3.html")]
|
||||
[AddComponentMenu("Scripts/RootMotion/Baker")]
|
||||
public abstract class Baker : MonoBehaviour
|
||||
{
|
||||
|
||||
// Open the User Manual URL
|
||||
[ContextMenu("User Manual")]
|
||||
void OpenUserManual()
|
||||
{
|
||||
Application.OpenURL("http://www.root-motion.com/finalikdox/html/page3.html");
|
||||
}
|
||||
|
||||
// Open the Script Reference URL
|
||||
[ContextMenu("Scrpt Reference")]
|
||||
void OpenScriptReference()
|
||||
{
|
||||
Application.OpenURL("http://www.root-motion.com/finalikdox/html/class_root_motion_1_1_baker.html");
|
||||
}
|
||||
|
||||
// Link to the Final IK Google Group
|
||||
[ContextMenu("Support Group")]
|
||||
void SupportGroup()
|
||||
{
|
||||
Application.OpenURL("https://groups.google.com/forum/#!forum/final-ik");
|
||||
}
|
||||
|
||||
// Link to the Final IK Asset Store thread in the Unity Community
|
||||
[ContextMenu("Asset Store Thread")]
|
||||
void ASThread()
|
||||
{
|
||||
Application.OpenURL("http://forum.unity3d.com/threads/final-ik-full-body-ik-aim-look-at-fabrik-ccd-ik-1-0-released.222685/");
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public enum Mode
|
||||
{
|
||||
AnimationClips = 0,
|
||||
AnimationStates = 1,
|
||||
PlayableDirector = 2,
|
||||
Realtime = 3
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// In AnimationClips, AnimationStates or PlayableDirector mode - the frame rate at which the animation clip will be sampled. In Realtime mode - the frame rate at which the pose will be sampled. With the latter, the frame rate is not guaranteed if the player is not able to reach it.
|
||||
/// </summary>
|
||||
[Tooltip("In AnimationClips, AnimationStates or PlayableDirector mode - the frame rate at which the animation clip will be sampled. In Realtime mode - the frame rate at which the pose will be sampled. With the latter, the frame rate is not guaranteed if the player is not able to reach it.")]
|
||||
[Range(1, 90)] public int frameRate = 30;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum allowed error for keyframe reduction.
|
||||
/// </summary>
|
||||
[Tooltip("Maximum allowed error for keyframe reduction.")]
|
||||
[Range(0f, 0.1f)] public float keyReductionError = 0.01f;
|
||||
|
||||
/// <summary>
|
||||
/// AnimationClips mode can be used to bake a batch of AnimationClips directly without the need of setting up an AnimatorController. AnimationStates mode is useful for when you need to set up a more complex rig with layers and AvatarMasks in Mecanim. PlayableDirector mode bakes a Timeline. Realtime mode is for continuous baking of gameplay, ragdoll phsysics or PuppetMaster dynamics.
|
||||
/// </summary>
|
||||
[Tooltip("AnimationClips mode can be used to bake a batch of AnimationClips directly without the need of setting up an AnimatorController. " +
|
||||
"AnimationStates mode is useful for when you need to set up a more complex rig with layers and AvatarMasks in Mecanim. " +
|
||||
"PlayableDirector mode bakes a Timeline. " +
|
||||
"Realtime mode is for continuous baking of gameplay, ragdoll phsysics or PuppetMaster dynamics.")]
|
||||
public Mode mode;
|
||||
|
||||
/// <summary>
|
||||
/// AnimationClips to bake.
|
||||
/// </summary>
|
||||
[Tooltip("AnimationClips to bake.")]
|
||||
public AnimationClip[] animationClips = new AnimationClip[0];
|
||||
|
||||
/// <summary>
|
||||
/// The name of the AnimationStates to bake (must be on the base layer) in the Animator (Right-click on this component header and select 'Find Animation States' to have Baker fill those in automatically, required that state names match with the names of the clips used in them).
|
||||
/// </summary>
|
||||
[Tooltip("The name of the AnimationStates to bake (must be on the base layer) in the Animator above (Right-click on this component header and select 'Find Animation States' to have Baker fill those in automatically, required that state names match with the names of the clips used in them).")]
|
||||
public string[] animationStates = new string[0];
|
||||
|
||||
/// <summary>
|
||||
/// The folder to save the baked AnimationClips to.
|
||||
/// </summary>
|
||||
[Tooltip("The folder to save the baked AnimationClips to.")]
|
||||
public string saveToFolder = "Assets";
|
||||
|
||||
/// <summary>
|
||||
/// String that will be added to each clip or animation state name for the saved clip. For example if your animation state/clip names were 'Idle' and 'Walk', then with '_Baked' as Append Name, the Baker will create 'Idle_Baked' and 'Walk_Baked' animation clips.
|
||||
/// </summary>
|
||||
[Tooltip("String that will be added to each clip or animation state name for the saved clip. For example if your animation state/clip names were 'Idle' and 'Walk', then with '_Baked' as Append Name, the Baker will create 'Idle_Baked' and 'Walk_Baked' animation clips.")]
|
||||
public string appendName = "_Baked";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the created AnimationClip file.
|
||||
/// </summary>
|
||||
[Tooltip("Name of the created AnimationClip file.")]
|
||||
public string saveName = "Baked Clip";
|
||||
|
||||
public bool isBaking { get; private set; }
|
||||
public float bakingProgress { get; private set; }
|
||||
|
||||
[HideInInspector] public Animator animator;
|
||||
[HideInInspector] public PlayableDirector director;
|
||||
|
||||
public delegate void BakerDelegate(AnimationClip clip, float time);
|
||||
|
||||
public BakerDelegate OnStartClip;
|
||||
public BakerDelegate OnUpdateClip;
|
||||
|
||||
[System.Serializable]
|
||||
public class ClipSettings
|
||||
{
|
||||
[System.Serializable]
|
||||
public enum BasedUponRotation
|
||||
{
|
||||
Original = 0,
|
||||
BodyOrientation = 1,
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public enum BasedUponY
|
||||
{
|
||||
Original = 0,
|
||||
CenterOfMass = 1,
|
||||
Feet = 2,
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public enum BasedUponXZ
|
||||
{
|
||||
Original = 0,
|
||||
CenterOfMass = 1,
|
||||
}
|
||||
|
||||
public bool loopTime;
|
||||
public bool loopBlend;
|
||||
public float cycleOffset;
|
||||
public bool loopBlendOrientation;
|
||||
public BasedUponRotation basedUponRotation;
|
||||
public float orientationOffsetY;
|
||||
public bool loopBlendPositionY;
|
||||
public BasedUponY basedUponY;
|
||||
public float level;
|
||||
public bool loopBlendPositionXZ;
|
||||
public BasedUponXZ basedUponXZ;
|
||||
public bool mirror;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
|
||||
public void ApplyTo(AnimationClipSettings settings)
|
||||
{
|
||||
settings.loopTime = loopTime;
|
||||
settings.loopBlend = loopBlend;
|
||||
settings.cycleOffset = cycleOffset;
|
||||
|
||||
settings.loopBlendOrientation = loopBlendOrientation;
|
||||
settings.keepOriginalOrientation = basedUponRotation == BasedUponRotation.Original;
|
||||
settings.orientationOffsetY = orientationOffsetY;
|
||||
|
||||
settings.loopBlendPositionY = loopBlendPositionY;
|
||||
settings.keepOriginalPositionY = basedUponY == BasedUponY.Original;
|
||||
settings.heightFromFeet = basedUponY == BasedUponY.Feet;
|
||||
settings.level = level;
|
||||
|
||||
settings.loopBlendPositionXZ = loopBlendPositionXZ;
|
||||
settings.keepOriginalPositionXZ = basedUponXZ == BasedUponXZ.Original;
|
||||
|
||||
settings.mirror = mirror;
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If enabled, baked clips will have the same AnimationClipSettings as the clips used for baking. If disabled, clip settings from below will be applied to all the baked clips.
|
||||
/// </summary>
|
||||
[Tooltip("If enabled, baked clips will have the same AnimationClipSettings as the clips used for baking. If disabled, clip settings from below will be applied to all the baked clips.")] public bool inheritClipSettings;
|
||||
|
||||
/// <summary>
|
||||
/// AnimationClipSettings applied to the baked animation clip.
|
||||
/// </summary>
|
||||
[Tooltip("AnimationClipSettings applied to the baked animation clip.")] public ClipSettings clipSettings;
|
||||
|
||||
protected abstract Transform GetCharacterRoot();
|
||||
protected abstract void OnStartBaking();
|
||||
protected abstract void OnSetLoopFrame(float time);
|
||||
protected abstract void OnSetCurves(ref AnimationClip clip);
|
||||
protected abstract void OnSetKeyframes(float time, bool lastFrame);
|
||||
protected float clipLength { get; private set; }
|
||||
protected bool addLoopFrame;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private AnimationClip[] bakedClips = new AnimationClip[0];
|
||||
|
||||
private AnimatorStateInfo currentClipStateInfo;
|
||||
private int currentClipIndex;
|
||||
|
||||
private float startBakingTime;
|
||||
private float nextKeyframeTime;
|
||||
private bool firstFrame;
|
||||
private int clipFrames;
|
||||
private int clipFrameNo;
|
||||
private bool setKeyframes;
|
||||
|
||||
private float currentClipTime;
|
||||
private float clipFrameInterval;
|
||||
#endif
|
||||
|
||||
// Start baking an animation state, clip or timeline, also called for each next clip in the baking array
|
||||
public void BakeClip()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (mode == Mode.AnimationClips && inheritClipSettings)
|
||||
{
|
||||
AnimationClipSettings originalSettings = AnimationUtility.GetAnimationClipSettings(animationClips[currentClipIndex]);
|
||||
addLoopFrame = originalSettings.loopTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mode == Mode.Realtime) addLoopFrame = clipSettings.loopTime && clipSettings.loopBlend;
|
||||
else addLoopFrame = clipSettings.loopTime;
|
||||
}
|
||||
|
||||
StartBaking();
|
||||
#endif
|
||||
}
|
||||
|
||||
public void StartBaking()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
|
||||
isBaking = true;
|
||||
nextKeyframeTime = 0f;
|
||||
|
||||
bakingProgress = 0f;
|
||||
clipFrameNo = 0;
|
||||
|
||||
if (bakedClips.Length == 0)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case Mode.AnimationClips:
|
||||
bakedClips = new AnimationClip[animationClips.Length];
|
||||
break;
|
||||
case Mode.AnimationStates:
|
||||
bakedClips = new AnimationClip[animationStates.Length];
|
||||
break;
|
||||
default:
|
||||
bakedClips = new AnimationClip[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
OnStartBaking();
|
||||
|
||||
firstFrame = true;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
public void StopBaking()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
|
||||
if (!isBaking) return;
|
||||
|
||||
if (addLoopFrame)
|
||||
{
|
||||
OnSetLoopFrame(clipLength);
|
||||
}
|
||||
|
||||
bakedClips[currentClipIndex] = new AnimationClip();
|
||||
bakedClips[currentClipIndex].frameRate = frameRate;
|
||||
|
||||
OnSetCurves(ref bakedClips[currentClipIndex]);
|
||||
|
||||
bakedClips[currentClipIndex].EnsureQuaternionContinuity();
|
||||
|
||||
if (mode == Mode.Realtime)
|
||||
{
|
||||
isBaking = false;
|
||||
SaveClips();
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
|
||||
[ContextMenu("Find Animation States")]
|
||||
public void FindAnimationStates()
|
||||
{
|
||||
animator = GetComponent<Animator>();
|
||||
if (animator == null)
|
||||
{
|
||||
Debug.LogError("No Animator found on Baker GameObject. Can not find animation states.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (animator.runtimeAnimatorController == null)
|
||||
{
|
||||
Debug.LogError("Animator does not have a valid Controller. Can not find animation states.");
|
||||
return;
|
||||
}
|
||||
|
||||
var clips = animator.runtimeAnimatorController.animationClips;
|
||||
animationStates = new string[clips.Length];
|
||||
for (int i = 0; i < clips.Length; i++)
|
||||
{
|
||||
animationStates[i] = clips[i].name;
|
||||
}
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
// Baking procedure
|
||||
if (isBaking)
|
||||
{
|
||||
if (mode != Mode.Realtime)
|
||||
{
|
||||
if (firstFrame)
|
||||
{
|
||||
transform.position = Vector3.zero;
|
||||
transform.rotation = Quaternion.identity;
|
||||
GetCharacterRoot().position = Vector3.zero;
|
||||
GetCharacterRoot().rotation = Quaternion.identity;
|
||||
|
||||
StartAnimationUpdate();
|
||||
|
||||
currentClipTime = 0f;
|
||||
firstFrame = false;
|
||||
}
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case Mode.AnimationClips:
|
||||
clipLength = animationClips[currentClipIndex].length;
|
||||
bakingProgress = currentClipTime / clipLength;
|
||||
break;
|
||||
case Mode.AnimationStates:
|
||||
currentClipStateInfo = animator.GetCurrentAnimatorStateInfo(0);
|
||||
bakingProgress = currentClipStateInfo.normalizedTime;
|
||||
|
||||
if (currentClipStateInfo.speed <= 0f)
|
||||
{
|
||||
Debug.LogError("Baker can not bake a clip with 0 speed.");
|
||||
return;
|
||||
}
|
||||
|
||||
clipLength = currentClipStateInfo.length / currentClipStateInfo.speed / animator.speed;
|
||||
break;
|
||||
case Mode.PlayableDirector:
|
||||
clipLength = (float)director.duration;
|
||||
bakingProgress = (float)director.time / clipLength;
|
||||
break;
|
||||
}
|
||||
|
||||
clipFrames = (int)(clipLength * (frameRate));
|
||||
clipFrameInterval = clipLength / (float)(clipFrames);
|
||||
setKeyframes = true;
|
||||
|
||||
// Stop clip baking if the clip is finished, start baking the next clip if possible
|
||||
if (clipFrameNo > clipFrames)
|
||||
{
|
||||
StopBaking();
|
||||
|
||||
currentClipIndex++;
|
||||
if (currentClipIndex >= bakedClips.Length)
|
||||
{
|
||||
currentClipIndex = 0;
|
||||
StopAnimationUpdate();
|
||||
isBaking = false;
|
||||
|
||||
SaveClips();
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
BakeClip();
|
||||
setKeyframes = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!firstFrame) AnimationUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LateUpdate()
|
||||
{
|
||||
if (!isBaking) return;
|
||||
|
||||
if (mode != Mode.Realtime)
|
||||
{
|
||||
if (setKeyframes)
|
||||
{
|
||||
OnSetKeyframes(clipFrameNo * clipFrameInterval, clipFrameNo >= clipFrames);
|
||||
|
||||
clipFrameNo++;
|
||||
setKeyframes = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (firstFrame)
|
||||
{
|
||||
startBakingTime = Time.time;
|
||||
firstFrame = false;
|
||||
}
|
||||
|
||||
if (Time.time < nextKeyframeTime) return;
|
||||
|
||||
OnSetKeyframes(Time.time - startBakingTime, false);
|
||||
|
||||
nextKeyframeTime = Time.time + (1f / (float)frameRate);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void StartAnimationUpdate()
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case Mode.AnimationClips:
|
||||
if (!AnimationMode.InAnimationMode()) AnimationMode.StartAnimationMode();
|
||||
AnimationMode.BeginSampling();
|
||||
AnimationMode.SampleAnimationClip(gameObject, animationClips[currentClipIndex], 0f);
|
||||
AnimationMode.EndSampling();
|
||||
if (OnStartClip != null) OnStartClip(animationClips[currentClipIndex], 0f);
|
||||
break;
|
||||
case Mode.AnimationStates:
|
||||
animator.enabled = false;
|
||||
animator.Play(animationStates[currentClipIndex], 0, 0f);
|
||||
break;
|
||||
case Mode.PlayableDirector:
|
||||
director.enabled = false;
|
||||
director.time = 0f;
|
||||
director.Evaluate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void StopAnimationUpdate()
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case Mode.AnimationClips:
|
||||
if (AnimationMode.InAnimationMode()) AnimationMode.StopAnimationMode();
|
||||
break;
|
||||
case Mode.AnimationStates:
|
||||
animator.enabled = true;
|
||||
break;
|
||||
case Mode.PlayableDirector:
|
||||
director.enabled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void AnimationUpdate()
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case Mode.AnimationClips:
|
||||
if (!AnimationMode.InAnimationMode()) AnimationMode.StartAnimationMode();
|
||||
AnimationMode.BeginSampling();
|
||||
AnimationMode.SampleAnimationClip(gameObject, animationClips[currentClipIndex], currentClipTime);
|
||||
AnimationMode.EndSampling();
|
||||
if (OnUpdateClip != null) OnUpdateClip(animationClips[currentClipIndex], currentClipTime / animationClips[currentClipIndex].length);
|
||||
currentClipTime += clipFrameInterval;
|
||||
break;
|
||||
case Mode.AnimationStates:
|
||||
animator.Update(clipFrameInterval);
|
||||
break;
|
||||
case Mode.PlayableDirector:
|
||||
director.time = currentClipTime;
|
||||
director.Evaluate();
|
||||
currentClipTime += clipFrameInterval;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveClips()
|
||||
{
|
||||
var clips = GetBakedClips();
|
||||
AnimationClip savedClip = null;
|
||||
|
||||
for (int i = 0; i < clips.Length; i++)
|
||||
{
|
||||
string path = GetFullPath(i);
|
||||
|
||||
if (mode == Mode.AnimationClips && inheritClipSettings)
|
||||
{
|
||||
AnimationClipSettings inheritedSettings = AnimationUtility.GetAnimationClipSettings(animationClips[i]);
|
||||
SetClipSettings(clips[i], inheritedSettings);
|
||||
AnimationUtility.SetAnimationClipSettings(clips[i], inheritedSettings);
|
||||
}
|
||||
else
|
||||
{
|
||||
AnimationClipSettings settings = AnimationUtility.GetAnimationClipSettings(clips[i]);
|
||||
clipSettings.ApplyTo(settings);
|
||||
SetClipSettings(clips[i], settings);
|
||||
AnimationUtility.SetAnimationClipSettings(clips[i], settings);
|
||||
}
|
||||
|
||||
var existing = AssetDatabase.LoadAssetAtPath(path, typeof(AnimationClip)) as AnimationClip;
|
||||
if (existing != null)
|
||||
{
|
||||
// Overwrite
|
||||
EditorUtility.CopySerialized(clips[i], existing);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create new asset
|
||||
AssetDatabase.CreateAsset(clips[i], path);
|
||||
}
|
||||
|
||||
/* v2.0
|
||||
switch (mode)
|
||||
{
|
||||
case Baker.Mode.Realtime: break;
|
||||
case Baker.Mode.AnimationClips:
|
||||
AnimationClipSettings originalSettings = AnimationUtility.GetAnimationClipSettings(animationClips[i]);
|
||||
SetClipSettings(clips[i], originalSettings);
|
||||
AnimationUtility.SetAnimationClipSettings(clips[i], originalSettings);
|
||||
break;
|
||||
default:
|
||||
AnimationClipSettings settings = AnimationUtility.GetAnimationClipSettings(clips[i]);
|
||||
settings.loopTime = loop;
|
||||
SetClipSettings(clips[i], settings);
|
||||
AnimationUtility.SetAnimationClipSettings(clips[i], settings);
|
||||
break;
|
||||
}
|
||||
|
||||
var existing = AssetDatabase.LoadAssetAtPath(path, typeof(AnimationClip)) as AnimationClip;
|
||||
if (existing != null)
|
||||
{
|
||||
// Overwrite with existing settings
|
||||
AnimationClipSettings existingSettings = AnimationUtility.GetAnimationClipSettings(existing);
|
||||
existingSettings.stopTime = clips[i].length;
|
||||
AnimationUtility.SetAnimationClipSettings(clips[i], existingSettings);
|
||||
EditorUtility.CopySerialized(clips[i], existing);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create new asset
|
||||
AssetDatabase.CreateAsset(clips[i], path);
|
||||
}
|
||||
*/
|
||||
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
savedClip = AssetDatabase.LoadAssetAtPath(path, typeof(AnimationClip)) as AnimationClip;
|
||||
|
||||
Debug.Log(path + " successfully baked.");
|
||||
}
|
||||
|
||||
Selection.activeObject = savedClip;
|
||||
|
||||
ClearBakedClips();
|
||||
}
|
||||
|
||||
protected virtual void SetClipSettings(AnimationClip clip, AnimationClipSettings settings) { }
|
||||
|
||||
private string GetFullPath(int clipIndex)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case Baker.Mode.AnimationClips:
|
||||
return saveToFolder + "/" + animationClips[clipIndex].name + appendName + ".anim";
|
||||
case Baker.Mode.AnimationStates:
|
||||
return saveToFolder + "/" + animationStates[clipIndex] + appendName + ".anim";
|
||||
case Baker.Mode.PlayableDirector:
|
||||
return saveToFolder + "/" + saveName + ".anim";
|
||||
default:
|
||||
return saveToFolder + "/" + saveName + ".anim";
|
||||
}
|
||||
}
|
||||
|
||||
private AnimationClip[] GetBakedClips()
|
||||
{
|
||||
return bakedClips;
|
||||
}
|
||||
|
||||
private void ClearBakedClips()
|
||||
{
|
||||
bakedClips = new AnimationClip[0];
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
12
LocalPackages/FinalIK/Runtime/Baker/Scripts/Baker.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ab14efce3fefe4f4982f0fa6911d0cd4
|
||||
timeCreated: 1516617114
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
134
LocalPackages/FinalIK/Runtime/Baker/Scripts/GenericBaker.cs
Normal file
@@ -0,0 +1,134 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System;
|
||||
|
||||
namespace RootMotion
|
||||
{
|
||||
/// <summary>
|
||||
/// Baker for Generic/Legacy animation.
|
||||
/// </summary>
|
||||
public class GenericBaker : Baker
|
||||
{
|
||||
/// <summary>
|
||||
/// If true, produced AnimationClips will be marked as Legacy and usable with the Legacy animation system.
|
||||
/// </summary>
|
||||
[Tooltip("If true, produced AnimationClips will be marked as Legacy and usable with the Legacy animation system.")]
|
||||
public bool markAsLegacy;
|
||||
|
||||
/// <summary>
|
||||
/// Root Transform of the hierarchy to bake.
|
||||
/// </summary>
|
||||
[Tooltip("Root Transform of the hierarchy to bake.")]
|
||||
public Transform root;
|
||||
|
||||
/// <summary>
|
||||
/// Root Node used for root motion.
|
||||
/// </summary>
|
||||
[Tooltip("Root Node used for root motion.")]
|
||||
public Transform rootNode;
|
||||
|
||||
/// <summary>
|
||||
/// List of Transforms to ignore, rotation curves will not be baked for these Transforms.
|
||||
/// </summary>
|
||||
[Tooltip("List of Transforms to ignore, rotation curves will not be baked for these Transforms.")]
|
||||
public Transform[] ignoreList;
|
||||
|
||||
/// <summary>
|
||||
/// LocalPosition curves will be baked for these Transforms only. If you are baking a character, the pelvis bone should be added to this array.
|
||||
/// </summary>
|
||||
[Tooltip("LocalPosition curves will be baked for these Transforms only. If you are baking a character, the pelvis bone should be added to this array.")]
|
||||
public Transform[] bakePositionList;
|
||||
|
||||
private BakerTransform[] children = new BakerTransform[0];
|
||||
private BakerTransform rootChild;
|
||||
private int rootChildIndex = -1;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
// Find all the child Transforms of the Animator
|
||||
Transform[] childrenAndRoot = (Transform[])root.GetComponentsInChildren<Transform>();
|
||||
|
||||
children = new BakerTransform[0];
|
||||
|
||||
// Exlude the ignore list, construct the children array
|
||||
for (int i = 0; i < childrenAndRoot.Length; i++)
|
||||
{
|
||||
if (!IsIgnored(childrenAndRoot[i]))
|
||||
{
|
||||
|
||||
Array.Resize(ref children, children.Length + 1);
|
||||
|
||||
bool isRootNode = childrenAndRoot[i] == rootNode;
|
||||
if (isRootNode) rootChildIndex = children.Length - 1;
|
||||
|
||||
children[children.Length - 1] = new BakerTransform(childrenAndRoot[i], root, BakePosition(childrenAndRoot[i]), isRootNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override Transform GetCharacterRoot()
|
||||
{
|
||||
return root;
|
||||
}
|
||||
|
||||
protected override void OnStartBaking()
|
||||
{
|
||||
for (int i = 0; i < children.Length; i++)
|
||||
{
|
||||
children[i].Reset();
|
||||
|
||||
if (i == rootChildIndex) children[i].SetRelativeSpace(root.position, root.rotation);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnSetLoopFrame(float time)
|
||||
{
|
||||
// TODO Change to SetLoopFrame like in HumanoidBaker
|
||||
for (int i = 0; i < children.Length; i++) children[i].AddLoopFrame(time);
|
||||
}
|
||||
|
||||
protected override void OnSetCurves(ref AnimationClip clip)
|
||||
{
|
||||
// TODO Length Multiplier
|
||||
|
||||
for (int i = 0; i < children.Length; i++) children[i].SetCurves(ref clip);
|
||||
}
|
||||
|
||||
protected override void OnSetKeyframes(float time, bool lastFrame)
|
||||
{
|
||||
for (int i = 0; i < children.Length; i++) children[i].SetKeyframes(time);
|
||||
}
|
||||
|
||||
// Is the specified Transform in the ignore list?
|
||||
private bool IsIgnored(Transform t)
|
||||
{
|
||||
for (int i = 0; i < ignoreList.Length; i++)
|
||||
{
|
||||
if (t == ignoreList[i]) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Should we record the localPosition channels of the Transform?
|
||||
private bool BakePosition(Transform t)
|
||||
{
|
||||
for (int i = 0; i < bakePositionList.Length; i++)
|
||||
{
|
||||
if (t == bakePositionList[i]) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
protected override void SetClipSettings(AnimationClip clip, UnityEditor.AnimationClipSettings settings)
|
||||
{
|
||||
clip.legacy = markAsLegacy;
|
||||
|
||||
if (mode != Baker.Mode.AnimationClips)
|
||||
{
|
||||
clip.wrapMode = settings.loopTime ? WrapMode.Loop : WrapMode.Default;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 27b32efee52144c4e934e6c3272ceb2c
|
||||
timeCreated: 1516356533
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 15001
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
9
LocalPackages/FinalIK/Runtime/Baker/Scripts/Helpers.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e468ef7e80a87f94588b5eeb3a423b91
|
||||
folderAsset: yes
|
||||
timeCreated: 1516621025
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,128 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace RootMotion
|
||||
{
|
||||
public class TQ
|
||||
{
|
||||
public TQ() { }
|
||||
|
||||
public TQ(Vector3 translation, Quaternion rotation)
|
||||
{
|
||||
t = translation;
|
||||
q = rotation;
|
||||
}
|
||||
|
||||
public Vector3 t;
|
||||
public Quaternion q;
|
||||
}
|
||||
|
||||
/*
|
||||
Written with the kind help of the one commonly known as Mecanim-Dev.
|
||||
*/
|
||||
public class AvatarUtility
|
||||
{
|
||||
|
||||
public static Quaternion GetPostRotation(Avatar avatar, AvatarIKGoal avatarIKGoal)
|
||||
{
|
||||
int humanId = (int)HumanIDFromAvatarIKGoal(avatarIKGoal);
|
||||
if (humanId == (int)HumanBodyBones.LastBone) throw new InvalidOperationException("Invalid human id.");
|
||||
|
||||
MethodInfo methodGetPostRotation = typeof(Avatar).GetMethod("GetPostRotation", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
if (methodGetPostRotation == null) throw new InvalidOperationException("Cannot find GetPostRotation method.");
|
||||
|
||||
return (Quaternion)methodGetPostRotation.Invoke(avatar, new object[] { humanId });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get IK position and rotation for foot/hand bone position/rotation.
|
||||
/// </summary>
|
||||
public static TQ GetIKGoalTQ(Avatar avatar, float humanScale, AvatarIKGoal avatarIKGoal, TQ bodyPositionRotation, TQ boneTQ)
|
||||
{
|
||||
int humanId = (int)HumanIDFromAvatarIKGoal(avatarIKGoal);
|
||||
if (humanId == (int)HumanBodyBones.LastBone) throw new InvalidOperationException("Invalid human id.");
|
||||
|
||||
MethodInfo methodGetAxisLength = typeof(Avatar).GetMethod("GetAxisLength", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
if (methodGetAxisLength == null) throw new InvalidOperationException("Cannot find GetAxisLength method.");
|
||||
|
||||
MethodInfo methodGetPostRotation = typeof(Avatar).GetMethod("GetPostRotation", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
if (methodGetPostRotation == null) throw new InvalidOperationException("Cannot find GetPostRotation method.");
|
||||
|
||||
Quaternion postRotation = (Quaternion)methodGetPostRotation.Invoke(avatar, new object[] { humanId });
|
||||
|
||||
var goalTQ = new TQ(boneTQ.t, boneTQ.q * postRotation);
|
||||
|
||||
if (avatarIKGoal == AvatarIKGoal.LeftFoot || avatarIKGoal == AvatarIKGoal.RightFoot)
|
||||
{
|
||||
// Here you could use animator.leftFeetBottomHeight or animator.rightFeetBottomHeight rather than GetAxisLenght
|
||||
// Both are equivalent but GetAxisLength is the generic way and work for all human bone
|
||||
float axislength = (float)methodGetAxisLength.Invoke(avatar, new object[] { humanId });
|
||||
Vector3 footBottom = new Vector3(axislength, 0, 0);
|
||||
goalTQ.t += (goalTQ.q * footBottom);
|
||||
}
|
||||
|
||||
// IK goal are in avatar body local space
|
||||
Quaternion invRootQ = Quaternion.Inverse(bodyPositionRotation.q);
|
||||
goalTQ.t = invRootQ * (goalTQ.t - bodyPositionRotation.t);
|
||||
goalTQ.q = invRootQ * goalTQ.q;
|
||||
goalTQ.t /= humanScale;
|
||||
|
||||
goalTQ.q = Quaternion.LookRotation(goalTQ.q * Vector3.forward, goalTQ.q * Vector3.up);
|
||||
|
||||
return goalTQ;
|
||||
}
|
||||
|
||||
public static TQ WorldSpaceIKGoalToBone(TQ goalTQ, Avatar avatar, AvatarIKGoal avatarIKGoal)
|
||||
{
|
||||
int humanId = (int)HumanIDFromAvatarIKGoal(avatarIKGoal);
|
||||
if (humanId == (int)HumanBodyBones.LastBone) throw new InvalidOperationException("Invalid human id.");
|
||||
|
||||
MethodInfo methodGetAxisLength = typeof(Avatar).GetMethod("GetAxisLength", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
if (methodGetAxisLength == null) throw new InvalidOperationException("Cannot find GetAxisLength method.");
|
||||
|
||||
MethodInfo methodGetPostRotation = typeof(Avatar).GetMethod("GetPostRotation", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
if (methodGetPostRotation == null) throw new InvalidOperationException("Cannot find GetPostRotation method.");
|
||||
|
||||
Quaternion postRotation = (Quaternion)methodGetPostRotation.Invoke(avatar, new object[] { humanId });
|
||||
|
||||
if (avatarIKGoal == AvatarIKGoal.LeftFoot || avatarIKGoal == AvatarIKGoal.RightFoot)
|
||||
{
|
||||
// Here you could use animator.leftFeetBottomHeight or animator.rightFeetBottomHeight rather than GetAxisLenght
|
||||
// Both are equivalent but GetAxisLength is the generic way and work for all human bone
|
||||
float axislength = (float)methodGetAxisLength.Invoke(avatar, new object[] { humanId });
|
||||
Vector3 footBottom = new Vector3(axislength, 0, 0);
|
||||
goalTQ.t -= (goalTQ.q * footBottom);
|
||||
}
|
||||
|
||||
TQ boneTQ = new TQ(goalTQ.t, goalTQ.q * Quaternion.Inverse(postRotation));
|
||||
|
||||
return boneTQ;
|
||||
}
|
||||
|
||||
public static TQ GetWorldSpaceIKGoal(BakerHumanoidQT ikQT, BakerHumanoidQT rootQT, float time, float humanScale)
|
||||
{
|
||||
var tq = ikQT.Evaluate(time);
|
||||
var rTQ = rootQT.Evaluate(time);
|
||||
|
||||
tq.q = rTQ.q * tq.q;
|
||||
tq.t = rTQ.t + rTQ.q * tq.t;
|
||||
tq.t *= humanScale;
|
||||
return tq;
|
||||
}
|
||||
|
||||
public static HumanBodyBones HumanIDFromAvatarIKGoal(AvatarIKGoal avatarIKGoal)
|
||||
{
|
||||
switch (avatarIKGoal)
|
||||
{
|
||||
case AvatarIKGoal.LeftFoot: return HumanBodyBones.LeftFoot;
|
||||
case AvatarIKGoal.RightFoot: return HumanBodyBones.RightFoot;
|
||||
case AvatarIKGoal.LeftHand: return HumanBodyBones.LeftHand;
|
||||
case AvatarIKGoal.RightHand: return HumanBodyBones.RightHand;
|
||||
default: return HumanBodyBones.LastBone;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2f9e403f0f8255c42b90254abc55f528
|
||||
timeCreated: 1516435305
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,642 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace RootMotion
|
||||
{
|
||||
public static class BakerUtilities
|
||||
{
|
||||
|
||||
public static void ReduceKeyframes(AnimationCurve curve, float maxError)
|
||||
{
|
||||
if (maxError <= 0f) return;
|
||||
|
||||
curve.keys = GetReducedKeyframes(curve, maxError);
|
||||
|
||||
// TODO Flatten outTangent for keys that have the next key and testAfter sampled to the same value in the original clip. Same thing for the inTangent
|
||||
}
|
||||
|
||||
public static Keyframe[] GetReducedKeyframes(AnimationCurve curve, float maxError)
|
||||
{
|
||||
Keyframe[] keys = curve.keys;
|
||||
|
||||
int i = 1;
|
||||
while (i < keys.Length - 1 && keys.Length > 2)
|
||||
{
|
||||
Keyframe[] testKeys = new Keyframe[keys.Length - 1];
|
||||
int c = 0;
|
||||
for (int n = 0; n < keys.Length; n++)
|
||||
{
|
||||
if (i != n)
|
||||
{
|
||||
testKeys[c] = new Keyframe(keys[n].time, keys[n].value, keys[n].inTangent, keys[n].outTangent);
|
||||
c++;
|
||||
}
|
||||
}
|
||||
|
||||
AnimationCurve testCurve = new AnimationCurve();
|
||||
testCurve.keys = testKeys;
|
||||
|
||||
float test0 = Mathf.Abs(testCurve.Evaluate(keys[i].time) - keys[i].value);
|
||||
float beforeTime = keys[i].time + (keys[i - 1].time - keys[i].time) * 0.5f;
|
||||
float afterTime = keys[i].time + (keys[i + 1].time - keys[i].time) * 0.5f;
|
||||
|
||||
float testBefore = Mathf.Abs(testCurve.Evaluate(beforeTime) - curve.Evaluate(beforeTime));
|
||||
float testAfter = Mathf.Abs(testCurve.Evaluate(afterTime) - curve.Evaluate(afterTime));
|
||||
|
||||
if (test0 < maxError && testBefore < maxError && testAfter < maxError)
|
||||
{
|
||||
keys = testKeys;
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
public static void SetLoopFrame(float time, AnimationCurve curve)
|
||||
{
|
||||
/*
|
||||
Keyframe[] keys = curve.keys;
|
||||
keys[keys.Length - 1].value = keys[0].value;
|
||||
|
||||
keys[keys.Length - 1].inTangent = keys[0].inTangent;
|
||||
keys[keys.Length - 1].outTangent = keys[0].outTangent;
|
||||
|
||||
keys[keys.Length - 1].time = time;
|
||||
curve.keys = keys;
|
||||
*/
|
||||
|
||||
Keyframe[] keys = curve.keys;
|
||||
keys[keys.Length - 1].value = keys[0].value;
|
||||
|
||||
float inTangent = Mathf.Lerp(keys[0].inTangent, keys[keys.Length - 1].inTangent, 0.5f);
|
||||
keys[0].inTangent = inTangent;
|
||||
keys[keys.Length - 1].inTangent = inTangent;
|
||||
|
||||
float outTangent = Mathf.Lerp(keys[0].outTangent, keys[keys.Length - 1].outTangent, 0.5f);
|
||||
keys[0].outTangent = outTangent;
|
||||
keys[keys.Length - 1].outTangent = outTangent;
|
||||
|
||||
keys[keys.Length - 1].time = time;
|
||||
curve.keys = keys;
|
||||
}
|
||||
|
||||
public static void SetTangentMode(AnimationCurve curve)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
|
||||
if (curve.length < 2) return;
|
||||
|
||||
for (int i = 1; i < curve.length - 1; i++)
|
||||
{
|
||||
UnityEditor.AnimationUtility.SetKeyLeftTangentMode(curve, i, UnityEditor.AnimationUtility.TangentMode.ClampedAuto);
|
||||
UnityEditor.AnimationUtility.SetKeyRightTangentMode(curve, i, UnityEditor.AnimationUtility.TangentMode.ClampedAuto);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
// Realigns quaternion keys to ensure shortest interpolation paths.
|
||||
public static Quaternion EnsureQuaternionContinuity(Quaternion lastQ, Quaternion q)
|
||||
{
|
||||
Quaternion flipped = new Quaternion(-q.x, -q.y, -q.z, -q.w);
|
||||
|
||||
Quaternion midQ = new Quaternion(
|
||||
Mathf.Lerp(lastQ.x, q.x, 0.5f),
|
||||
Mathf.Lerp(lastQ.y, q.y, 0.5f),
|
||||
Mathf.Lerp(lastQ.z, q.z, 0.5f),
|
||||
Mathf.Lerp(lastQ.w, q.w, 0.5f)
|
||||
);
|
||||
|
||||
Quaternion midQFlipped = new Quaternion(
|
||||
Mathf.Lerp(lastQ.x, flipped.x, 0.5f),
|
||||
Mathf.Lerp(lastQ.y, flipped.y, 0.5f),
|
||||
Mathf.Lerp(lastQ.z, flipped.z, 0.5f),
|
||||
Mathf.Lerp(lastQ.w, flipped.w, 0.5f)
|
||||
);
|
||||
|
||||
float angle = Quaternion.Angle(lastQ, midQ);
|
||||
float angleFlipped = Quaternion.Angle(lastQ, midQFlipped);
|
||||
|
||||
return angleFlipped < angle ? flipped : q;
|
||||
}
|
||||
}
|
||||
|
||||
//Manages the Animation Curves for Humanoid Q/T channels.
|
||||
[System.Serializable]
|
||||
public class BakerHumanoidQT
|
||||
{
|
||||
|
||||
private Transform transform;
|
||||
private string Qx, Qy, Qz, Qw;
|
||||
private string Tx, Ty, Tz;
|
||||
|
||||
// Animation curves for each channel of the Transform
|
||||
public AnimationCurve rotX, rotY, rotZ, rotW;
|
||||
public AnimationCurve posX, posY, posZ;
|
||||
|
||||
private AvatarIKGoal goal;
|
||||
private Quaternion lastQ;
|
||||
private bool lastQSet;
|
||||
|
||||
// The custom constructor
|
||||
public BakerHumanoidQT(string name)
|
||||
{
|
||||
Qx = name + "Q.x";
|
||||
Qy = name + "Q.y";
|
||||
Qz = name + "Q.z";
|
||||
Qw = name + "Q.w";
|
||||
|
||||
Tx = name + "T.x";
|
||||
Ty = name + "T.y";
|
||||
Tz = name + "T.z";
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
public BakerHumanoidQT(Transform transform, AvatarIKGoal goal, string name)
|
||||
{
|
||||
this.transform = transform;
|
||||
this.goal = goal;
|
||||
|
||||
Qx = name + "Q.x";
|
||||
Qy = name + "Q.y";
|
||||
Qz = name + "Q.z";
|
||||
Qw = name + "Q.w";
|
||||
|
||||
Tx = name + "T.x";
|
||||
Ty = name + "T.y";
|
||||
Tz = name + "T.z";
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
public Quaternion EvaluateRotation(float time)
|
||||
{
|
||||
Quaternion q = new Quaternion(rotX.Evaluate(time), rotY.Evaluate(time), rotZ.Evaluate(time), rotW.Evaluate(time));
|
||||
return q;
|
||||
//return q.normalized;
|
||||
}
|
||||
|
||||
public Vector3 EvaluatePosition(float time)
|
||||
{
|
||||
return new Vector3(posX.Evaluate(time), posY.Evaluate(time), posZ.Evaluate(time));
|
||||
}
|
||||
|
||||
public TQ Evaluate(float time)
|
||||
{
|
||||
return new TQ(EvaluatePosition(time), EvaluateRotation(time));
|
||||
}
|
||||
|
||||
public void GetCurvesFromClip(AnimationClip clip, Animator animator)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
rotX = GetEditorCurve(clip, Qx);
|
||||
rotY = GetEditorCurve(clip, Qy);
|
||||
rotZ = GetEditorCurve(clip, Qz);
|
||||
rotW = GetEditorCurve(clip, Qw);
|
||||
|
||||
posX = GetEditorCurve(clip, Tx);
|
||||
posY = GetEditorCurve(clip, Ty);
|
||||
posZ = GetEditorCurve(clip, Tz);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private AnimationCurve GetEditorCurve(AnimationClip clip, string propertyPath)
|
||||
{
|
||||
var binding = UnityEditor.EditorCurveBinding.FloatCurve(string.Empty, typeof(Animator), propertyPath);
|
||||
return UnityEditor.AnimationUtility.GetEditorCurve(clip, binding);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Clear all curves
|
||||
public void Reset()
|
||||
{
|
||||
rotX = new AnimationCurve();
|
||||
rotY = new AnimationCurve();
|
||||
rotZ = new AnimationCurve();
|
||||
rotW = new AnimationCurve();
|
||||
|
||||
posX = new AnimationCurve();
|
||||
posY = new AnimationCurve();
|
||||
posZ = new AnimationCurve();
|
||||
|
||||
lastQ = Quaternion.identity;
|
||||
lastQSet = false;
|
||||
}
|
||||
|
||||
public void SetIKKeyframes(float time, Avatar avatar, Transform root, float humanScale, Vector3 bodyPosition, Quaternion bodyRotation)
|
||||
{
|
||||
Vector3 bonePos = transform.position;
|
||||
Quaternion boneRot = transform.rotation;
|
||||
|
||||
if (root.parent != null)
|
||||
{
|
||||
bonePos = root.parent.InverseTransformPoint(bonePos);
|
||||
boneRot = Quaternion.Inverse(root.parent.rotation) * boneRot;
|
||||
}
|
||||
|
||||
TQ IKTQ = AvatarUtility.GetIKGoalTQ(avatar, humanScale, goal, new TQ(bodyPosition, bodyRotation), new TQ(bonePos, boneRot));
|
||||
|
||||
Quaternion rot = IKTQ.q;
|
||||
if (lastQSet) rot = BakerUtilities.EnsureQuaternionContinuity(lastQ, IKTQ.q);
|
||||
|
||||
//rot.Normalize();
|
||||
|
||||
lastQ = rot;
|
||||
lastQSet = true;
|
||||
|
||||
rotX.AddKey(time, rot.x);
|
||||
rotY.AddKey(time, rot.y);
|
||||
rotZ.AddKey(time, rot.z);
|
||||
rotW.AddKey(time, rot.w);
|
||||
|
||||
Vector3 pos = IKTQ.t;
|
||||
posX.AddKey(time, pos.x);
|
||||
posY.AddKey(time, pos.y);
|
||||
posZ.AddKey(time, pos.z);
|
||||
}
|
||||
|
||||
public void SetKeyframes(float time, Vector3 pos, Quaternion rot)
|
||||
{
|
||||
// Rotation flipping already prevented in HumanoidBaker.UpdateHumanPose().
|
||||
rotX.AddKey(time, rot.x);
|
||||
rotY.AddKey(time, rot.y);
|
||||
rotZ.AddKey(time, rot.z);
|
||||
rotW.AddKey(time, rot.w);
|
||||
|
||||
posX.AddKey(time, pos.x);
|
||||
posY.AddKey(time, pos.y);
|
||||
posZ.AddKey(time, pos.z);
|
||||
}
|
||||
|
||||
public void MoveLastKeyframes(float time)
|
||||
{
|
||||
MoveLastKeyframe(time, rotX);
|
||||
MoveLastKeyframe(time, rotY);
|
||||
MoveLastKeyframe(time, rotZ);
|
||||
MoveLastKeyframe(time, rotW);
|
||||
|
||||
MoveLastKeyframe(time, posX);
|
||||
MoveLastKeyframe(time, posY);
|
||||
MoveLastKeyframe(time, posZ);
|
||||
}
|
||||
|
||||
// Add a copy of the first frame to the specified time
|
||||
public void SetLoopFrame(float time)
|
||||
{
|
||||
BakerUtilities.SetLoopFrame(time, rotX);
|
||||
BakerUtilities.SetLoopFrame(time, rotY);
|
||||
BakerUtilities.SetLoopFrame(time, rotZ);
|
||||
BakerUtilities.SetLoopFrame(time, rotW);
|
||||
|
||||
BakerUtilities.SetLoopFrame(time, posX);
|
||||
BakerUtilities.SetLoopFrame(time, posY);
|
||||
BakerUtilities.SetLoopFrame(time, posZ);
|
||||
}
|
||||
|
||||
public void SetRootLoopFrame(float time)
|
||||
{
|
||||
/*
|
||||
// TODO Should be based on AnimationClipSettings
|
||||
BakerUtilities.SetLoopFrame(time, rotX);
|
||||
BakerUtilities.SetLoopFrame(time, rotY);
|
||||
BakerUtilities.SetLoopFrame(time, rotZ);
|
||||
BakerUtilities.SetLoopFrame(time, rotW);
|
||||
|
||||
BakerUtilities.SetLoopFrame(time, posY);
|
||||
*/
|
||||
}
|
||||
|
||||
private void MoveLastKeyframe(float time, AnimationCurve curve)
|
||||
{
|
||||
Keyframe[] keys = curve.keys;
|
||||
keys[keys.Length - 1].time = time;
|
||||
curve.keys = keys;
|
||||
}
|
||||
|
||||
public void MultiplyLength(AnimationCurve curve, float mlp)
|
||||
{
|
||||
Keyframe[] keys = curve.keys;
|
||||
for (int i = 0; i < keys.Length; i++)
|
||||
{
|
||||
keys[i].time *= mlp;
|
||||
}
|
||||
curve.keys = keys;
|
||||
}
|
||||
|
||||
// Add curves to the AnimationClip for each channel
|
||||
public void SetCurves(ref AnimationClip clip, float maxError, float lengthMlp)
|
||||
{
|
||||
MultiplyLength(rotX, lengthMlp);
|
||||
MultiplyLength(rotY, lengthMlp);
|
||||
MultiplyLength(rotZ, lengthMlp);
|
||||
MultiplyLength(rotW, lengthMlp);
|
||||
|
||||
MultiplyLength(posX, lengthMlp);
|
||||
MultiplyLength(posY, lengthMlp);
|
||||
MultiplyLength(posZ, lengthMlp);
|
||||
|
||||
BakerUtilities.ReduceKeyframes(rotX, maxError);
|
||||
BakerUtilities.ReduceKeyframes(rotY, maxError);
|
||||
BakerUtilities.ReduceKeyframes(rotZ, maxError);
|
||||
BakerUtilities.ReduceKeyframes(rotW, maxError);
|
||||
|
||||
BakerUtilities.ReduceKeyframes(posX, maxError);
|
||||
BakerUtilities.ReduceKeyframes(posY, maxError);
|
||||
BakerUtilities.ReduceKeyframes(posZ, maxError);
|
||||
|
||||
BakerUtilities.SetTangentMode(rotX);
|
||||
BakerUtilities.SetTangentMode(rotY);
|
||||
BakerUtilities.SetTangentMode(rotZ);
|
||||
BakerUtilities.SetTangentMode(rotW);
|
||||
|
||||
/*
|
||||
BakerUtilities.SetTangentMode(posX);
|
||||
BakerUtilities.SetTangentMode(posY);
|
||||
BakerUtilities.SetTangentMode(posZ);
|
||||
*/
|
||||
|
||||
clip.SetCurve(string.Empty, typeof(Animator), Qx, rotX);
|
||||
clip.SetCurve(string.Empty, typeof(Animator), Qy, rotY);
|
||||
clip.SetCurve(string.Empty, typeof(Animator), Qz, rotZ);
|
||||
clip.SetCurve(string.Empty, typeof(Animator), Qw, rotW);
|
||||
|
||||
clip.SetCurve(string.Empty, typeof(Animator), Tx, posX);
|
||||
clip.SetCurve(string.Empty, typeof(Animator), Ty, posY);
|
||||
clip.SetCurve(string.Empty, typeof(Animator), Tz, posZ);
|
||||
}
|
||||
}
|
||||
|
||||
// Manages the Animation Curves for a single Transform that is a child of the root Transform.
|
||||
[System.Serializable]
|
||||
public class BakerMuscle
|
||||
{
|
||||
|
||||
// Animation curves for each channel of the Transform
|
||||
public AnimationCurve curve;
|
||||
|
||||
private int muscleIndex = -1;
|
||||
private string propertyName;
|
||||
|
||||
// The custom constructor
|
||||
public BakerMuscle(int muscleIndex)
|
||||
{
|
||||
this.muscleIndex = muscleIndex;
|
||||
this.propertyName = MuscleNameToPropertyName(HumanTrait.MuscleName[muscleIndex]);
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
private string MuscleNameToPropertyName(string n)
|
||||
{
|
||||
// Left fingers
|
||||
if (n == "Left Index 1 Stretched") return "LeftHand.Index.1 Stretched";
|
||||
if (n == "Left Index 2 Stretched") return "LeftHand.Index.2 Stretched";
|
||||
if (n == "Left Index 3 Stretched") return "LeftHand.Index.3 Stretched";
|
||||
|
||||
if (n == "Left Middle 1 Stretched") return "LeftHand.Middle.1 Stretched";
|
||||
if (n == "Left Middle 2 Stretched") return "LeftHand.Middle.2 Stretched";
|
||||
if (n == "Left Middle 3 Stretched") return "LeftHand.Middle.3 Stretched";
|
||||
|
||||
if (n == "Left Ring 1 Stretched") return "LeftHand.Ring.1 Stretched";
|
||||
if (n == "Left Ring 2 Stretched") return "LeftHand.Ring.2 Stretched";
|
||||
if (n == "Left Ring 3 Stretched") return "LeftHand.Ring.3 Stretched";
|
||||
|
||||
if (n == "Left Little 1 Stretched") return "LeftHand.Little.1 Stretched";
|
||||
if (n == "Left Little 2 Stretched") return "LeftHand.Little.2 Stretched";
|
||||
if (n == "Left Little 3 Stretched") return "LeftHand.Little.3 Stretched";
|
||||
|
||||
if (n == "Left Thumb 1 Stretched") return "LeftHand.Thumb.1 Stretched";
|
||||
if (n == "Left Thumb 2 Stretched") return "LeftHand.Thumb.2 Stretched";
|
||||
if (n == "Left Thumb 3 Stretched") return "LeftHand.Thumb.3 Stretched";
|
||||
|
||||
if (n == "Left Index Spread") return "LeftHand.Index.Spread";
|
||||
if (n == "Left Middle Spread") return "LeftHand.Middle.Spread";
|
||||
if (n == "Left Ring Spread") return "LeftHand.Ring.Spread";
|
||||
if (n == "Left Little Spread") return "LeftHand.Little.Spread";
|
||||
if (n == "Left Thumb Spread") return "LeftHand.Thumb.Spread";
|
||||
|
||||
// Right fingers
|
||||
if (n == "Right Index 1 Stretched") return "RightHand.Index.1 Stretched";
|
||||
if (n == "Right Index 2 Stretched") return "RightHand.Index.2 Stretched";
|
||||
if (n == "Right Index 3 Stretched") return "RightHand.Index.3 Stretched";
|
||||
|
||||
if (n == "Right Middle 1 Stretched") return "RightHand.Middle.1 Stretched";
|
||||
if (n == "Right Middle 2 Stretched") return "RightHand.Middle.2 Stretched";
|
||||
if (n == "Right Middle 3 Stretched") return "RightHand.Middle.3 Stretched";
|
||||
|
||||
if (n == "Right Ring 1 Stretched") return "RightHand.Ring.1 Stretched";
|
||||
if (n == "Right Ring 2 Stretched") return "RightHand.Ring.2 Stretched";
|
||||
if (n == "Right Ring 3 Stretched") return "RightHand.Ring.3 Stretched";
|
||||
|
||||
if (n == "Right Little 1 Stretched") return "RightHand.Little.1 Stretched";
|
||||
if (n == "Right Little 2 Stretched") return "RightHand.Little.2 Stretched";
|
||||
if (n == "Right Little 3 Stretched") return "RightHand.Little.3 Stretched";
|
||||
|
||||
if (n == "Right Thumb 1 Stretched") return "RightHand.Thumb.1 Stretched";
|
||||
if (n == "Right Thumb 2 Stretched") return "RightHand.Thumb.2 Stretched";
|
||||
if (n == "Right Thumb 3 Stretched") return "RightHand.Thumb.3 Stretched";
|
||||
|
||||
if (n == "Right Index Spread") return "RightHand.Index.Spread";
|
||||
if (n == "Right Middle Spread") return "RightHand.Middle.Spread";
|
||||
if (n == "Right Ring Spread") return "RightHand.Ring.Spread";
|
||||
if (n == "Right Little Spread") return "RightHand.Little.Spread";
|
||||
if (n == "Right Thumb Spread") return "RightHand.Thumb.Spread";
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
public void MultiplyLength(AnimationCurve curve, float mlp)
|
||||
{
|
||||
Keyframe[] keys = curve.keys;
|
||||
for (int i = 0; i < keys.Length; i++)
|
||||
{
|
||||
keys[i].time *= mlp;
|
||||
}
|
||||
curve.keys = keys;
|
||||
}
|
||||
|
||||
// Add curves to the AnimationClip for each channel
|
||||
public void SetCurves(ref AnimationClip clip, float maxError, float lengthMlp)
|
||||
{
|
||||
MultiplyLength(curve, lengthMlp);
|
||||
BakerUtilities.ReduceKeyframes(curve, maxError);
|
||||
|
||||
// BakerUtilities.SetTangentMode(curve);
|
||||
|
||||
clip.SetCurve(string.Empty, typeof(Animator), propertyName, curve);
|
||||
}
|
||||
|
||||
// Clear all curves
|
||||
public void Reset()
|
||||
{
|
||||
curve = new AnimationCurve();
|
||||
}
|
||||
|
||||
// Record a keyframe for each channel
|
||||
public void SetKeyframe(float time, float[] muscles)
|
||||
{
|
||||
curve.AddKey(time, muscles[muscleIndex]);
|
||||
}
|
||||
|
||||
// Add a copy of the first frame to the specified time
|
||||
public void SetLoopFrame(float time)
|
||||
{
|
||||
BakerUtilities.SetLoopFrame(time, curve);
|
||||
}
|
||||
}
|
||||
|
||||
//Manages the Animation Curves for a single Transform that is a child of the root Transform.
|
||||
[System.Serializable]
|
||||
public class BakerTransform
|
||||
{
|
||||
|
||||
public Transform transform; // The Transform component to record
|
||||
|
||||
// Animation curves for each channel of the Transform
|
||||
public AnimationCurve
|
||||
posX, posY, posZ,
|
||||
rotX, rotY, rotZ, rotW;
|
||||
|
||||
private string relativePath; // Path relative to the root
|
||||
private bool recordPosition; // Should we record the localPosition if the transform?
|
||||
private Vector3 relativePosition;
|
||||
private bool isRootNode;
|
||||
private Quaternion relativeRotation;
|
||||
|
||||
// The custom constructor
|
||||
public BakerTransform(Transform transform, Transform root, bool recordPosition, bool isRootNode)
|
||||
{
|
||||
this.transform = transform;
|
||||
this.recordPosition = recordPosition || isRootNode;
|
||||
this.isRootNode = isRootNode;
|
||||
|
||||
relativePath = string.Empty;
|
||||
#if UNITY_EDITOR
|
||||
relativePath = UnityEditor.AnimationUtility.CalculateTransformPath(transform, root);
|
||||
#endif
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
public void SetRelativeSpace(Vector3 position, Quaternion rotation)
|
||||
{
|
||||
relativePosition = position;
|
||||
relativeRotation = rotation;
|
||||
}
|
||||
|
||||
// Add curves to the AnimationClip for each channel
|
||||
public void SetCurves(ref AnimationClip clip)
|
||||
{
|
||||
if (recordPosition)
|
||||
{
|
||||
clip.SetCurve(relativePath, typeof(Transform), "localPosition.x", posX);
|
||||
clip.SetCurve(relativePath, typeof(Transform), "localPosition.y", posY);
|
||||
clip.SetCurve(relativePath, typeof(Transform), "localPosition.z", posZ);
|
||||
}
|
||||
|
||||
clip.SetCurve(relativePath, typeof(Transform), "localRotation.x", rotX);
|
||||
clip.SetCurve(relativePath, typeof(Transform), "localRotation.y", rotY);
|
||||
clip.SetCurve(relativePath, typeof(Transform), "localRotation.z", rotZ);
|
||||
clip.SetCurve(relativePath, typeof(Transform), "localRotation.w", rotW);
|
||||
|
||||
if (isRootNode) AddRootMotionCurves(ref clip);
|
||||
|
||||
// @todo probably only need to do it once for the clip
|
||||
clip.EnsureQuaternionContinuity(); // DOH!
|
||||
}
|
||||
|
||||
private void AddRootMotionCurves(ref AnimationClip clip)
|
||||
{
|
||||
if (recordPosition)
|
||||
{
|
||||
clip.SetCurve("", typeof(Animator), "MotionT.x", posX);
|
||||
clip.SetCurve("", typeof(Animator), "MotionT.y", posY);
|
||||
clip.SetCurve("", typeof(Animator), "MotionT.z", posZ);
|
||||
}
|
||||
|
||||
clip.SetCurve("", typeof(Animator), "MotionQ.x", rotX);
|
||||
clip.SetCurve("", typeof(Animator), "MotionQ.y", rotY);
|
||||
clip.SetCurve("", typeof(Animator), "MotionQ.z", rotZ);
|
||||
clip.SetCurve("", typeof(Animator), "MotionQ.w", rotW);
|
||||
}
|
||||
|
||||
// Clear all curves
|
||||
public void Reset()
|
||||
{
|
||||
posX = new AnimationCurve();
|
||||
posY = new AnimationCurve();
|
||||
posZ = new AnimationCurve();
|
||||
|
||||
rotX = new AnimationCurve();
|
||||
rotY = new AnimationCurve();
|
||||
rotZ = new AnimationCurve();
|
||||
rotW = new AnimationCurve();
|
||||
}
|
||||
|
||||
public void ReduceKeyframes(float maxError)
|
||||
{
|
||||
BakerUtilities.ReduceKeyframes(rotX, maxError);
|
||||
BakerUtilities.ReduceKeyframes(rotY, maxError);
|
||||
BakerUtilities.ReduceKeyframes(rotZ, maxError);
|
||||
BakerUtilities.ReduceKeyframes(rotW, maxError);
|
||||
|
||||
BakerUtilities.ReduceKeyframes(posX, maxError);
|
||||
BakerUtilities.ReduceKeyframes(posY, maxError);
|
||||
BakerUtilities.ReduceKeyframes(posZ, maxError);
|
||||
}
|
||||
|
||||
// Record a keyframe for each channel
|
||||
public void SetKeyframes(float time)
|
||||
{
|
||||
if (recordPosition)
|
||||
{
|
||||
Vector3 pos = transform.localPosition;
|
||||
|
||||
if (isRootNode)
|
||||
{
|
||||
pos = transform.position - relativePosition;
|
||||
}
|
||||
|
||||
posX.AddKey(time, pos.x);
|
||||
posY.AddKey(time, pos.y);
|
||||
posZ.AddKey(time, pos.z);
|
||||
}
|
||||
|
||||
Quaternion rot = transform.localRotation;
|
||||
|
||||
if (isRootNode)
|
||||
{
|
||||
rot = Quaternion.Inverse(relativeRotation) * transform.rotation;
|
||||
}
|
||||
|
||||
rotX.AddKey(time, rot.x);
|
||||
rotY.AddKey(time, rot.y);
|
||||
rotZ.AddKey(time, rot.z);
|
||||
rotW.AddKey(time, rot.w);
|
||||
}
|
||||
|
||||
// Add a copy of the first frame to the specified time
|
||||
public void AddLoopFrame(float time)
|
||||
{
|
||||
// TODO change to SetLoopFrame
|
||||
if (recordPosition && !isRootNode)
|
||||
{
|
||||
posX.AddKey(time, posX.keys[0].value);
|
||||
posY.AddKey(time, posY.keys[0].value);
|
||||
posZ.AddKey(time, posZ.keys[0].value);
|
||||
}
|
||||
|
||||
rotX.AddKey(time, rotX.keys[0].value);
|
||||
rotY.AddKey(time, rotY.keys[0].value);
|
||||
rotZ.AddKey(time, rotZ.keys[0].value);
|
||||
rotW.AddKey(time, rotW.keys[0].value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 582052db0a6096149a7b2b75914ef3a6
|
||||
timeCreated: 1516263395
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
196
LocalPackages/FinalIK/Runtime/Baker/Scripts/HumanoidBaker.cs
Normal file
@@ -0,0 +1,196 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using UnityEngine.Playables;
|
||||
|
||||
namespace RootMotion
|
||||
{
|
||||
/// <summary>
|
||||
/// Baker for Humanoid animation.
|
||||
/// </summary>
|
||||
public class HumanoidBaker : Baker
|
||||
{
|
||||
/// <summary>
|
||||
/// Should the hand IK curves be added to the animation? Disable this if the original hand positions are not important when using the clip on another character via Humanoid retargeting.
|
||||
/// </summary>
|
||||
[Tooltip("Should the hand IK curves be added to the animation? Disable this if the original hand positions are not important when using the clip on another character via Humanoid retargeting.")]
|
||||
public bool bakeHandIK = true;
|
||||
|
||||
/// <summary>
|
||||
/// Max keyframe reduction error for the Root.Q/T, LeftFoot IK and RightFoot IK channels. Having a larger error value for 'Key Reduction Error' and a smaller one for this enables you to optimize clip data size without the floating feet effect by enabling 'Foot IK' in the Animator.
|
||||
/// </summary>
|
||||
[Tooltip("Max keyframe reduction error for the Root.Q/T, LeftFoot IK and RightFoot IK channels. Having a larger error value for 'Key Reduction Error' and a smaller one for this enables you to optimize clip data size without the floating feet effect by enabling 'Foot IK' in the Animator.")]
|
||||
[Range(0f, 0.1f)] public float IKKeyReductionError;
|
||||
|
||||
/// <summary>
|
||||
/// Frame rate divider for the muscle curves. If you had 'Frame Rate' set to 30, and this value set to 3, the muscle curves will be baked at 10 fps. Only the Root Q/T and Hand and Foot IK curves will be baked at 30. This enables you to optimize clip data size without the floating feet effect by enabling 'Foot IK' in the Animator.
|
||||
/// </summary>
|
||||
[Tooltip("Frame rate divider for the muscle curves. If you have 'Frame Rate' set to 30, and this value set to 3, the muscle curves will be baked at 10 fps. Only the Root Q/T and Hand and Foot IK curves will be baked at 30. This enables you to optimize clip data size without the floating feet effect by enabling 'Foot IK' in the Animator.")]
|
||||
[Range(1, 9)] public int muscleFrameRateDiv = 1;
|
||||
|
||||
private BakerMuscle[] bakerMuscles;
|
||||
private BakerHumanoidQT rootQT;
|
||||
private BakerHumanoidQT leftFootQT;
|
||||
private BakerHumanoidQT rightFootQT;
|
||||
private BakerHumanoidQT leftHandQT;
|
||||
private BakerHumanoidQT rightHandQT;
|
||||
|
||||
private float[] muscles = new float[0];
|
||||
private HumanPose pose = new HumanPose();
|
||||
private HumanPoseHandler handler;
|
||||
private Vector3 bodyPosition;
|
||||
private Quaternion bodyRotation = Quaternion.identity;
|
||||
private int mN = 0;
|
||||
private Quaternion lastBodyRotation = Quaternion.identity;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
animator = GetComponent<Animator>();
|
||||
director = GetComponent<PlayableDirector>();
|
||||
|
||||
if (mode == Mode.AnimationStates || mode == Mode.AnimationClips)
|
||||
{
|
||||
if (animator == null || !animator.isHuman)
|
||||
{
|
||||
Debug.LogError("HumanoidBaker GameObject does not have a Humanoid Animator component, can not bake.");
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
animator.cullingMode = AnimatorCullingMode.AlwaysAnimate;
|
||||
}
|
||||
else if (mode == Mode.PlayableDirector)
|
||||
{
|
||||
if (director == null)
|
||||
{
|
||||
Debug.LogError("HumanoidBaker GameObject does not have a PlayableDirector component, can not bake.");
|
||||
}
|
||||
}
|
||||
|
||||
muscles = new float[HumanTrait.MuscleCount];
|
||||
bakerMuscles = new BakerMuscle[HumanTrait.MuscleCount];
|
||||
for (int i = 0; i < bakerMuscles.Length; i++)
|
||||
{
|
||||
bakerMuscles[i] = new BakerMuscle(i);
|
||||
}
|
||||
|
||||
rootQT = new BakerHumanoidQT("Root");
|
||||
|
||||
leftFootQT = new BakerHumanoidQT(animator.GetBoneTransform(HumanBodyBones.LeftFoot), AvatarIKGoal.LeftFoot, "LeftFoot");
|
||||
rightFootQT = new BakerHumanoidQT(animator.GetBoneTransform(HumanBodyBones.RightFoot), AvatarIKGoal.RightFoot, "RightFoot");
|
||||
leftHandQT = new BakerHumanoidQT(animator.GetBoneTransform(HumanBodyBones.LeftHand), AvatarIKGoal.LeftHand, "LeftHand");
|
||||
rightHandQT = new BakerHumanoidQT(animator.GetBoneTransform(HumanBodyBones.RightHand), AvatarIKGoal.RightHand, "RightHand");
|
||||
|
||||
handler = new HumanPoseHandler(animator.avatar, animator.transform);
|
||||
}
|
||||
|
||||
protected override Transform GetCharacterRoot()
|
||||
{
|
||||
return animator.transform;
|
||||
}
|
||||
|
||||
protected override void OnStartBaking()
|
||||
{
|
||||
|
||||
rootQT.Reset();
|
||||
leftFootQT.Reset();
|
||||
rightFootQT.Reset();
|
||||
leftHandQT.Reset();
|
||||
rightHandQT.Reset();
|
||||
|
||||
for (int i = 0; i < bakerMuscles.Length; i++)
|
||||
{
|
||||
bakerMuscles[i].Reset();
|
||||
}
|
||||
|
||||
mN = muscleFrameRateDiv;
|
||||
|
||||
lastBodyRotation = Quaternion.identity;
|
||||
}
|
||||
|
||||
protected override void OnSetLoopFrame(float time)
|
||||
{
|
||||
for (int i = 0; i < bakerMuscles.Length; i++) bakerMuscles[i].SetLoopFrame(time);
|
||||
|
||||
rootQT.MoveLastKeyframes(time);
|
||||
|
||||
leftFootQT.SetLoopFrame(time);
|
||||
rightFootQT.SetLoopFrame(time);
|
||||
leftHandQT.SetLoopFrame(time);
|
||||
rightHandQT.SetLoopFrame(time);
|
||||
}
|
||||
|
||||
protected override void OnSetCurves(ref AnimationClip clip)
|
||||
{
|
||||
float length = bakerMuscles[0].curve.keys[bakerMuscles[0].curve.keys.Length - 1].time;
|
||||
float lengthMlp = mode != Mode.Realtime ? clipLength / length : 1f;
|
||||
|
||||
for (int i = 0; i < bakerMuscles.Length; i++) bakerMuscles[i].SetCurves(ref clip, keyReductionError, lengthMlp);
|
||||
|
||||
rootQT.SetCurves(ref clip, IKKeyReductionError, lengthMlp);
|
||||
leftFootQT.SetCurves(ref clip, IKKeyReductionError, lengthMlp);
|
||||
rightFootQT.SetCurves(ref clip, IKKeyReductionError, lengthMlp);
|
||||
|
||||
if (bakeHandIK)
|
||||
{
|
||||
leftHandQT.SetCurves(ref clip, IKKeyReductionError, lengthMlp);
|
||||
rightHandQT.SetCurves(ref clip, IKKeyReductionError, lengthMlp);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnSetKeyframes(float time, bool lastFrame)
|
||||
{
|
||||
// Skip muscle frames
|
||||
mN++;
|
||||
bool updateMuscles = true;
|
||||
if (mN < muscleFrameRateDiv && !lastFrame)
|
||||
{
|
||||
updateMuscles = false;
|
||||
}
|
||||
if (mN >= muscleFrameRateDiv) mN = 0;
|
||||
|
||||
UpdateHumanPose();
|
||||
|
||||
if (updateMuscles)
|
||||
{
|
||||
for (int i = 0; i < bakerMuscles.Length; i++) bakerMuscles[i].SetKeyframe(time, muscles);
|
||||
}
|
||||
|
||||
rootQT.SetKeyframes(time, bodyPosition, bodyRotation);
|
||||
|
||||
Vector3 bodyPositionScaled = bodyPosition * animator.humanScale;
|
||||
leftFootQT.SetIKKeyframes(time, animator.avatar, animator.transform, animator.humanScale, bodyPositionScaled, bodyRotation);
|
||||
rightFootQT.SetIKKeyframes(time, animator.avatar, animator.transform, animator.humanScale, bodyPositionScaled, bodyRotation);
|
||||
|
||||
leftHandQT.SetIKKeyframes(time, animator.avatar, animator.transform, animator.humanScale, bodyPositionScaled, bodyRotation);
|
||||
rightHandQT.SetIKKeyframes(time, animator.avatar, animator.transform, animator.humanScale, bodyPositionScaled, bodyRotation);
|
||||
}
|
||||
|
||||
private void UpdateHumanPose()
|
||||
{
|
||||
handler.GetHumanPose(ref pose);
|
||||
|
||||
bodyPosition = pose.bodyPosition;
|
||||
bodyRotation = pose.bodyRotation;
|
||||
|
||||
bodyRotation = BakerUtilities.EnsureQuaternionContinuity(lastBodyRotation, bodyRotation);
|
||||
lastBodyRotation = bodyRotation;
|
||||
|
||||
for (int i = 0; i < pose.muscles.Length; i++)
|
||||
{
|
||||
muscles[i] = pose.muscles[i];
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
protected override void SetClipSettings(AnimationClip clip, UnityEditor.AnimationClipSettings settings)
|
||||
{
|
||||
/* v2.0
|
||||
settings.loopBlendOrientation = true;
|
||||
settings.loopBlendPositionY = true;
|
||||
settings.keepOriginalOrientation = true;
|
||||
settings.keepOriginalPositionY = true;
|
||||
*/
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: efcc0ec5ed265a340a1412edb9110337
|
||||
timeCreated: 1516287616
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 15000
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
9
LocalPackages/FinalIK/Runtime/Baker/_DEMOS.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c41cf13236c01a747b3dfb963402b3a0
|
||||
folderAsset: yes
|
||||
timeCreated: 1516620909
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a4b02f60233a6cf4eb1c424f90323213
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
11611
LocalPackages/FinalIK/Runtime/Baker/_DEMOS/Baked Clips/Clip 1_Baked.anim
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3451f091c656bfc429396cc701ac5b8d
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 7400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,69 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!91 &9100000
|
||||
AnimatorController:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 0}
|
||||
m_Name: Humanoid Baker Clip Sampler
|
||||
serializedVersion: 5
|
||||
m_AnimatorParameters: []
|
||||
m_AnimatorLayers:
|
||||
- serializedVersion: 5
|
||||
m_Name: Base Layer
|
||||
m_StateMachine: {fileID: 110737558}
|
||||
m_Mask: {fileID: 0}
|
||||
m_Motions: []
|
||||
m_Behaviours: []
|
||||
m_BlendingMode: 0
|
||||
m_SyncedLayerIndex: -1
|
||||
m_DefaultWeight: 0
|
||||
m_IKPass: 0
|
||||
m_SyncedLayerAffectsTiming: 0
|
||||
m_Controller: {fileID: 9100000}
|
||||
--- !u!1102 &110235224
|
||||
AnimatorState:
|
||||
serializedVersion: 5
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 0}
|
||||
m_Name: Clip 1
|
||||
m_Speed: 1
|
||||
m_CycleOffset: 0
|
||||
m_Transitions: []
|
||||
m_StateMachineBehaviours: []
|
||||
m_Position: {x: 50, y: 50, z: 0}
|
||||
m_IKOnFeet: 1
|
||||
m_WriteDefaultValues: 1
|
||||
m_Mirror: 0
|
||||
m_SpeedParameterActive: 0
|
||||
m_MirrorParameterActive: 0
|
||||
m_CycleOffsetParameterActive: 0
|
||||
m_TimeParameterActive: 0
|
||||
m_Motion: {fileID: 7400000, guid: 739b2627204c24240aa40c4f67f59d0e, type: 3}
|
||||
m_Tag:
|
||||
m_SpeedParameter:
|
||||
m_MirrorParameter:
|
||||
m_CycleOffsetParameter:
|
||||
m_TimeParameter:
|
||||
--- !u!1107 &110737558
|
||||
AnimatorStateMachine:
|
||||
serializedVersion: 5
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 0}
|
||||
m_Name: Base Layer
|
||||
m_ChildStates:
|
||||
- serializedVersion: 1
|
||||
m_State: {fileID: 110235224}
|
||||
m_Position: {x: 300, y: 36, z: 0}
|
||||
m_ChildStateMachines: []
|
||||
m_AnyStateTransitions: []
|
||||
m_EntryTransitions: []
|
||||
m_StateMachineTransitions: {}
|
||||
m_StateMachineBehaviours: []
|
||||
m_AnyStatePosition: {x: 50, y: 20, z: 0}
|
||||
m_EntryPosition: {x: 50, y: 120, z: 0}
|
||||
m_ExitPosition: {x: 800, y: 120, z: 0}
|
||||
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
|
||||
m_DefaultState: {fileID: 110235224}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 24d41cb619dc9dc42bf10705eb128c97
|
||||
timeCreated: 1516284817
|
||||
licenseType: Store
|
||||
NativeFormatImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
2241
LocalPackages/FinalIK/Runtime/Baker/_DEMOS/Humanoid Baker.unity
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0bd8d9a8cbacde343967c95c4458318e
|
||||
timeCreated: 1517387718
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
LocalPackages/FinalIK/Runtime/Baker/_DEMOS/Scripts.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3349a7526568cf042bf8609694db3327
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,53 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace RootMotion.Demos
|
||||
{
|
||||
// Adds simple FK rotation offset to bones.
|
||||
public class FKOffset : MonoBehaviour
|
||||
{
|
||||
[System.Serializable]
|
||||
public class Offset
|
||||
{
|
||||
[HideInInspector] public string name;
|
||||
public HumanBodyBones bone;
|
||||
public Vector3 rotationOffset;
|
||||
|
||||
private Transform t;
|
||||
|
||||
public void Apply(Animator animator)
|
||||
{
|
||||
if (t == null) t = animator.GetBoneTransform(bone);
|
||||
if (t == null) return;
|
||||
|
||||
t.localRotation *= Quaternion.Euler(rotationOffset);
|
||||
}
|
||||
}
|
||||
|
||||
public Offset[] offsets;
|
||||
|
||||
private Animator animator;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
animator = GetComponent<Animator>();
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
foreach (Offset offset in offsets)
|
||||
{
|
||||
offset.Apply(animator);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDrawGizmosSelected()
|
||||
{
|
||||
foreach (Offset offset in offsets)
|
||||
{
|
||||
offset.name = offset.bone.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ea198996b9a58624b82f921e56faf4ba
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
9
LocalPackages/FinalIK/Runtime/FinalIK.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 934bb813ebad34517a1b22565370b2af
|
||||
folderAsset: yes
|
||||
timeCreated: 1434626794
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
9
LocalPackages/FinalIK/Runtime/FinalIK/BipedIK.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 24b4e6f1f9c204bc5bd16676aecf434d
|
||||
folderAsset: yes
|
||||
timeCreated: 1434626794
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
317
LocalPackages/FinalIK/Runtime/FinalIK/BipedIK/BipedIK.cs
Normal file
@@ -0,0 +1,317 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace RootMotion.FinalIK {
|
||||
|
||||
/// <summary>
|
||||
/// %IK system for standard biped characters that is designed to replicate and enhance the behaviour of the Unity's built-in character %IK setup.
|
||||
/// </summary>
|
||||
[HelpURL("http://www.root-motion.com/finalikdox/html/page4.html")]
|
||||
[AddComponentMenu("Scripts/RootMotion.FinalIK/IK/Biped IK")]
|
||||
public class BipedIK : SolverManager {
|
||||
|
||||
// Open the User Manual URL
|
||||
[ContextMenu("User Manual")]
|
||||
private void OpenUserManual() {
|
||||
Application.OpenURL("http://www.root-motion.com/finalikdox/html/page4.html");
|
||||
}
|
||||
|
||||
// Open the Script Reference URL
|
||||
[ContextMenu("Scrpt Reference")]
|
||||
private void OpenScriptReference() {
|
||||
Application.OpenURL("http://www.root-motion.com/finalikdox/html/class_root_motion_1_1_final_i_k_1_1_biped_i_k.html");
|
||||
}
|
||||
|
||||
// Link to the Final IK Google Group
|
||||
[ContextMenu("Support Group")]
|
||||
void SupportGroup() {
|
||||
Application.OpenURL("https://groups.google.com/forum/#!forum/final-ik");
|
||||
}
|
||||
|
||||
// Link to the Final IK Asset Store thread in the Unity Community
|
||||
[ContextMenu("Asset Store Thread")]
|
||||
void ASThread() {
|
||||
Application.OpenURL("http://forum.unity3d.com/threads/final-ik-full-body-ik-aim-look-at-fabrik-ccd-ik-1-0-released.222685/");
|
||||
}
|
||||
|
||||
#region Main Interface
|
||||
|
||||
/// <summary>
|
||||
/// References to character bones.
|
||||
/// </summary>
|
||||
public BipedReferences references = new BipedReferences();
|
||||
/// <summary>
|
||||
/// The %IK solvers.
|
||||
/// </summary>
|
||||
public BipedIKSolvers solvers = new BipedIKSolvers();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the %IK position weight.
|
||||
/// </summary>
|
||||
/// <param name='goal'>
|
||||
/// %IK Goal.
|
||||
/// </param>
|
||||
public float GetIKPositionWeight(AvatarIKGoal goal) {
|
||||
return GetGoalIK(goal).GetIKPositionWeight();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the %IK rotation weight.
|
||||
/// </summary>
|
||||
/// <param name='goal'>
|
||||
/// IK Goal.
|
||||
/// </param>
|
||||
public float GetIKRotationWeight(AvatarIKGoal goal) {
|
||||
return GetGoalIK(goal).GetIKRotationWeight();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the %IK position weight.
|
||||
/// </summary>
|
||||
/// <param name='goal'>
|
||||
/// %IK Goal.
|
||||
/// </param>
|
||||
/// <param name='weight'>
|
||||
/// Weight.
|
||||
/// </param>
|
||||
public void SetIKPositionWeight(AvatarIKGoal goal, float weight) {
|
||||
GetGoalIK(goal).SetIKPositionWeight(weight);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the %IK rotation weight.
|
||||
/// </summary>
|
||||
/// <param name='goal'>
|
||||
/// %IK Goal.
|
||||
/// </param>
|
||||
/// <param name='weight'>
|
||||
/// Weight.
|
||||
/// </param>
|
||||
public void SetIKRotationWeight(AvatarIKGoal goal, float weight) {
|
||||
GetGoalIK(goal).SetIKRotationWeight(weight);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the %IK position.
|
||||
/// </summary>
|
||||
/// <param name='goal'>
|
||||
/// %IK Goal.
|
||||
/// </param>
|
||||
/// <param name='IKPosition'>
|
||||
/// Position.
|
||||
/// </param>
|
||||
public void SetIKPosition(AvatarIKGoal goal, Vector3 IKPosition) {
|
||||
GetGoalIK(goal).SetIKPosition(IKPosition);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the %IK rotation.
|
||||
/// </summary>
|
||||
/// <param name='goal'>
|
||||
/// %IK Goal.
|
||||
/// </param>
|
||||
/// <param name='IKRotation'>
|
||||
/// Rotation.
|
||||
/// </param>
|
||||
public void SetIKRotation(AvatarIKGoal goal, Quaternion IKRotation) {
|
||||
GetGoalIK(goal).SetIKRotation(IKRotation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the %IK position.
|
||||
/// </summary>
|
||||
/// <param name='goal'>
|
||||
/// %IK Goal.
|
||||
/// </param>
|
||||
public Vector3 GetIKPosition(AvatarIKGoal goal) {
|
||||
return GetGoalIK(goal).GetIKPosition();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the %IK rotation.
|
||||
/// </summary>
|
||||
/// <param name='goal'>
|
||||
/// %IK Goal.
|
||||
/// </param>
|
||||
public Quaternion GetIKRotation(AvatarIKGoal goal) {
|
||||
return GetGoalIK(goal).GetIKRotation();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the look at weight.
|
||||
/// </summary>
|
||||
/// <param name='weight'>
|
||||
/// Master Weight.
|
||||
/// </param>
|
||||
/// <param name='bodyWeight'>
|
||||
/// Body weight.
|
||||
/// </param>
|
||||
/// <param name='headWeight'>
|
||||
/// Head weight.
|
||||
/// </param>
|
||||
/// <param name='eyesWeight'>
|
||||
/// Eyes weight.
|
||||
/// </param>
|
||||
/// <param name='clampWeight'>
|
||||
/// Clamp weight for body and head.
|
||||
/// </param>
|
||||
/// <param name='clampWeightEyes'>
|
||||
/// Clamp weight for eyes.
|
||||
/// </param>
|
||||
public void SetLookAtWeight(float weight, float bodyWeight , float headWeight, float eyesWeight, float clampWeight, float clampWeightHead, float clampWeightEyes) {
|
||||
solvers.lookAt.SetLookAtWeight(weight, bodyWeight, headWeight, eyesWeight, clampWeight, clampWeightHead, clampWeightEyes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the look at target.
|
||||
/// </summary>
|
||||
/// <param name='lookAtPosition'>
|
||||
/// Look at position.
|
||||
/// </param>
|
||||
public void SetLookAtPosition(Vector3 lookAtPosition) {
|
||||
solvers.lookAt.SetIKPosition(lookAtPosition);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the spine %IK position.
|
||||
/// </summary>
|
||||
/// <param name='spinePosition'>
|
||||
/// Spine %IK position.
|
||||
/// </param>
|
||||
public void SetSpinePosition(Vector3 spinePosition) {
|
||||
solvers.spine.SetIKPosition(spinePosition);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the spine weight.
|
||||
/// </summary>
|
||||
/// <param name='weight'>
|
||||
/// Weight.
|
||||
/// </param>
|
||||
public void SetSpineWeight(float weight) {
|
||||
solvers.spine.SetIKPositionWeight(weight);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the limb solver for the %IK Goal.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The solver.
|
||||
/// </returns>
|
||||
/// <param name='goal'>
|
||||
/// %IK Goal.
|
||||
/// </param>
|
||||
public IKSolverLimb GetGoalIK(AvatarIKGoal goal) {
|
||||
switch(goal) {
|
||||
case AvatarIKGoal.LeftFoot: return solvers.leftFoot;
|
||||
case AvatarIKGoal.RightFoot: return solvers.rightFoot;
|
||||
case AvatarIKGoal.LeftHand: return solvers.leftHand;
|
||||
case AvatarIKGoal.RightHand: return solvers.rightHand;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// (Re)Initiates the biped IK solvers.
|
||||
/// </summary>
|
||||
public void InitiateBipedIK() {
|
||||
InitiateSolver();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updating BipedIK
|
||||
/// </summary>
|
||||
public void UpdateBipedIK() {
|
||||
UpdateSolver();
|
||||
}
|
||||
|
||||
/*
|
||||
* Set default solver values.
|
||||
* */
|
||||
public void SetToDefaults() {
|
||||
// Limbs
|
||||
foreach (IKSolverLimb limb in solvers.limbs) {
|
||||
limb.SetIKPositionWeight(0f);
|
||||
limb.SetIKRotationWeight(0f);
|
||||
limb.bendModifier = IKSolverLimb.BendModifier.Animation;
|
||||
limb.bendModifierWeight = 1f;
|
||||
}
|
||||
|
||||
solvers.leftHand.maintainRotationWeight = 0f;
|
||||
solvers.rightHand.maintainRotationWeight = 0f;
|
||||
|
||||
// Spine
|
||||
solvers.spine.SetIKPositionWeight(0f);
|
||||
solvers.spine.tolerance = 0f;
|
||||
solvers.spine.maxIterations = 2;
|
||||
solvers.spine.useRotationLimits = false;
|
||||
|
||||
// Aim
|
||||
solvers.aim.SetIKPositionWeight(0f);
|
||||
solvers.aim.tolerance = 0f;
|
||||
solvers.aim.maxIterations = 2;
|
||||
|
||||
// LookAt
|
||||
SetLookAtWeight(0f, 0.5f, 1f, 1f, 0.5f, 0.7f, 0.5f);
|
||||
}
|
||||
|
||||
#endregion Main Interface
|
||||
|
||||
/*
|
||||
* Fixes all the Transforms used by the solver to their default local states.
|
||||
* */
|
||||
protected override void FixTransforms() {
|
||||
solvers.pelvis.FixTransforms();
|
||||
solvers.lookAt.FixTransforms();
|
||||
for (int i = 0; i < solvers.limbs.Length; i++) solvers.limbs[i].FixTransforms();
|
||||
}
|
||||
|
||||
/*
|
||||
* Initiates the %IK solver
|
||||
* */
|
||||
protected override void InitiateSolver() {
|
||||
string message = "";
|
||||
if (BipedReferences.SetupError(references, ref message)) {
|
||||
Warning.Log(message, references.root, false);
|
||||
return;
|
||||
}
|
||||
solvers.AssignReferences(references);
|
||||
|
||||
// Initiating solvers
|
||||
if (solvers.spine.bones.Length > 1) solvers.spine.Initiate(transform);
|
||||
solvers.lookAt.Initiate(transform);
|
||||
solvers.aim.Initiate(transform);
|
||||
foreach (IKSolverLimb limb in solvers.limbs) limb.Initiate(transform);
|
||||
|
||||
// Initiating constraints
|
||||
solvers.pelvis.Initiate(references.pelvis);
|
||||
}
|
||||
|
||||
/*
|
||||
* Updates the solvers. If you need full control of the execution order of your IK solvers, disable this script and call UpdateSolver() instead.
|
||||
* */
|
||||
protected override void UpdateSolver() {
|
||||
// Storing Limb bend and rotation before %IK
|
||||
for (int i = 0; i < solvers.limbs.Length; i++) {
|
||||
solvers.limbs[i].MaintainBend();
|
||||
solvers.limbs[i].MaintainRotation();
|
||||
}
|
||||
|
||||
// Updating constraints
|
||||
solvers.pelvis.Update();
|
||||
|
||||
// Updating %IK solvers
|
||||
if (solvers.spine.bones.Length > 1) solvers.spine.Update();
|
||||
solvers.aim.Update();
|
||||
solvers.lookAt.Update();
|
||||
for (int i = 0; i < solvers.limbs.Length; i++) solvers.limbs[i].Update();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Logs the warning if no other warning has beed logged in this session.
|
||||
/// </summary>
|
||||
public void LogWarning(string message) {
|
||||
Warning.Log(message, transform);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6d406d8b892f54ccaa5b0ef4de59944a
|
||||
labels:
|
||||
- InverseKinematics
|
||||
- IK
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 9998
|
||||
icon: {fileID: 2800000, guid: 2631a18e2dd7844718dea7db8ecf6c03, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,89 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System;
|
||||
|
||||
namespace RootMotion.FinalIK {
|
||||
|
||||
/// <summary>
|
||||
/// BipedIK solver collection.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class BipedIKSolvers {
|
||||
/// <summary>
|
||||
/// The left foot
|
||||
/// </summary>
|
||||
public IKSolverLimb leftFoot = new IKSolverLimb(AvatarIKGoal.LeftFoot);
|
||||
/// <summary>
|
||||
/// The right foot.
|
||||
/// </summary>
|
||||
public IKSolverLimb rightFoot = new IKSolverLimb(AvatarIKGoal.RightFoot);
|
||||
/// <summary>
|
||||
/// The left hand.
|
||||
/// </summary>
|
||||
public IKSolverLimb leftHand = new IKSolverLimb(AvatarIKGoal.LeftHand);
|
||||
/// <summary>
|
||||
/// The right hand.
|
||||
/// </summary>
|
||||
public IKSolverLimb rightHand = new IKSolverLimb(AvatarIKGoal.RightHand);
|
||||
/// <summary>
|
||||
/// The spine.
|
||||
/// </summary>
|
||||
public IKSolverFABRIK spine = new IKSolverFABRIK();
|
||||
/// <summary>
|
||||
/// The Look At %IK.
|
||||
/// </summary>
|
||||
public IKSolverLookAt lookAt = new IKSolverLookAt();
|
||||
/// <summary>
|
||||
/// The Aim %IK. Rotates the spine to aim a transform's forward towards the target.
|
||||
/// </summary>
|
||||
public IKSolverAim aim = new IKSolverAim();
|
||||
/// <summary>
|
||||
/// %Constraints for manipulating the character's pelvis.
|
||||
/// </summary>
|
||||
public Constraints pelvis = new Constraints();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the array containing all the limbs.
|
||||
/// </summary>
|
||||
public IKSolverLimb[] limbs {
|
||||
get {
|
||||
if (_limbs == null || (_limbs != null && _limbs.Length != 4)) _limbs = new IKSolverLimb[4] { leftFoot, rightFoot, leftHand, rightHand };
|
||||
return _limbs;
|
||||
}
|
||||
}
|
||||
private IKSolverLimb[] _limbs;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the array containing all %IK solvers.
|
||||
/// </summary>
|
||||
public IKSolver[] ikSolvers {
|
||||
get {
|
||||
if (_ikSolvers == null || (_ikSolvers != null && _ikSolvers.Length != 7)) _ikSolvers = new IKSolver[7] { leftFoot, rightFoot, leftHand, rightHand, spine, lookAt, aim };
|
||||
return _ikSolvers;
|
||||
}
|
||||
}
|
||||
private IKSolver[] _ikSolvers;
|
||||
|
||||
public void AssignReferences(BipedReferences references) {
|
||||
// Assigning limbs from references
|
||||
leftHand.SetChain(references.leftUpperArm, references.leftForearm, references.leftHand, references.root);
|
||||
rightHand.SetChain(references.rightUpperArm, references.rightForearm, references.rightHand, references.root);
|
||||
leftFoot.SetChain(references.leftThigh, references.leftCalf, references.leftFoot, references.root);
|
||||
rightFoot.SetChain(references.rightThigh, references.rightCalf, references.rightFoot, references.root);
|
||||
|
||||
// Assigning spine bones from references
|
||||
spine.SetChain(references.spine, references.root);
|
||||
|
||||
// Assigning lookAt bones from references
|
||||
lookAt.SetChain(references.spine, references.head, references.eyes, references.root);
|
||||
|
||||
// Assigning Aim bones from references
|
||||
aim.SetChain(references.spine, references.root);
|
||||
|
||||
leftFoot.goal = AvatarIKGoal.LeftFoot;
|
||||
rightFoot.goal = AvatarIKGoal.RightFoot;
|
||||
leftHand.goal = AvatarIKGoal.LeftHand;
|
||||
rightHand.goal = AvatarIKGoal.RightHand;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 552b6be99351d42019784667c84a7d5a
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
9
LocalPackages/FinalIK/Runtime/FinalIK/Constraints.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 230c114522f924447be695b657911302
|
||||
folderAsset: yes
|
||||
timeCreated: 1434626794
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,42 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace RootMotion.FinalIK {
|
||||
|
||||
/// <summary>
|
||||
/// The base abstract class for all Transform constraints.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public abstract class Constraint {
|
||||
|
||||
#region Main Interface
|
||||
|
||||
/// <summary>
|
||||
/// The transform to constrain.
|
||||
/// </summary>
|
||||
public Transform transform;
|
||||
/// <summary>
|
||||
/// %Constraint weight.
|
||||
/// </summary>
|
||||
public float weight;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this <see cref="Constraint"/> is valid.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <c>true</c> if is valid; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public bool isValid {
|
||||
get {
|
||||
return transform != null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the constraint.
|
||||
/// </summary>
|
||||
public abstract void UpdateConstraint();
|
||||
|
||||
#endregion Main Interface
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c7e377232abb249ed8b4ef7d7ae933e7
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,34 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace RootMotion.FinalIK {
|
||||
|
||||
/// <summary>
|
||||
/// %Constraints to position in world space.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class ConstraintPosition : Constraint {
|
||||
|
||||
#region Main Interface
|
||||
|
||||
/// <summary>
|
||||
/// The target position.
|
||||
/// </summary>
|
||||
public Vector3 position;
|
||||
|
||||
public override void UpdateConstraint() {
|
||||
if (weight <= 0) return;
|
||||
if (!isValid) return;
|
||||
|
||||
// Lerping to position
|
||||
transform.position = Vector3.Lerp(transform.position, position, weight);
|
||||
}
|
||||
|
||||
#endregion Main Interface
|
||||
|
||||
public ConstraintPosition() {}
|
||||
public ConstraintPosition(Transform transform) {
|
||||
this.transform = transform;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 071793b8887c44ddda2d9dc3a0525167
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,64 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace RootMotion.FinalIK {
|
||||
|
||||
/// <summary>
|
||||
/// Offsets the transform from its (animated) position.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class ConstraintPositionOffset : Constraint {
|
||||
|
||||
#region Main Interface
|
||||
|
||||
/// <summary>
|
||||
/// The position offset in world space.
|
||||
/// </summary>
|
||||
public Vector3 offset;
|
||||
|
||||
public override void UpdateConstraint() {
|
||||
if (weight <= 0) return;
|
||||
if (!isValid) return;
|
||||
|
||||
// Initiating
|
||||
if (!initiated) {
|
||||
// Storing default values
|
||||
defaultLocalPosition = transform.localPosition;
|
||||
lastLocalPosition = transform.localPosition;
|
||||
|
||||
initiated = true;
|
||||
}
|
||||
|
||||
// Check if position has changed. If true, set default local position to current.
|
||||
if (positionChanged) defaultLocalPosition = transform.localPosition;
|
||||
|
||||
// Offsetting the position
|
||||
transform.localPosition = defaultLocalPosition;
|
||||
transform.position += offset * weight;
|
||||
|
||||
// Store the current local position to check if it has changed in the next update.
|
||||
lastLocalPosition = transform.localPosition;
|
||||
}
|
||||
|
||||
#endregion Main Interface
|
||||
|
||||
public ConstraintPositionOffset() {}
|
||||
|
||||
public ConstraintPositionOffset(Transform transform) {
|
||||
this.transform = transform;
|
||||
}
|
||||
|
||||
private Vector3 defaultLocalPosition, lastLocalPosition;
|
||||
private bool initiated;
|
||||
|
||||
/*
|
||||
* Check if position has been changed by animation or any other external script.
|
||||
* If not, consider the object to be static and offset only from the default rotation.
|
||||
* */
|
||||
private bool positionChanged {
|
||||
get {
|
||||
return transform.localPosition != lastLocalPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e2d9a3e673645474bb6716a1c403e3b1
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,34 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace RootMotion.FinalIK {
|
||||
|
||||
/// <summary>
|
||||
/// %Constraints to rotation in world space
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class ConstraintRotation : Constraint {
|
||||
|
||||
#region Main Interface
|
||||
|
||||
/// <summary>
|
||||
/// The target rotation.
|
||||
/// </summary>
|
||||
public Quaternion rotation;
|
||||
|
||||
public override void UpdateConstraint() {
|
||||
if (weight <= 0) return;
|
||||
if (!isValid) return;
|
||||
|
||||
// Slerping to target rotation
|
||||
transform.rotation = Quaternion.Slerp(transform.rotation, rotation, weight);
|
||||
}
|
||||
|
||||
#endregion Main Interface
|
||||
|
||||
public ConstraintRotation() {}
|
||||
public ConstraintRotation(Transform transform) {
|
||||
this.transform = transform;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a47eb259ef1b9403599c08fb1e457fcc
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,64 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace RootMotion.FinalIK {
|
||||
|
||||
/// <summary>
|
||||
/// Offsets the transform from its (animated) rotation
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class ConstraintRotationOffset: Constraint {
|
||||
|
||||
#region Main Interface
|
||||
|
||||
/// <summary>
|
||||
/// The rotation offset in world space.
|
||||
/// </summary>
|
||||
public Quaternion offset;
|
||||
|
||||
public override void UpdateConstraint() {
|
||||
if (weight <= 0) return;
|
||||
if (!isValid) return;
|
||||
|
||||
// Initiating
|
||||
if (!initiated) {
|
||||
// Storing default rotations.
|
||||
defaultLocalRotation = transform.localRotation;
|
||||
lastLocalRotation = transform.localRotation;
|
||||
|
||||
initiated = true;
|
||||
}
|
||||
|
||||
// Check if rotation has changed. If true, set default local rotation to current.
|
||||
if (rotationChanged) defaultLocalRotation = transform.localRotation;
|
||||
|
||||
// Offsetting the rotation
|
||||
transform.localRotation = defaultLocalRotation;
|
||||
transform.rotation = Quaternion.Slerp(transform.rotation, offset, weight);
|
||||
|
||||
// Store the current local rotation to check if it has changed in the next update.
|
||||
lastLocalRotation = transform.localRotation;
|
||||
}
|
||||
|
||||
#endregion Main Interface
|
||||
|
||||
public ConstraintRotationOffset() {}
|
||||
public ConstraintRotationOffset(Transform transform) {
|
||||
this.transform = transform;
|
||||
}
|
||||
|
||||
private Quaternion defaultRotation, defaultLocalRotation, lastLocalRotation, defaultTargetLocalRotation;
|
||||
private bool initiated;
|
||||
|
||||
/*
|
||||
* Check if rotation has been changed by animation or any other external script.
|
||||
* If not, consider the object to be static and offset only from the default rotation.
|
||||
* */
|
||||
private bool rotationChanged {
|
||||
get {
|
||||
return transform.localRotation != lastLocalRotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 530e73d7a55ff47029c43502e289273f
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,95 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace RootMotion.FinalIK {
|
||||
|
||||
/// <summary>
|
||||
/// Contains and manages a set of constraints.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class Constraints {
|
||||
|
||||
#region Main Interface
|
||||
|
||||
/// <summary>
|
||||
/// The transform.
|
||||
/// </summary>
|
||||
public Transform transform;
|
||||
/// <summary>
|
||||
/// The target.
|
||||
/// </summary>
|
||||
public Transform target;
|
||||
/// <summary>
|
||||
/// The position offset.
|
||||
/// </summary>
|
||||
public Vector3 positionOffset;
|
||||
/// <summary>
|
||||
/// The position to lerp to by positionWeight
|
||||
/// </summary>
|
||||
public Vector3 position;
|
||||
/// <summary>
|
||||
/// The weight of lerping to position
|
||||
/// </summary>
|
||||
[Range(0f, 1f)]
|
||||
public float positionWeight;
|
||||
/// <summary>
|
||||
/// The rotation offset.
|
||||
/// </summary>
|
||||
public Vector3 rotationOffset;
|
||||
/// <summary>
|
||||
/// The rotation to slerp to by rotationWeight
|
||||
/// </summary>
|
||||
public Vector3 rotation;
|
||||
/// <summary>
|
||||
/// The weight of slerping to rotation
|
||||
/// </summary>
|
||||
[Range(0f, 1f)]
|
||||
public float rotationWeight;
|
||||
|
||||
private Vector3 defaultLocalPosition;
|
||||
private Quaternion defaultLocalRotation;
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this instance is valid.
|
||||
/// </summary>
|
||||
public bool IsValid() {
|
||||
return transform != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initiate to the specified transform.
|
||||
/// </summary>
|
||||
public void Initiate(Transform transform) {
|
||||
this.transform = transform;
|
||||
this.position = transform.position;
|
||||
this.rotation = transform.eulerAngles;
|
||||
defaultLocalPosition = transform.localPosition;
|
||||
defaultLocalRotation = transform.localRotation;
|
||||
}
|
||||
|
||||
public void FixTransforms()
|
||||
{
|
||||
transform.localPosition = defaultLocalPosition;
|
||||
transform.localRotation = defaultLocalRotation;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the constraints.
|
||||
/// </summary>
|
||||
public void Update() {
|
||||
if (!IsValid()) return;
|
||||
|
||||
// Position
|
||||
if (target != null) position = target.position;
|
||||
transform.position += positionOffset;
|
||||
if (positionWeight > 0f) transform.position = Vector3.Lerp(transform.position, position, positionWeight);
|
||||
|
||||
// Rotation
|
||||
if (target != null) rotation = target.eulerAngles;
|
||||
transform.rotation = Quaternion.Euler(rotationOffset) * transform.rotation;
|
||||
if (rotationWeight > 0f) transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.Euler(rotation), rotationWeight);
|
||||
}
|
||||
|
||||
#endregion Main Interface
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 11679c68b0e4448338c1e21138a3596a
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
1859
LocalPackages/FinalIK/Runtime/FinalIK/DoxygenManualFinalIK.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2ad7f440b73d8470b959b7c9fb12fcfb
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
LocalPackages/FinalIK/Runtime/FinalIK/FinalIK Change Log.pdf
Normal file
@@ -0,0 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e7b02201a6e3c416cad2e367877dacc7
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
LocalPackages/FinalIK/Runtime/FinalIK/FinalIK ReadMe.rtf
Normal file
@@ -0,0 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 365bd3269a5454635af24dc6962f7d1d
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
LocalPackages/FinalIK/Runtime/FinalIK/FinalIK User Manual.pdf
Normal file
@@ -0,0 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7ef58c8cd22c3461180e62ac068acdc4
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
9
LocalPackages/FinalIK/Runtime/FinalIK/Finger Rig.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 44d91317b400b4b9ab842fa07822acc2
|
||||
folderAsset: yes
|
||||
timeCreated: 1434626794
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
387
LocalPackages/FinalIK/Runtime/FinalIK/Finger Rig/FingerRig.cs
Normal file
@@ -0,0 +1,387 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using RootMotion;
|
||||
using System;
|
||||
|
||||
namespace RootMotion.FinalIK {
|
||||
|
||||
/// <summary>
|
||||
/// Contains a LimbIK solver and some additional logic to handle the finger.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class Finger {
|
||||
|
||||
[System.Serializable]
|
||||
public enum DOF {
|
||||
One,
|
||||
Three
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Master Weight for the finger.
|
||||
/// </summary>
|
||||
[Tooltip("Master Weight for the finger.")]
|
||||
[Range(0f, 1f)] public float weight = 1f;
|
||||
/// <summary>
|
||||
/// The weight of rotating the finger tip and bending the finger to the target.
|
||||
/// </summary>
|
||||
[Tooltip("The weight of rotating the finger tip and bending the finger to the target.")]
|
||||
[Range(0f, 1f)]
|
||||
public float rotationWeight = 1f;
|
||||
|
||||
[Tooltip("Rotational degrees of freedom. When set to 'One' the fingers will be able to be rotated only around a single axis. When 3, all 3 axes are free to rotate around.")]
|
||||
/// <summary>
|
||||
/// Rotational degrees of freedom. When set to 'One' the fingers will be able to be rotated only around a single axis. When 3, all 3 axes are free to rotate around.
|
||||
/// </summary>
|
||||
public DOF rotationDOF;
|
||||
|
||||
[Tooltip("If enabled, keeps bone1 twist angle fixed relative to bone2.")]
|
||||
/// <summary>
|
||||
/// If enabled, keeps bone1 twist angle fixed relative to bone2.
|
||||
/// </summary>
|
||||
public bool fixBone1Twist;
|
||||
|
||||
/// <summary>
|
||||
/// The first bone of the finger.
|
||||
/// </summary>
|
||||
[Tooltip("The first bone of the finger.")]
|
||||
public Transform bone1;
|
||||
/// <summary>
|
||||
/// The second bone of the finger.
|
||||
/// </summary>
|
||||
[Tooltip("The second bone of the finger.")]
|
||||
public Transform bone2;
|
||||
/// <summary>
|
||||
/// The (optional) third bone of the finger. This can be ignored for thumbs.
|
||||
/// </summary>
|
||||
[Tooltip("The (optional) third bone of the finger. This can be ignored for thumbs.")]
|
||||
public Transform bone3;
|
||||
/// <summary>
|
||||
/// The fingertip object. If your character doesn't have tip bones, you can create an empty GameObject and parent it to the last bone in the finger. Place it to the tip of the finger.
|
||||
/// </summary>
|
||||
[Tooltip("The fingertip object. If your character doesn't have tip bones, you can create an empty GameObject and parent it to the last bone in the finger. Place it to the tip of the finger.")]
|
||||
public Transform tip;
|
||||
/// <summary>
|
||||
/// The IK target (optional, can use IKPosition and IKRotation directly).
|
||||
/// </summary>
|
||||
[Tooltip("The IK target (optional, can use IKPosition and IKRotation directly).")]
|
||||
public Transform target;
|
||||
|
||||
/// <summary>
|
||||
/// Has the finger properly initiated (in play mode only)?
|
||||
/// </summary>
|
||||
public bool initiated { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the IK target position if target is not used.
|
||||
/// </summary>
|
||||
public Vector3 IKPosition {
|
||||
get {
|
||||
return solver.IKPosition;
|
||||
}
|
||||
set {
|
||||
solver.IKPosition = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the IK target rotation if target is not used.
|
||||
/// </summary>
|
||||
public Quaternion IKRotation {
|
||||
get {
|
||||
return solver.IKRotation;
|
||||
}
|
||||
set {
|
||||
solver.IKRotation = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is this finger setup valid?
|
||||
/// </summary>
|
||||
public bool IsValid(ref string errorMessage) {
|
||||
if (bone1 == null || bone2 == null || tip == null) {
|
||||
errorMessage = "One of the bones in the Finger Rig is null, can not initiate solvers.";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private IKSolverLimb solver;
|
||||
private Quaternion bone3RelativeToTarget;
|
||||
private Vector3 bone3DefaultLocalPosition;
|
||||
private Quaternion bone3DefaultLocalRotation;
|
||||
private Vector3 bone1Axis;
|
||||
private Vector3 tipAxis;
|
||||
private Vector3 bone1TwistAxis;
|
||||
private Vector3 defaultBendNormal;
|
||||
|
||||
// Initiates the LimbIK solver
|
||||
public void Initiate(Transform hand, int index) {
|
||||
initiated = false;
|
||||
|
||||
string errorMessage = string.Empty;
|
||||
if (!IsValid(ref errorMessage)) {
|
||||
Warning.Log(errorMessage, hand, false);
|
||||
return;
|
||||
}
|
||||
|
||||
solver = new IKSolverLimb();
|
||||
|
||||
solver.IKPositionWeight = weight;
|
||||
solver.bendModifier = IKSolverLimb.BendModifier.Target;
|
||||
solver.bendModifierWeight = 1f;
|
||||
defaultBendNormal = -Vector3.Cross(tip.position - bone1.position, bone2.position - bone1.position).normalized;
|
||||
solver.bendNormal = defaultBendNormal;
|
||||
|
||||
Vector3 axisWorld = Vector3.Cross(bone2.position - bone1.position, tip.position - bone1.position);
|
||||
bone1Axis = Quaternion.Inverse(bone1.rotation) * axisWorld;
|
||||
tipAxis = Quaternion.Inverse(tip.rotation) * axisWorld;
|
||||
|
||||
Vector3 normal = bone2.position - bone1.position;
|
||||
Vector3 tangent = -Vector3.Cross(tip.position - bone1.position, bone2.position - bone1.position);
|
||||
Vector3.OrthoNormalize(ref normal, ref tangent);
|
||||
bone1TwistAxis = Quaternion.Inverse(bone1.rotation) * tangent;
|
||||
|
||||
IKPosition = tip.position;
|
||||
IKRotation = tip.rotation;
|
||||
|
||||
if (bone3 != null) {
|
||||
bone3RelativeToTarget = Quaternion.Inverse(IKRotation) * bone3.rotation;
|
||||
bone3DefaultLocalPosition = bone3.localPosition;
|
||||
bone3DefaultLocalRotation = bone3.localRotation;
|
||||
}
|
||||
|
||||
solver.SetChain(bone1, bone2, tip, hand);
|
||||
solver.Initiate(hand);
|
||||
|
||||
initiated = true;
|
||||
}
|
||||
|
||||
// Fix bones to their initial local position and rotation
|
||||
public void FixTransforms() {
|
||||
if (!initiated) return;
|
||||
if (weight <= 0f) return;
|
||||
|
||||
solver.FixTransforms();
|
||||
|
||||
if (bone3 != null) {
|
||||
bone3.localPosition = bone3DefaultLocalPosition;
|
||||
bone3.localRotation = bone3DefaultLocalRotation;
|
||||
}
|
||||
}
|
||||
|
||||
// Stores the default localPosition/Rotation of the finger bones used by FixTransforms()
|
||||
public void StoreDefaultLocalState() {
|
||||
if (!initiated) return;
|
||||
|
||||
solver.StoreDefaultLocalState();
|
||||
|
||||
if (bone3 != null) {
|
||||
bone3DefaultLocalPosition = bone3.localPosition;
|
||||
bone3DefaultLocalRotation = bone3.localRotation;
|
||||
}
|
||||
}
|
||||
|
||||
// Update the LimbIK solver and rotate the optional 3rd bone
|
||||
public void Update(float masterWeight) {
|
||||
if (!initiated) return;
|
||||
|
||||
float w = weight * masterWeight;
|
||||
if (w <= 0f) return;
|
||||
|
||||
solver.target = target;
|
||||
if (target != null) {
|
||||
IKPosition = target.position;
|
||||
IKRotation = target.rotation;
|
||||
}
|
||||
|
||||
if (rotationDOF == DOF.One) {
|
||||
Quaternion q = Quaternion.FromToRotation(IKRotation * tipAxis, bone1.rotation * bone1Axis);
|
||||
IKRotation = q * IKRotation;
|
||||
}
|
||||
|
||||
// Rotate the 3rd bone
|
||||
if (bone3 != null) {
|
||||
if (w * rotationWeight >= 1f) {
|
||||
bone3.rotation = IKRotation * bone3RelativeToTarget;
|
||||
} else {
|
||||
bone3.rotation = Quaternion.Lerp(bone3.rotation, IKRotation * bone3RelativeToTarget, w * rotationWeight);
|
||||
}
|
||||
}
|
||||
|
||||
solver.IKPositionWeight = w;
|
||||
solver.IKRotationWeight = rotationWeight;
|
||||
solver.Update();
|
||||
|
||||
if (fixBone1Twist)
|
||||
{
|
||||
Quaternion bone2Rotation = bone2.rotation;
|
||||
Quaternion space = Quaternion.LookRotation(bone1.rotation * bone1TwistAxis, bone2.position - bone1.position);
|
||||
Vector3 bone1Twist = Quaternion.Inverse(space) * solver.bendNormal;
|
||||
float angle = Mathf.Atan2(bone1Twist.x, bone1Twist.z) * Mathf.Rad2Deg;
|
||||
bone1.rotation = Quaternion.AngleAxis(angle, bone2.position - bone1.position) * bone1.rotation;
|
||||
bone2.rotation = bone2Rotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles IK for a number of Fingers with 3-4 joints.
|
||||
/// </summary>
|
||||
public class FingerRig : SolverManager {
|
||||
|
||||
/// <summary>
|
||||
/// The master weight for all fingers.
|
||||
/// </summary>
|
||||
[Tooltip("The master weight for all fingers.")]
|
||||
[Range(0f, 1f)]
|
||||
public float weight = 1f;
|
||||
|
||||
/// <summary>
|
||||
/// The array of Fingers.
|
||||
/// </summary>
|
||||
public Finger[] fingers = new Finger[0];
|
||||
|
||||
/// <summary>
|
||||
/// Has the rig properly initiated (in play mode only)?
|
||||
/// </summary>
|
||||
public bool initiated { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Is this rig valid?
|
||||
/// </summary>
|
||||
public bool IsValid(ref string errorMessage) {
|
||||
foreach (Finger finger in fingers) {
|
||||
if (!finger.IsValid(ref errorMessage)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to automatically fill in the Finger bones.
|
||||
/// </summary>
|
||||
[ContextMenu("Auto-detect")]
|
||||
public void AutoDetect() {
|
||||
fingers = new Finger[0];
|
||||
|
||||
for (int i = 0; i < transform.childCount; i++) {
|
||||
Transform[] potentialFinger = new Transform[0];
|
||||
AddChildrenRecursive(transform.GetChild(i), ref potentialFinger);
|
||||
|
||||
if (potentialFinger.Length == 3 || potentialFinger.Length == 4) {
|
||||
Finger finger = new Finger();
|
||||
finger.bone1 = potentialFinger[0];
|
||||
finger.bone2 = potentialFinger[1];
|
||||
if (potentialFinger.Length == 3) {
|
||||
finger.tip = potentialFinger[2];
|
||||
} else {
|
||||
finger.bone3 = potentialFinger[2];
|
||||
finger.tip = potentialFinger[3];
|
||||
}
|
||||
|
||||
finger.weight = 1f;
|
||||
|
||||
Array.Resize(ref fingers, fingers.Length + 1);
|
||||
fingers[fingers.Length - 1] = finger;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a finger in run-time.
|
||||
/// </summary>
|
||||
public void AddFinger(Transform bone1, Transform bone2, Transform bone3, Transform tip, Transform target = null) {
|
||||
Finger finger = new Finger();
|
||||
finger.bone1 = bone1;
|
||||
finger.bone2 = bone2;
|
||||
finger.bone3 = bone3;
|
||||
finger.tip = tip;
|
||||
finger.target = target;
|
||||
|
||||
Array.Resize(ref fingers, fingers.Length + 1);
|
||||
fingers[fingers.Length - 1] = finger;
|
||||
|
||||
initiated = false;
|
||||
finger.Initiate(transform, fingers.Length - 1);
|
||||
if (fingers[fingers.Length - 1].initiated) initiated = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a finger in runtime.
|
||||
/// </summary>
|
||||
public void RemoveFinger(int index) {
|
||||
if (index < 0f || index >= fingers.Length) {
|
||||
Warning.Log("RemoveFinger index out of bounds.", transform);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fingers.Length == 1) {
|
||||
fingers = new Finger[0];
|
||||
return;
|
||||
}
|
||||
|
||||
Finger[] newFingers = new Finger[fingers.Length - 1];
|
||||
int added = 0;
|
||||
|
||||
for (int i = 0; i < fingers.Length; i++) {
|
||||
if (i != index) {
|
||||
newFingers[added] = fingers[i];
|
||||
added ++;
|
||||
}
|
||||
}
|
||||
|
||||
fingers = newFingers;
|
||||
}
|
||||
|
||||
// Adds child Transforms of the 'parent' to the 'array' recursively only if each Transform has a single child.
|
||||
private void AddChildrenRecursive(Transform parent, ref Transform[] array) {
|
||||
Array.Resize(ref array, array.Length + 1);
|
||||
array[array.Length - 1] = parent;
|
||||
|
||||
if (parent.childCount != 1) return;
|
||||
|
||||
AddChildrenRecursive(parent.GetChild(0), ref array);
|
||||
}
|
||||
|
||||
protected override void InitiateSolver() {
|
||||
initiated = true;
|
||||
|
||||
for (int i = 0; i < fingers.Length; i++) {
|
||||
fingers[i].Initiate(transform, i);
|
||||
if (!fingers[i].initiated) initiated = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateFingerSolvers() {
|
||||
foreach (Finger finger in fingers) {
|
||||
finger.Update(weight);
|
||||
}
|
||||
}
|
||||
|
||||
public void FixFingerTransforms() {
|
||||
if (weight <= 0f) return;
|
||||
|
||||
foreach (Finger finger in fingers) {
|
||||
finger.FixTransforms();
|
||||
}
|
||||
}
|
||||
|
||||
public void StoreDefaultLocalState() {
|
||||
foreach (Finger finger in fingers) {
|
||||
finger.StoreDefaultLocalState();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void UpdateSolver() {
|
||||
UpdateFingerSolvers();
|
||||
}
|
||||
|
||||
protected override void FixTransforms() {
|
||||
if (weight <= 0f) return;
|
||||
|
||||
FixFingerTransforms();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ee545149746b44547897f32030465e57
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 10000
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
9
LocalPackages/FinalIK/Runtime/FinalIK/Gizmos.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1bdc8112837ae4a76b936df3038e4b2c
|
||||
folderAsset: yes
|
||||
timeCreated: 1434626794
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
LocalPackages/FinalIK/Runtime/FinalIK/Gizmos/AimIK Icon.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
@@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 14a4d69b319a04b75bb03f351a174cec
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 0
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
LocalPackages/FinalIK/Runtime/FinalIK/Gizmos/BipedIK Icon.png
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
@@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2631a18e2dd7844718dea7db8ecf6c03
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 0
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
LocalPackages/FinalIK/Runtime/FinalIK/Gizmos/CCDIK Icon.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
@@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 79450243724744b44820e5468e418048
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 0
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
LocalPackages/FinalIK/Runtime/FinalIK/Gizmos/Chain Icon.png
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
@@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e394bb73c6c534de1a49e2eff63b4f6d
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: -1
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 4.7 KiB |
@@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0ee227cd5021b40b2a18d383ba9dadff
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: -1
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
LocalPackages/FinalIK/Runtime/FinalIK/Gizmos/FABRIK Icon.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
@@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1ccc9218a62cd44dda0ddb5fa15c62cc
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 0
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
LocalPackages/FinalIK/Runtime/FinalIK/Gizmos/FABRIKRoot Icon.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
@@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 55f7720fb239042f08656d4ab294f5c5
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 0
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 4.7 KiB |
@@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 89e0c79ada10847639ab1754e12413a7
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 0
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
LocalPackages/FinalIK/Runtime/FinalIK/Gizmos/GrounderBipedIK.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
@@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c0b08042695f548e79a4e5c84112fe52
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 0
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 3.5 KiB |
@@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 36056811931e14f20adcc2767d6262e7
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 0
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
LocalPackages/FinalIK/Runtime/FinalIK/Gizmos/GrounderIK.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
@@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7c84c5721b6d74a15ab63fe46effb886
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 0
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 5.1 KiB |
@@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c92822fd107844dccaf6c30c024e5806
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 0
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 9.6 KiB |
@@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9e5cf919254ee4d6bb9ccd7dc1b4bebd
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: -1
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5e7cd1ffcb3304ceba342d37416ceb2c
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: -1
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 5.4 KiB |
@@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 706b88054f06c4e83ad5f34217bedea3
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: -1
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 6.8 KiB |
@@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2a1323dcf174944a69736d167afe96e0
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 0
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
LocalPackages/FinalIK/Runtime/FinalIK/Gizmos/LimbIK Icon.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
@@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e747b4712fd43444ab8213b7ff4c089b
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 0
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
LocalPackages/FinalIK/Runtime/FinalIK/Gizmos/LookAtIK Icon.png
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
@@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dc3f34dec09f54c4d8a48bf1a653b179
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 0
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
LocalPackages/FinalIK/Runtime/FinalIK/Gizmos/Mapping Icon.png
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
@@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8e949b7451d544077b75cb3246f9f739
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: -1
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 7.9 KiB |
@@ -0,0 +1,53 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c829e174cb3c74f869cd9949be8d8814
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -2
|
||||
maxTextureSize: 128
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: -1
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||