IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> CCD IK(循环坐标下降逆动态学) -> 正文阅读

[游戏开发]CCD IK(循环坐标下降逆动态学)

CCDIK(循环坐标下降逆动态学)

策略思路
1.骨骼间的结构为子父层次链接(父节点的变换会影响子节点的)
2.每个骨骼都以【自身轴点到尾叶子节点的方向】旋转到【自身轴点到目标点方向】,开始趋近
3.最终效果与迭代次数成正比
在这里插入图片描述
更多细节查看 IK

Arrow类

    [Serializable]
    public class Arrow
    {
        public float len;		//箭头长度
        public float angle;		//相对父箭头方向的角度
        public Vector2 angleLimt = new Vector2(-180f,180f);		//角度限制

        public Color color;			//Gizmo Color

        public Vector2 a { get; private set; }  //起点
        public Vector2 b { get; private set; }  //终点
        public Vector2 forward { get { return (b - a).normalized; } }

        /// <summary>
        /// 箭头看向目标位置
        /// </summary>
        /// <param name="target">目标位置</param>
        /// <param name="end">评估节点位置</param>
        /// <param name="limt">角度限制</param>
        public void Follow(Vector2 target, Vector2 end, bool limt)
        {
            angle = (angle + Vector2.SignedAngle(end - a, target - a)) % 360f;

            if (limt && (angleLimt.x != -180 || angleLimt.y != 180))
            {
                angle = Mathf.Clamp(angle, angleLimt.x, angleLimt.y);
            }
        }
        /// <summary>
        /// 计算箭头 A、B 点位置
        /// </summary>
        /// <param name="origin">起点</param>
        /// <param name="right">父箭头方向</param>
        public void Calculate_AB(Vector2 origin, Vector2 right)
        {
            a = origin;
            b = a + Rotate(right, angle) * len;
        }

        /// <summary>
        /// 返回旋转后的角度
        /// </summary>
        /// <param name="v">normal</param>
        /// <param name="a">rad</param>
        private Vector2 Rotate(Vector2 v, float a)
        {
            a = a * Mathf.Deg2Rad + Mathf.Atan2(v.y, v.x);
            return new Vector2(Mathf.Cos(a), Mathf.Sin(a));
        }
    }

IKSolverCCD 类

    [Serializable]
    public class IKSolverCCD {

        public Arrow[] arrows = new Arrow[] { };    //箭头集合

        public Vector2 target;  //目标位置

        public bool useLimt = false;        //是否启用角度限制

        public int iterations = 4;      //迭代次数

        /// <summary>
        /// 箭头线段跟踪目标位置
        /// </summary>
        /// <param name="maxIterations">迭代次数</param>
        public void FollowTarget()
        {
            for (int n = 0; n < iterations; n++)
            {
                for (int i = arrows.Length - 1; i >= 0; i--)
                {
                    arrows[i].Follow(target, arrows[arrows.Length - 1].b, useLimt);

                    UpdatePosition(i == 0 ? Vector2.right : arrows[i - 1].forward, i);
                }
            }
        }

        /// <summary>
        /// 集合箭头从指定顺序索引开始更新箭头 A、B 点位置
        /// </summary>
        /// <param name="arrows">箭头集合</param>
        /// <param name="right">父箭头方向</param>
        /// <param name="n">指定顺序索引</param>
        public void UpdatePosition(Vector2 right, int n = 0)
        {
            Vector2 origin = arrows[n].a;
            for (; n < arrows.Length; n++)
            {
                arrows[n].Calculate_AB(origin, right);
                origin = arrows[n].b;
                right = arrows[n].forward;
            }
        }
    }

CCDTest类

    public class CCDTest : MonoBehaviour
    {
        public IKSolverCCD iKSolverCCD;     //CCD 解算器
        public Transform targetP;       //目标位置
        public Transform anchorP;       //固定位置

        public bool useLimt = true;     //使用限制
        public bool update = false;     //实时更新
        [Range(1,10)]
        public int iterations = 1;      //迭代次数

        [Button("UpdateAnchor")]
        void UpdateAnchor()
        {
            iKSolverCCD.useLimt = useLimt;
            iKSolverCCD.iterations = iterations;
            iKSolverCCD.arrows[0].Calculate_AB(anchorP.position, Vector2.right);
            iKSolverCCD.UpdatePosition(Vector2.right);
            iKSolverCCD.FollowTarget();
        }
        [Button("Calculate")]
        void Calculate()
        {
            iKSolverCCD.useLimt = useLimt;
            iKSolverCCD.iterations = iterations;
            iKSolverCCD.target = targetP.position;
            iKSolverCCD.FollowTarget();
        }
        private void OnDrawGizmos()
        {
            if (update) {
                Calculate();
            }

            Arrow last = null;
            foreach (var item in iKSolverCCD.arrows)
            {
                Gizmos.color = item.color;
                Mov.GizmeDrawArrow(item.a, item.b);

                if (useLimt)
                {
                    Mov.GizmeDrawCircleLimt(item.a, item.forward, item.angleLimt, 0, item.len / 4f, last == null ? (item.a-Vector2.right): last.a);
                }
                last = item;
            }
        }
    }

测试

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2022-03-15 22:58:26  更:2022-03-15 23:01:16 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/16 18:02:29-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码