using UnityEngine;
using System.Collections; /*
* ----------------------------------------------------------------------------
* Creation Info
* ----------------------------------------------------------------------------
* Root Motion Computer
* Version: 1.2
* Date: 2010.12.08
* Author: Adam Mechtley (http://adammechtley.com)
* Created for Mixamo, Inc. (http://mixamo.com)
*
* ----------------------------------------------------------------------------
* Description:
* ----------------------------------------------------------------------------
* Like many other game engines, Unity was developed with the intent that
* character animations be created in-place, as though the characters were
* moving and acting on a treadmill, and the characters' root nodes would then
* be moved programmatically using physics, a character controller, or another
* procedural mechanism. Unfortunately, many character movements, such as a
* zombie lurching forward, do not move forward with a constant velocity.
* Consequently, such motions can introduce foot sliding or dramatic bobbing
* back and forth when moved procedurally.
*
* The Root Motion Computer was designed to solve this problem, particularly by
* leveraging the fact that motion-capture animations actually capture a moving
* actor rather than an actor performing in place. Using all of the default
* settings, the root motion computer uses the movement of the character's
* pelvis to move move the root node. Thus, in-place motions will play back in-
* place, while motions captured with forward or sideways movement will
* actually move the character when looping, rather than snapping back to the
* starting location. Users can also configure the computer's various settings
* to instead pipe its output to another script to drive the velocity of a
* character controller or another movement tool.
*
* ----------------------------------------------------------------------------
* Usage:
* ----------------------------------------------------------------------------
* You can place this script anywhere in your project folder. Because it is
* written in C#, however, you must put it in your Plugins folder in your
* project if you are coding in UnityScript.
*
* In many cases, you can simply add the component to your character and it
* should "just work." Otherwise you can manually specify various properties:
*
* isManagedExternally: Specifies that another script will invoke Initialize()
* and ComputeRootMotion(). This is used if you need to manage the
* execution order to prevent the computer from interfering with animation
* requests you may make in your own Start(), Awake(), or LateUpdate()
* functions.
* rootNode: The transform that is actually moved, whether by the computer or
* by another mechanism like a character controller.
* anim: The animation component from which to process AnimationStates.
* pelvis: The character's pelvis transform. This object is used to determine
* changes in the character's overall position or rotation.
* pelvisForwardAxis: The axis on the pelvis that points to the character's
* front in the bind pose.
* pelvisRightAxis: The axis on the pelvis that points to the character's right
* in the bind pose.
* computationMode: Specifies whether the computer should compute only forward
* translation, all translation (forward-back and side-to-side), or all
* translation as well as turning rotation.
* applyMotion: Specifies whether the computation results should be applied to
* rootNode. Set to false if output is going to be read and processed by
* another script to move a character controller, for example.
* deltaPosition: Represents the character's change in translation since the
* last frame, given in the space of rootNode.
* deltaRotation: Represents the character's change in orientation since the
* last frame, given in the space of rootNode.
* deltaEulerAngles: Same as deltaRotation but converted into Euler angles.
* isDebugMode: Renders pelvis axes in the scene view when the character is
* selected. Renders axis tripods to illustrate the position and
* orientation of the pelvis and root node when the game is playing.
* debugGizmoSize: A scalar for the debug gizmos.
*
* ----------------------------------------------------------------------------
* Notes and Limitations:
* ----------------------------------------------------------------------------
* 1. The computer is currently only designed to handle movement of characters
* forward-back and side-to-side with rotation about their up-axes. As such, it
* offers no generalized mechanism for adjusting the height of a character
* (e.g. jumping, going up stairs). Because the computer operates using delta
* values in LateUpdate(), however, you can implement your own custom logic for
* adjusting a character's height in your own movement code and the computer
* will simply work on top if it.
*
* 2. As of Unity 2.x, there is no way to query the post-normalized weights of
* AnimationStates. The computer attempts to work around this by rebuilding
* normalized weights for each state using the same process that Unity uses
* (applying weights to top-most layers first, and then working down).
*
* 3. The computer currently assumes that the clip for any particular
* AnimationState will not change. (Generally speaking, it should not once it
* has been added to the animation component anyway.)
*
* 4. The computer should support adding new clips at run-time, though the
* feature has been tested only briefly.
*
* 5. Because of how rotation computation works, if a character is on his
* stomach and then rolls onto his back (or vice-versa), then it is inadvisable
* to blend in other motions at the time the actual roll occurs (unless it is
* another synchronized rolling motion).
* */ // a struct to store information about all of the animation states
/// <summary>
/// 存放动画状态的结构体
/// </summary>
public struct AnimInfo
{ /// <summary>
/// 当前动作的规范化时间,直接指向对应动画的规范化时间
/// </summary>
public float currentNormalizedTime;
/// <summary>
/// 之前动作的规范化时间
/// </summary>
public float previousNormalizedTime;
/// <summary>
/// 当前动作的权重,直接指向对应动画的权重
/// </summary>
public float currentWeight; // the actual weight value queried from the AnimationState
/// <summary>
/// 实际播放出来的权重
/// </summary>
public float contributingWeight; // the weight the AnimationState is actually contributing to the final result based on layers
/// <summary>
/// 当前位置
/// </summary>
public Vector3 currentPosition;
/// <summary>
/// 之前的位置
/// </summary>
public Vector3 previousPosition;
/// <summary>
/// 开始位置
/// </summary>
public Vector3 startPosition;
/// <summary>
/// 结束位置
/// </summary>
public Vector3 endPosition;
/// <summary>
/// 当前的轴
/// </summary>
public Vector3 currentAxis;
/// <summary>
/// 之前的轴
/// </summary>
public Vector3 previousAxis;
/// <summary>
/// 开始的轴
/// </summary>
public Vector3 startAxis;
/// <summary>
/// 结束的轴
/// </summary>
public Vector3 endAxis;
/// <summary>
/// 全部旋转
/// </summary>
public Quaternion totalRotation;
} // an enum to describe how delta values should be computed
/// <summary>
/// 增量值计算枚举
/// </summary>
public enum RootMotionComputationMode
{
ZTranslation,
XZTranslation,
TranslationAndRotation
} /// <summary>
/// 管理所有动画,权重,混合
/// </summary>
[AddComponentMenu("Mixamo/Root Motion Computer")]
public class RootMotionComputer : MonoBehaviour
{
// the transform to have root motion applied
/// <summary>
/// 脚本所在对象
/// </summary>
public Transform rootNode; // the animation component where all of the clips for this model exist
/// <summary>
/// 当前所有的动画数组
/// </summary>
public Animation anim; // the pelvis joint from which the script obtains x-z motion and y-rotation for the root
/// <summary>
/// 模型所在的对象,设置X向Z移动、Y旋转
/// </summary>
public Transform pelvis;
/// <summary>
/// 骨盆局部的轴,右方向 也是X轴
/// </summary>
public Vector3 pelvisRightAxis = Vector3.right; // its local axis specifying the right direction
/// <summary>
/// 暂时存储骨盆的局部位置
/// </summary>
private Vector3 pLocalPosition; // a variable to temporarily store and set the pelvis local position after computation // parameters for computation and application of result
/// <summary>
/// 是否是外部管理
/// </summary>
public bool isManagedExternally = false; // if the computer is managed externally, then its calls are invoked manually
/// <summary>
/// 增量结构
/// </summary>
public RootMotionComputationMode computationMode = RootMotionComputationMode.TranslationAndRotation;
/// <summary>
/// 应用运动
/// </summary>
public bool applyMotion = true; // information about the computed root position
/// <summary>
/// 来自上一帧的三角州位置
/// </summary>
private Vector3 dPosition = Vector3.zero; // local-space delta position since previous frame
/// <summary>
/// 来自上一帧的三角州位置
/// </summary>
public Vector3 deltaPosition { get { return dPosition; } }
/// <summary>
/// 减少分配的一个容器
/// </summary>
private Vector3 p; // a simple container to minimize allocations // information about the computed root rotation
/// <summary>
/// 来自上一帧的三角州旋转
/// </summary>
private Quaternion dRotation = Quaternion.identity; // local-space delta rotation since previous frame
/// <summary>
/// 来自上一帧的三角州旋转
/// </summary>
public Quaternion deltaRotation { get { return dRotation; } }
/// <summary>
/// 来自上一帧的三角州旋转的欧拉角
/// </summary>
public Vector3 deltaEulerAngles { get { return dRotation.eulerAngles; } } // a hashtable storing information about each AnimationState
/// <summary>
/// 存放所有动画的哈希表
/// </summary>
private Hashtable animInfoTable;
/// <summary>
/// 动画状态信息结构体,为了减少分配
/// </summary>
private AnimInfo info; // a simple container to minimize allocations // specify whether the component should be running in debug mode
/// <summary>
/// 是否是调试模式下运行
/// </summary>
public bool isDebugMode = true;
/// <summary>
/// 调试线框的大小
/// </summary>
public float debugGizmoSize = 0.25f; // is the computation occuring on the first frame of execution?
/// <summary>
/// 计算上的第一帧执行?
/// </summary>
private bool isFirstFrame = true; // the highest and lowest layers on which there is an AnimationState
/// <summary>
/// 最高的层
/// </summary>
private int highestLayer = ;
/// <summary>
/// 最低的层
/// </summary>
private int lowestLayer = ; /*
* Initialize the component if it is not managed externally
* */
void Start()
{
//如果不是外部管理
if (!isManagedExternally) Initialize();
} /*
* Initialize all necessary variables and warn user as needed
* */
/// <summary>
/// 必须的初始化
/// </summary>
public void Initialize()
{
// validate component references
if (anim == null)
{
//取子对象的所有动画
anim = gameObject.GetComponentInChildren(typeof(Animation)) as Animation;
if (anim == null) Debug.LogError("No animation component has been specified.", this);
else if (isDebugMode) Debug.LogWarning(string.Format("No animation component has been specified. Using the animation component on {0}.", gameObject.name), this);
}
if (rootNode == null)
{
//等于自身
rootNode = transform;
if (isDebugMode) Debug.LogWarning(string.Format("No root object has been manually specified. Assuming that {0} is the root object to be moved.", gameObject.name), this);
}
if (pelvis == null)
{
//取自身的所有组件
Component[] hierarchy = GetComponentsInChildren(typeof(Transform));
// first try to figure out the pelvis based on name
//给骨盆赋值
foreach (Transform joint in hierarchy)
if (pelvis == null && (joint.name.ToLower() == "hips" || joint.name.ToLower().Contains("pelvis"))) pelvis = joint;
// if no named pelvis was found, then try to find the first skinned mesh renderer with children
if (pelvis == null)
{
foreach (Transform joint in hierarchy)
{
if (joint.GetComponent(typeof(SkinnedMeshRenderer)) == null) continue;
Component[] children = joint.GetComponentsInChildren(typeof(Transform));
if (children.Length > ) pelvis = joint;
}
}
if (pelvis == null) Debug.LogError("No pelvis transform has been specified.", this);
else if (isDebugMode) Debug.LogWarning(string.Format("No pelvis object as been manually specified. Assuming that {0} is the pelvis object to track.", pelvis.name));
} // store whether or not the animation component is playing
bool isAnimationPlaying = anim.isPlaying; // store information about each AnimationState in a hashtable for easy lookup later
animInfoTable = new Hashtable();
// first, figure out what all AnimationStates are currently doing
//默认设置给每一个动画
foreach (AnimationState aState in anim)
{
AddAnimInfoToTable(aState);
}
//动画采样
anim.Sample(); // BUG: need to call Sample() once up front or AnimationStates in Animation component may reorder during iteration
//停止所有动画,以确保所有的动画权重为0
anim.Stop(); // call Stop() to ensure that all weights go to 0
//重新启动,以确保采样时的值是正确的
anim.enabled = true; // reenable the animation component to ensure that values will be correct when sampling
// store properties for each state one at a time
foreach (AnimationState aState in anim)
{
SetupNewAnimInfo(aState);
} // revert the animation component to whatever it was doing beforehand
//权重,规范化时间 再次赋值为结构体里面的!当时为何不在设置结构体的时候就直接做了呢?
foreach (AnimationState aState in anim)
{
info = (AnimInfo)animInfoTable[aState];
//尼玛。这里不是重赋值么
aState.weight = info.currentWeight;
aState.normalizedTime = info.currentNormalizedTime;
}
if (isAnimationPlaying) anim.Play();
else anim.Stop();
} /*
* Add information about the provided state to the hashtable
* */
/// <summary>
/// 设置一个动画的详细信息为结构体,并将之 动画名,结构体 的形式存入哈希表
/// </summary>
/// <param name="aState">动画</param>
public void AddAnimInfoToTable(AnimationState aState)
{
// create the new info object
AnimInfo newInfo = new AnimInfo(); // store the current properties
//设置规范化时间
newInfo.currentNormalizedTime = aState.normalizedTime;
//设置权重
newInfo.currentWeight = aState.weight; // add a new hashtable entry for the AnimInfo
//存入动画哈希表中
animInfoTable.Add(aState, newInfo);
} /*
* Set up further properties for a newly-created info object after calling AddAnimInfoToTable()
* */
/// <summary>
/// 设置哈希表里动画对应的结构体,重置这个动画
/// </summary>
/// <param name="aState">动画名</param>
public void SetupNewAnimInfo(AnimationState aState)
{
//取这个动画的结构体
AnimInfo newInfo = (AnimInfo)animInfoTable[aState]; // store information about the animation state up front
//当前的状态,应当是false 。
bool isEnabled = aState.enabled;
WrapMode wrapMode = aState.wrapMode; // activate the animation state 激活动画状态
aState.weight = 1f;
aState.enabled = true; //循环模式 确保该值在normalizedTime=1f是不一定相同normalizedTime= 0F ,官方没有 Clamp 的解释 操
aState.wrapMode = WrapMode.Clamp; // ensures the value at normalizedTime = 1f is not necessarily the same as normalizedTime = 0f // scrub to the beginning of the animation state and store initial position and rotation values
//净化开始动画状态的初始位置的和旋转值
aState.normalizedTime = 0f;
anim.Sample();
newInfo.startPosition = GetProjectedPosition(pelvis);
newInfo.previousPosition = GetProjectedPosition(pelvis);
newInfo.startAxis = GetProjectedAxis(pelvis, pelvisRightAxis);
newInfo.previousAxis = GetProjectedAxis(pelvis, pelvisRightAxis); // scrub to the end of the animation state and store final position and rotation values
//净化结束的动画状态,并存储最后的位置和旋转值
aState.normalizedTime = 1f;
anim.Sample();
newInfo.endPosition = GetProjectedPosition(pelvis);
newInfo.endAxis = GetProjectedAxis(pelvis, pelvisRightAxis); // store the total rotation over the course of the animation
//从开始到结束的一个旋转的四元数
newInfo.totalRotation = Quaternion.FromToRotation(newInfo.startAxis, newInfo.endAxis); // reset the clip to its starting point and scrub it down to 0 weight
//重置这个动画到开始的点到0的权重
aState.normalizedTime = 0f;
aState.weight = 0f;
aState.enabled = isEnabled;
aState.wrapMode = wrapMode;
anim.Sample(); //最后赋值
animInfoTable[aState] = newInfo;
} /*
* All motion is applied in LateUpdate() since it is called after all animation states have been set
* */
//以保万一才在LatUpdate里运行,因为开头设置了。
void LateUpdate()
{
if (!isManagedExternally) ComputeRootMotion();
} /*
* Compute the root motion variables
* */
/// <summary>
/// 计算根运动变量
/// </summary>
public void ComputeRootMotion()
{
// early out if no animation is playing 没运动
if (!anim.isPlaying) return; // store whether or not we should be bothering to compute rotation parameters存储是否我们应该费心去计算旋转参数
bool isRotationMode = (computationMode == RootMotionComputationMode.TranslationAndRotation); #region 设置最高层低层,是否所有的动画都已加入哈希表?没有则添加并设置
// an array to store any AnimationStates that have been added to the animation component since the last frame
//一个数组来存储已被添加到自上一帧的动画组件任何AnimationStates,用于初始化没有添加进的动画
ArrayList newlyAddedAnimationStates = null; // first store current actual weight and time information for all AnimationStates
foreach (AnimationState aState in anim)
{
// store the highest and lowest layers for use in a later iteration
//给最高层和最低层赋值 . 这里每次都要赋一下,让我感到很费解
highestLayer = Mathf.Max(highestLayer, aState.layer);
lowestLayer = Mathf.Min(lowestLayer, aState.layer); // if any new animation states have been added, then deal with them in a following iteration
// 这里判断有没有初始化没添加到哈希表的动画
if (!animInfoTable.ContainsKey(aState))
{
AddAnimInfoToTable(aState);
newlyAddedAnimationStates.Add(aState);
continue;
} info = (AnimInfo)animInfoTable[aState];
//我擦。又一次分配
info.currentNormalizedTime = aState.normalizedTime;
info.currentWeight = aState.weight; animInfoTable[aState] = info; // scrub the weight down to 0 for the next iteration
//为下一次做好准备??
aState.weight = 0f;
} // if any new AnimationStates have been added, add their info to the table
//有新的动画添加,就设置
if (newlyAddedAnimationStates != null && newlyAddedAnimationStates.Count > )
{
// first set all weights to 0, which will include newly added states
foreach (AnimationState aState in anim) aState.weight = 0f; // store all the properties for the new states
foreach (AnimationState aState in newlyAddedAnimationStates) SetupNewAnimInfo(aState);
} #endregion #region 计算层的整合,权重的分配。这里有些不懂的地方
// compute normalized AnimationState weights across layers since Unity does not expose them
//计算归AnimationState的重量跨越层,因为Unity不暴露他们
//总的权重,余下的权重
float remainingWeight = 1f;
//从最高层开始
for (int i = highestLayer; i >= lowestLayer; i--)
{
//所有动画(指当前的层)权重的总和
float weightOnThisLayer = 0f;
//用循环取当前层。layer层中可能有多个动画
foreach (AnimationState aState in anim)
{ if (aState.layer != i) continue;
//取当前层的当前动画信息
info = (AnimInfo)animInfoTable[aState]; // find out how much weight the animation state is actually contributing this frame
//没有启用动画,或者已分配完
if (!aState.enabled || remainingWeight <= 0f)
{
info.contributingWeight = 0f;
}
else
{
//实际上播放出来的权重
info.contributingWeight = remainingWeight * info.currentWeight;
//print(aState.name + "-- layer: " + aState.layer + "还余下的权重:" + remainingWeight + "这个动画当前的权重:"
// + info.currentWeight + "实际播放出来的权重" + info.contributingWeight);
}
//将这个层上所有的动画的权重加起来
weightOnThisLayer += info.contributingWeight;
//print(weightOnThisLayer);
animInfoTable[aState] = info;
}
// if the weight on this layer is > 1, then normalize it
// using Blend() or setting weights manually will not affect other weights on the layer, so they must be manually renormalized
//这个层上所有动画权重相加后的数大于1了
if (weightOnThisLayer > 1f)
{
//设置一个百分数来减少实际播放出来的权重
float oneOverWeightOnThisLayer = 1f / weightOnThisLayer;
//循环这个层的动画,并做出一些播出的权重的减少
foreach (AnimationState aState in anim)
{
if (aState.layer != i) continue;
info = (AnimInfo)animInfoTable[aState];
info.contributingWeight = info.contributingWeight * oneOverWeightOnThisLayer;
animInfoTable[aState] = info;
}
//重置为1
weightOnThisLayer = 1f;
}
//余下的权重 等于 减去分配后的权重
remainingWeight -= weightOnThisLayer;
} #endregion // reset the delta values for this frame
//重设此帧的增量值
dPosition = Vector3.zero;
dRotation = Quaternion.identity; // compute each AnimationState's individual contribution to the current frame's delta values
//计算每个动画的贡献,以当前帧的增量值
foreach (AnimationState aState in anim)
{
info = (AnimInfo)animInfoTable[aState]; // early out if this state was contributing nothing this frame
//如果没有权重,下一位
if (info.contributingWeight == 0f) continue; // early out if aState uses additive blending
// NOTE: Not entirely sure if this is ideal or not, but it generally should be
//如果混合模式为附加,则下一位
if (aState.blendMode == AnimationBlendMode.Additive) continue; // scrub the weight up to 1 for sampling values
//设置权重为1
aState.weight = 1f; // sample the values for the projected root configuration back one frame
// NOTE: cannot simply store these values from one frame to the next since user may manually change the time value at any point
//采样数值为投影机的根目录配置一帧
//注意:不能简单地存储这些值从一帧到下一个,因为用户可以在任何时候手动更改时间值
aState.time = aState.time - Time.deltaTime * aState.speed;
info.previousNormalizedTime = aState.normalizedTime;
anim.Sample();
info.previousAxis = GetProjectedAxis(pelvis, pelvisRightAxis);
info.previousPosition = GetProjectedPosition(pelvis); // sample the values for the projected root configuration at the current frame
aState.normalizedTime = info.currentNormalizedTime;
anim.Sample();
info.currentPosition = GetProjectedPosition(pelvis);
info.currentAxis = GetProjectedAxis(pelvis, pelvisRightAxis); // ensure both normalizedTime values are positive
info.previousNormalizedTime = 1f + info.previousNormalizedTime - (int)info.previousNormalizedTime;
info.currentNormalizedTime = 1f + info.currentNormalizedTime - (int)info.currentNormalizedTime; // determine the contribution to the root's delta this frame based on whether the animation looped since the previous frame
if (info.previousNormalizedTime - (int)info.previousNormalizedTime > info.currentNormalizedTime - (int)info.currentNormalizedTime)
{
// compute displacement with respect to identity
p = info.contributingWeight * ((info.endPosition - info.previousPosition) + (info.currentPosition - info.startPosition));
if (isRotationMode)
{
// rotate displacement into current orientation
p = Quaternion.FromToRotation(info.currentAxis, info.totalRotation * Vector3.right) * p;
// compute angular displacement and append to result
dRotation *= Quaternion.Slerp(Quaternion.identity,
Quaternion.FromToRotation(info.previousAxis, info.endAxis) * Quaternion.FromToRotation(info.startAxis, info.currentAxis),
info.contributingWeight);
}
// append displacement to result
dPosition += p;
}
else
{
// compute displacement with respect to identity
p = info.contributingWeight * (info.currentPosition - info.previousPosition);
if (isRotationMode)
{
// rotate displacement into current orientation
p = Quaternion.FromToRotation(info.currentAxis, Vector3.right) * p;
// compute angular displacement and append to result
dRotation *= Quaternion.Slerp(Quaternion.identity, Quaternion.FromToRotation(info.previousAxis, info.currentAxis), info.contributingWeight);
}
// append displacement to result
dPosition += p;
} // scrub the weight back down to 0 so as to not affect sampling of other states
aState.weight = 0f;
} // reset weights to where they were before computation
foreach (AnimationState aState in anim)
{
info = (AnimInfo)animInfoTable[aState];
aState.weight = info.currentWeight;
} // return the character to its current pose
anim.Sample(); // delta values for the first frame should simply move from the starting configuration into the current frame of animation
if (isFirstFrame)
{
// simply translate and rotate to the current projected position and orientation
dPosition = GetProjectedPosition(pelvis);
dRotation = Quaternion.FromToRotation(Vector3.right, GetProjectedAxis(pelvis, pelvisRightAxis)); // rotate displacement into current orientation
if (isRotationMode) dPosition = Quaternion.FromToRotation(GetProjectedAxis(pelvis, pelvisRightAxis), Vector3.right) * dPosition; isFirstFrame = false;
} // store the local position of the pelvis before returning it to hover over the root
pLocalPosition = pelvis.localPosition; // zero out the local x-component of the position delta if root translation method is z-only
if (computationMode == RootMotionComputationMode.ZTranslation) dPosition = Vector3.forward * Vector3.Dot(dPosition, Vector3.forward);
// otherwise zero out the local x-position of the pelvis
else pLocalPosition.x = 0f; // return the pelvis to a point hovering over the root
pLocalPosition.z = 0f;
pelvis.localPosition = pLocalPosition; // if computing rotation, then zero out local y-rotation of the pelvis
if (isRotationMode) pelvis.localRotation = Quaternion.FromToRotation(GetProjectedAxis(pelvis, pelvisRightAxis), Vector3.right) * pelvis.localRotation; // draw debug lines if requested
if (isDebugMode) DrawDebug(); // return if root movement is not requested (e.g. a character controller will use delta values)
if (!applyMotion) return; // apply rotation if requested
if (isRotationMode) rootNode.localRotation *= dRotation; // apply translation
rootNode.Translate(dPosition, Space.Self);
} /*
* Obtain the position of t projected onto rootNode's zx plane
* */
/// <summary>
/// 获取传入位置投射在根结点的ZX轴坐标的一个点 ,y = 0
/// </summary>
/// <param name="t">传入的位置</param>
/// <returns></returns>
private Vector3 GetProjectedPosition(Transform t)
{
Vector3 p = rootNode.InverseTransformPoint(t.position);
p.y = 0f;
return p;
} /*
* Obtain the projection of axis on t onto rootNode's zx plane
* */
/// <summary>
/// 获取根节点的zx平面上的投影轴
/// </summary>
/// <param name="t">传入的位置</param>
/// <param name="axis">方向</param>
/// <returns></returns>
private Vector3 GetProjectedAxis(Transform t, Vector3 axis)
{
Vector3 p = rootNode.InverseTransformDirection(t.TransformDirection(axis));
p.y = 0f;
return p;
} /*
* Draw axis tripods to show how root motion is being determined and applied
* */
private void DrawDebug()
{
// draw pelvis right axis
Debug.DrawRay(pelvis.position, pelvis.TransformDirection(pelvisRightAxis) * debugGizmoSize, Color.red); // draw root node axes
Debug.DrawRay(rootNode.position, rootNode.rotation * Vector3.forward * debugGizmoSize, Color.blue);
Debug.DrawRay(rootNode.position, rootNode.rotation * Vector3.right * debugGizmoSize, Color.red);
Debug.DrawRay(rootNode.position, rootNode.rotation * Vector3.up * debugGizmoSize, Color.green);
}
}

RootMotionComputer 根运动计算机的更多相关文章

  1. Animator根运动清除刚体速率问题测试

    在根运动打开时,施加AddForce,速率在后面几帧被清0了: 没有打开根运动AddForce的情况: unity论坛看了下,似乎有人遇到这个问题,而且无解.只能受力状态下关闭根运动 Q:Im wor ...

  2. 根运动 (Root Motion) – 工作原理

    http://blog.csdn.net/myarrow/article/details/45505085 1. 基本概念 在Unity3D动画中,模型的位置.角度经常会发生变化,我们需要决定是否将模 ...

  3. 说说用C语言求根的那些事儿

    C语言--求根:计算机只识别0和1,那么问题来了,作为计算工具如何解决数学问题?其实,计算机是死东西,都是程序员用计算机的的思维去加数学公式计算数学题的.听起来好高端的样子,其实啊,也就那么回事儿, ...

  4. Unity编辑器下获取动画的根运动状态并修改

    我最初想直接修改.anim文件 但通过后来得到的信息,其实根运动状态储存在FBX.meta文件里,转出的.anim文件虽然也有根运动的信息但是算是塌陷过的,无法进行开关操作. 这是我针对有根运动.an ...

  5. python应用-21根火柴游戏

    """ 21跟火柴 """ from random import randint def main(): total=21 while to ...

  6. Unity-Animator深入系列---API详解

    回到 Animator深入系列总目录 测试Unity版本为5.2.1 人形动画的接口都有标注 本列表不包含所有标注为过时的方法 1.Vector3 angularVelocity { get; } [ ...

  7. Unity-Animator深入系列---StateMachineBehaviour状态机脚本学习

    回到 Animator深入系列总目录 首先这个脚本必须继承自StateMachineBehaviour public class MySMB : StateMachineBehaviour { pub ...

  8. Unity-Animator深入系列---deltaPosition&deltaRotation

    回到 Animator深入系列总目录 官方文档给出的信息非常含糊 Gets the avatar delta position for the last evaluated frame. 测试了一下, ...

  9. 官方 Animator 例子解析 Animator.MatchTarget

    一.官方的解释 Animator.MatchTargetSwitch to Manual ); Parameters matchPosition The position we want the bo ...

随机推荐

  1. 我的OI生涯 第七章 终篇

    11.10日. 我们TSOI再次来到了熟悉的燕山大学,只不过这次是真刀真枪的干了. 望着那座熟悉的小桥,身边的好友不知此行过后还有多少. 下午才到,出人意外的是这次没有住燕大宾馆而是选择了熟悉的格林豪 ...

  2. POJ 3553 Light Switching Game 博弈论 nim积 sg函数

    http://poj.org/problem?id=3533 变成三维的nim积..前面hdu那个算二维nim积的题的函数都不用改,多nim积一次就过了...longlong似乎不必要但是还是加上了 ...

  3. ARC 101 C - Candles

    题面在这里! 显然直接枚举左端点(右端点)就OK啦. #include<cstdio> #include<cstdlib> #include<algorithm> ...

  4. 【DFS】BZOJ3522-[Poi2014]Hotel

    [题目大意] 给出一棵树,求三个节点使得它们两两之间的距离相等,问共有多少种可能性? [思路] 显然,这三个节点是关于一个中心点对称地辐射出去的. 枚举中心点,往它的各个子树跑Dfs.tmp[i]表示 ...

  5. [CC-ANUCBC]Cards, bags and coins

    [CC-ANUCBC]Cards, bags and coins 题目大意: 给你\(n(n\le10^5)\)个数,\(q(q\le30)\)次询问,问从中选取若干个数使得这些数之和为\(m(m\l ...

  6. poj 2912 并查集(食物链加强版)

    题目:给出n个人玩剪刀石头布的游戏,其中有一个人是裁判,剩下的人分为3组,每一组的人只出某一种手型,裁判可以任意出.问是否能判断出哪个人是裁判 链接:点我 分分钟看吐血,先把食物链看懂吧 枚举裁判,然 ...

  7. python开发_tempfile

    python中的tempfile模块,是为创建临时文件(夹)所提供的 如果你的应用程序需要一个临时文件来存储数据,但不需要同其他程序共享,那么tempfile模块来创建临时文件(夹)是个不错的选择 其 ...

  8. CROC 2016 - Qualification C. Hostname Aliases map

    C. Hostname Aliases 题目连接: http://www.codeforces.com/contest/644/problem/C Description There are some ...

  9. C#利用NPOI在同一个Excel文件中创建多个sheet

    借用NPOI来实现,要在同一Excel文件中创建多个sheet,只需要在同一个workbook中创建多个sheet即可.要注意的是,sheet的名字一定不能重复.下面是实现的代码: private v ...

  10. Hyper-v: Snapshot merge

    我有一个Hyper-V上的虚拟机, 在使用的过程中我给这个虚拟机创建了多个snapshots. 有一天我把整个的snapshots tree从root删掉了(delete snapshot with ...