Aim Pole

This scene demonstrates how you can have 360 degrees of aiming freedom with just 6 static aim poses and AimIK.
这个场景演示了如何用6个静态瞄准姿势和AimIK获得360度的瞄准自由。

The aim poses (forward, left, back, right, up, down) are cross-faded between based on the direction from the character towards the target.
目标姿势(前、左、后、右、上、下)会根据角色朝向目标的方向淡入淡出。

The directions and ranges for those 6 poses are defined in AimPoser.cs on the “Aim Poser” GameObject.
The names of the poses must match with the parameters set in the animator controller.

在“Aim Poser”游戏对象上的AimPoser.cs脚本上定义了这6个姿势的方向和范围。
姿势的名称必须与动画控制器中设置的参数匹配

Direct blend trees are used to work around Mecanim’s cross-fading issues
(won’t cross-fade back to a state it is still cross-fading from, ignoring the call)

直接blend tree(混合树)用于解决Mecanimus动画系统的交叉淡入淡出问题。
(不会淡入淡出回到它仍然淡入淡出的状态,忽略调用)

AimIK works on top of that to correct the static poses to always keep the gun aimed at the target. All AimIK ever does is rotating the spine hierarchy.
AImIK除了修正静态姿势外,还一直保持枪瞄准目标。AimIK所做的一切都是旋转脊椎层次结构。

LookAtIK is also used for rotating the head to face the target.
LookAtIk 用于旋转头部以面对目标。

SimpleAimingSystemMecanim.cs on “Dummy Legacy” in resposible for cross-fading between the aim poses and updating the IK target position
SimpleAimingSystemMecanim.cs 脚本是在"Dummy Legacy(人物) " 在目标姿态之间进行淡入淡出和更新IK目标位置*

Aim Poser
The names of the Poses must match exactly with the parameters of the Direct blend tree in the Animator Controller’s “Upperbody Aiming” layer.
姿态的名称必须与动画控制器的“Upperbody Aiming”层中的直接混合树的参数完全匹配

Top:

  • pitch是围绕X轴旋转,也叫做俯仰角,
  • yaw是围绕Y轴旋转,也叫偏航角,
  • roll是围绕Z轴旋转,也叫翻滚角,
    在这里插入图片描述
    俯仰角θ(pitch):
    机体坐标系X轴与水平面的夹角。
    当X轴的正半轴位于过坐标原点的水平面之上(抬头)时,俯仰角为正,否则为负。
    pitch是围绕X轴旋转,也叫做俯仰角,
    如图所示:
    在这里插入图片描述
    偏航角ψ(yaw):
    yaw是围绕Y轴旋转,也叫偏航角,
    如图所示。
    在这里插入图片描述
    翻滚角Φ(roll):
    roll是围绕Z轴旋转,也叫翻滚角,
    如图所示:
    在这里插入图片描述

这个案例是通过AimIK的Target在人物不同的方向和位置,来改变人物动画,
效果:
在这里插入图片描述
还有一些向前向后的就不显示了,电脑太卡了…(⊙_⊙;)…

代码:

AimPoser

using UnityEngine;
using System.Collections;
using RootMotion;

namespace RootMotion.FinalIK {

	/// <summary>
	/// Aim Poser returns a reference by direction.
    /// 瞄准的姿势按照方向返回
	/// </summary>
	public class AimPoser : MonoBehaviour {

        /// <summary>
        /// the pose definition
        /// 姿态定义
        /// </summary>
        [System.Serializable]
		public class Pose {

            // Show the direction and range of this pose in the scene view
            //在场景视图中显示该姿态的方向和范围
            public bool visualize = true;
            // the reference
            //引用姿势名
            public string name;
            // the direction of the pose
            //瞄准姿势的方向
            public Vector3 direction;
            // the yaw range
            //俯仰角范围
            public float yaw = 75f;
            // the pitch range
            //偏航角范围
            public float pitch = 45f; 
            //角度缓冲器
			private float angleBuffer;

            // Determines whether this Pose is in the specified direction.
            //确认此姿势是否处于指定的方向。
            public bool IsInDirection(Vector3 d) {
				if (direction == Vector3.zero)
                    return false;
				if (yaw <= 0 || pitch <= 0)
                    return false;

                // Yaw
                //偏航角
                if (yaw < 180f) {
					Vector3 directionYaw = new Vector3(direction.x, 0f, direction.z);
					if (directionYaw == Vector3.zero)
                        directionYaw = Vector3.forward;

					Vector3 dYaw = new Vector3(d.x, 0f, d.z);
					float yawAngle = Vector3.Angle(dYaw, directionYaw);

					if (yawAngle > yaw + angleBuffer)
                        return false;
				}

                // Pitch
                //俯仰角
                if (pitch >= 180f)
                    return true;

				float directionPitch = Vector3.Angle(Vector3.up, direction);
				float dPitch = Vector3.Angle(Vector3.up, d);
				return Mathf.Abs(dPitch - directionPitch) < pitch + angleBuffer;
			}

            // Sets the angle buffer to prevent immediatelly switching back to the last pose if the angle should change a bit.
            //设置角度缓冲区,以防止在角度应该稍微改变时立即切换回最后一个姿势。
            public void SetAngleBuffer(float value) {
				angleBuffer = value;
			}
		}

        // The angle buffer
        //缓冲角
        public float angleBuffer = 5f;
        //The array of poses.
        //poses 脚本的数组
        public Pose[] poses = new Pose[0];

        /// <summary>
        /// Gets the pose by direction. GetPose will go through the poses array and return the first pose that has the direction in range.
        /// 按方向获取姿态。GetPose将遍历姿态数组,并返回第一个在范围中具有方向的姿态。
        /// </summary>
        public Pose GetPose(Vector3 localDirection)
        {
			if (poses.Length == 0)
                return null;

			for (int i = 0; i < poses.Length - 1; i++)
                if (poses[i].IsInDirection(localDirection))
                    return poses[i];
			return poses[poses.Length - 1];
		}

        /// <summary>
        /// Sets the pose active, increasing it's angle buffer.
        /// 设置有效的姿势,增加它的角度缓冲器。
        /// </summary>
        public void SetPoseActive(Pose pose) {
			for (int i = 0; i < poses.Length; i++) {
				poses[i].SetAngleBuffer(poses[i] == pose? angleBuffer: 0f);
			}
		}
	}
}

SimpleAimingSystem

using RootMotion.Demos;
using UnityEngine;
using System.Collections;
using RootMotion.FinalIK;

namespace RootMotion.Demos {

    // Demonstrating 360-degree aiming system built with 6 static aiming poses and AimIK.
    //演示了360度瞄准系统,由6个静态瞄准姿态和AimIK组成。
    public class SimpleAimingSystem : MonoBehaviour {
		
		[Tooltip("AimPoser is a tool that returns an animation name based on direction.")]
        //AimPoser 是一个根据方向返回动画名称的工具。
        public AimPoser aimPoser;
		
		[Tooltip("Reference to the AimIK component.")]
        //引用AimIK 组件
		public AimIK aim;
		
		[Tooltip("Reference to the LookAt component (only used for the head in this instance).")]
        //引用LookAtIk 组件 (在这种情况下只用于头部)
        public LookAtIK lookAt;
		
		[Tooltip("Reference to the Animator component.")]
        //引用Animator 组件
		public Animator animator;
		
		[Tooltip("Time of cross-fading from pose to pose.")]
        //两姿势逐渐转变的时间
		public float crossfadeTime = 0.2f;

		[Tooltip("Will keep the aim target at a distance.")]
        //将目标保持在一定距离
        public float minAimDistance = 0.5f;
		
		private AimPoser.Pose aimPose, lastPose;

		void Start() {
            // Disable IK components to manage their updating order
            //禁用IK组件管理其更新顺序
            aim.enabled = false;
			lookAt.enabled = false;
		}

        // LateUpdate is called once per frame
        //每帧调用一次LateUpdate
        void LateUpdate () {
			if (aim.solver.target == null) {
				Debug.LogWarning("AimIK and LookAtIK need to have their 'Target' value assigned.", transform);
                Debug.LogWarning("AimIk 和 lookAtIk 必需分配‘Target(目标)给他’",transform);
			}

            // Switch aim poses (Legacy animation)
            //切换目标姿势(Legacy动画)
            Pose();

			// Update IK solvers
            //更新IK求解器
			aim.solver.Update();
			if (lookAt != null) lookAt.solver.Update();
		}
		
		private void Pose() {
            // Make sure aiming target is not too close (might make the solver instable when the target is closer to the first bone than the last bone is).
            //确保瞄准目标不是太近(当目标比最底层骨骼更靠近父级骨骼时,可能使求解器不稳定)。
            LimitAimTarget();

			// Get the aiming direction
            // 获得瞄准方向

            Vector3 direction = (aim.solver.target.position - aim.solver.bones[0].transform.position);
            // Getting the direction relative to the root transform
            //获得相对于root(根)变换的方向
            Vector3 localDirection = transform.InverseTransformDirection(direction);
			
			// Get the Pose from AimPoser
            //获取Pose 从AimPoser脚本
			aimPose = aimPoser.GetPose(localDirection);

            // If the Pose has changed
            //如果姿势改变了
            if (aimPose != lastPose) {
                // Increase the angle buffer of the pose so we won't switch back too soon if the direction changes a bit
                //增加姿势的角度缓冲,这样如果方向稍微改变,我们不会很快切换回来。
                aimPoser.SetPoseActive(aimPose);

                // Store the pose so we know if it changes
                //存储姿势,让我们知道它是否会改变
                lastPose = aimPose;
			}

            // Direct blending
            //直接混合
            foreach (AimPoser.Pose pose in aimPoser.poses) {
				if (pose == aimPose) {
					DirectCrossFade(pose.name, 1f);
				} else {
					DirectCrossFade(pose.name, 0f);
				}
			}
		}

        // Make sure aiming target is not too close (might make the solver instable when the target is closer to the first bone than the last bone is).
        //确保瞄准目标不是太近(当目标比最底层骨骼更靠近父级骨骼时,可能使求解器不稳定)。
        void LimitAimTarget() {
			Vector3 aimFrom = aim.solver.bones[0].transform.position;
			Vector3 direction = (aim.solver.target.position - aimFrom);
			direction = direction.normalized * Mathf.Max(direction.magnitude, minAimDistance);
			
			aim.solver.target.position = aimFrom + direction;
		}
		
		// Uses Mecanim's Direct blend trees for cross-fading
        //使用Mecanim's Direct 混合树进行逐渐转变
		private void DirectCrossFade(string state, float target) {
			float f = Mathf.MoveTowards(animator.GetFloat(state), target, Time.deltaTime * (1f / crossfadeTime));
			animator.SetFloat(state, f);
		}
	}
}

Aim IK
在这里插入图片描述

LookAtIK
在这里插入图片描述
效果:
在这里插入图片描述

一些相关的知识:
姿态角
https://jingyan.baidu.com/article/0bc808fc2c0e851bd485b9ce.html
FinalIk的官方API
http://root-motion.com/finalikdox/html/pages.html

猜你喜欢

转载自blog.csdn.net/qq_42782299/article/details/84575826