备份CatanBuilding瘦身独立工程

This commit is contained in:
JSD\13999
2026-05-26 16:15:54 +08:00
commit 2d0e6a61b7
12001 changed files with 2431925 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 47bf04154c11c5e45b94b1aec2c0baf6
folderAsset: yes
timeCreated: 1516620867
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 8d2079bf8fd63d640a121f8fea6f5c5f
folderAsset: yes
timeCreated: 1516620916
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 490fde02f41ae014abec4edfce28648f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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) { }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3f66200036e67da4998b9ac08649304f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: addea154dd3a3e442abb7c12a65ebf8e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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
}
}

View 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:

View 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
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 27b32efee52144c4e934e6c3272ceb2c
timeCreated: 1516356533
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 15001
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: e468ef7e80a87f94588b5eeb3a423b91
folderAsset: yes
timeCreated: 1516621025
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 2f9e403f0f8255c42b90254abc55f528
timeCreated: 1516435305
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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);
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 582052db0a6096149a7b2b75914ef3a6
timeCreated: 1516263395
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: efcc0ec5ed265a340a1412edb9110337
timeCreated: 1516287616
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 15000
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: c41cf13236c01a747b3dfb963402b3a0
folderAsset: yes
timeCreated: 1516620909
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a4b02f60233a6cf4eb1c424f90323213
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3451f091c656bfc429396cc701ac5b8d
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 7400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 24d41cb619dc9dc42bf10705eb128c97
timeCreated: 1516284817
licenseType: Store
NativeFormatImporter:
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 0bd8d9a8cbacde343967c95c4458318e
timeCreated: 1517387718
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3349a7526568cf042bf8609694db3327
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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();
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ea198996b9a58624b82f921e56faf4ba
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 934bb813ebad34517a1b22565370b2af
folderAsset: yes
timeCreated: 1434626794
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 24b4e6f1f9c204bc5bd16676aecf434d
folderAsset: yes
timeCreated: 1434626794
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View 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);
}
}
}

View File

@@ -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:

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 552b6be99351d42019784667c84a7d5a
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 230c114522f924447be695b657911302
folderAsset: yes
timeCreated: 1434626794
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: c7e377232abb249ed8b4ef7d7ae933e7
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 071793b8887c44ddda2d9dc3a0525167
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: e2d9a3e673645474bb6716a1c403e3b1
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: a47eb259ef1b9403599c08fb1e457fcc
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 530e73d7a55ff47029c43502e289273f
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 11679c68b0e4448338c1e21138a3596a
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 2ad7f440b73d8470b959b7c9fb12fcfb
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,6 @@
fileFormatVersion: 2
guid: e7b02201a6e3c416cad2e367877dacc7
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,6 @@
fileFormatVersion: 2
guid: 365bd3269a5454635af24dc6962f7d1d
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,6 @@
fileFormatVersion: 2
guid: 7ef58c8cd22c3461180e62ac068acdc4
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 44d91317b400b4b9ab842fa07822acc2
folderAsset: yes
timeCreated: 1434626794
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View 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();
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: ee545149746b44547897f32030465e57
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 10000
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 1bdc8112837ae4a76b936df3038e4b2c
folderAsset: yes
timeCreated: 1434626794
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@@ -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:

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@@ -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:

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

@@ -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:

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

@@ -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:

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@@ -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:

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@@ -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:

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@@ -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:

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@@ -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:

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@@ -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:

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -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:

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@@ -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:

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

@@ -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:

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

View File

@@ -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:

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -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:

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@@ -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:

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

View File

@@ -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:

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@@ -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:

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@@ -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:

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@@ -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:

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

View File

@@ -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:

Some files were not shown because too many files have changed in this diff Show More