Unity 真实物理动力学实时计算

来源:互联网 发布:佳能wifi软件app 编辑:程序博客网 时间:2024/06/11 22:26

独立开发也很多很多年头了.一直被身边的朋友吐槽我什么都不说
在csdn也有几个年头了.
最近又被一些国外友人吐槽我. 稀字如金
所信就借这个博客写点东西吧.哈哈这个也算是我人生的第一篇博文啊
好了.废话不表,进入正题.

===================我是分割线===================

这个想法最初来源于我为了实现游戏Claidia中的各种飘动摆动效果.但是由于Unity原生的似乎达不到我想要的那种可以随意控制.调整张力.重力.以及其他系数的功能.
所以一直在想说能不能通过DX11来实现.但是那样似乎效率上有些问题.流畅度可能达不到一个游戏的运行标准.毕竟一个大型MMO单帧画面渲染全屏用户至少要保证100个动态单位吧.
所以对效率还是有一定要求的.因此在为了保证效率和质量的情况下.一次玩某款日本的游戏的时候从中得到灵感.
下面上代码
整套动力系统模拟由一个主管理类和每个分节点受力计算类控制
首先主管理类:
PhysicalDynamicsSystem.cs

using UnityEngine;using System.Collections.Generic;namespace DIYPhySys{    public class PhysicalDynamicsSystem : MonoBehaviour    {        static PhysicalDynamicsSystem PDManager;        public float dynamicRatio = 1.0f;        public Transform Bip;        public float            stiffnessForce;        public AnimationCurve   stiffnessCurve;        public float            dragForce;        public AnimationCurve   dragCurve;        public List<DynamicsBone> dynamicsBones = new List<DynamicsBone>();        public bool SetOnce;        public bool AllTest;        void Awake(){PDManager = this;}        public static PhysicalDynamicsSystem GetSpmm() { return PDManager; }        void Start ()        {            dynamicsBones.Clear();            DynamicsBone[] dbs = Bip.GetComponentsInChildren<DynamicsBone>();            for (int i = 0; i < dbs.Length; i ++)            {                if (AllTest)                {                    dbs[i].stiffnessForce = stiffnessForce;                    dbs[i].dragForce = dragForce;                }                if (dbs[i].child)                    dynamicsBones.Add(dbs[i]);            }            GetComponent<RandomWind>().IntStart(this);            UpdateParameters ();        }        void Set()        {            if(SetOnce)            {                SetOnce = false;                foreach (DynamicsBone db in dynamicsBones)                {                    db.stiffnessForce = stiffnessForce;                    db.dragForce = dragForce;                }            }        }        void Update ()        {            Set();#if UNITY_EDITOR            if (dynamicRatio >= 1.0f)            dynamicRatio = 1.0f;        else if(dynamicRatio <= 0.0f)            dynamicRatio = 0.0f;        UpdateParameters();#endif        }        private void LateUpdate ()        {            if (dynamicRatio != 0.0f) {                for (int i = 0; i < dynamicsBones.Count; i++) {                    if (dynamicRatio > dynamicsBones [i].threshold) {                        dynamicsBones [i].UpdateSpring ();                    }                }            }        }        private void UpdateParameters ()        {            UpdateParameter ("stiffnessForce", stiffnessForce, stiffnessCurve);            UpdateParameter ("dragForce", dragForce, dragCurve);        }        private void UpdateParameter (string fieldName, float baseValue, AnimationCurve curve)        {            var start = curve.keys [0].time;            var end = curve.keys [curve.length - 1].time;            //var step  = (end - start) / (springBones.Length - 1);            var prop = dynamicsBones [0].GetType ().GetField (fieldName, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);            for (int i = 0; i < dynamicsBones.Count; i++) {                if (!dynamicsBones [i].isUseEachBoneForceSettings) {                    var scale = curve.Evaluate (start + (end - start) * i / (dynamicsBones.Count - 1));                    prop.SetValue (dynamicsBones [i], baseValue * scale);                }            }        }    }}

其次分节点编辑器模式下的可视化帮助:
DynamicsCollider.cs

using UnityEngine;using System.Collections;namespace DIYPhySys{    public class DynamicsCollider : MonoBehaviour    {        //半径        public float radius = 0.5f;        private void OnDrawGizmosSelected ()        {            Gizmos.color = Color.green;            Gizmos.DrawWireSphere (transform.position, radius);        }    }}

最后每个分节点真实物理动力学受力和力反馈类:

DynamicsBone.cs

using UnityEngine;using System.Collections.Generic;namespace DIYPhySys{    public class DynamicsBone : MonoBehaviour    {        public Transform child;        public Vector3 boneAxis = new Vector3 (-1.0f, 0.0f, 0.0f);        public float radius = 0.05f;        public bool isUseEachBoneForceSettings = false;         public float stiffnessForce = 0.01f;        public float dragForce = 0.4f;        public Vector3 springForce = new Vector3 (0.0f, -0.0001f, 0.0f);            public List<DynamicsCollider> colliders = new List<DynamicsCollider>();        public bool debug = true;        public float threshold = 0.01f;        private float springLength;        private Quaternion localRotation;        private Transform trs;        private Vector3 currTipPos;        private Vector3 prevTipPos;        private Transform org;        private PhysicalDynamicsSystem managerRef;        private void Awake ()        {            if (child)            {                trs = transform;                localRotation = transform.localRotation;                managerRef = GetParentSpringManager(transform);            }        }        private PhysicalDynamicsSystem GetParentSpringManager (Transform t)        {            var springManager = t.GetComponent<PhysicalDynamicsSystem> ();            if (springManager != null)                return springManager;            if (t.parent != null) {                return GetParentSpringManager (t.parent);            }            return null;        }        private void Start ()        {            if (child)            {                springLength = Vector3.Distance(trs.position, child.position);                currTipPos = child.position;                prevTipPos = child.position;            }        }        public void UpdateSpring ()        {            org = trs;            trs.localRotation = Quaternion.identity * localRotation;            float sqrDt = Time.deltaTime * Time.deltaTime;            Vector3 force = trs.rotation * (boneAxis * stiffnessForce) / sqrDt;            force += (prevTipPos - currTipPos) * dragForce / sqrDt;            force += springForce / sqrDt;            Vector3 temp = currTipPos;            currTipPos = (currTipPos - prevTipPos) + currTipPos + (force * sqrDt);            currTipPos = ((currTipPos - trs.position).normalized * springLength) + trs.position;            for (int i = 0; i < colliders.Count; i++) {                if (Vector3.Distance (currTipPos, colliders [i].transform.position) <= (radius + colliders [i].radius)) {                    Vector3 normal = (currTipPos - colliders [i].transform.position).normalized;                    currTipPos = colliders [i].transform.position + (normal * (radius + colliders [i].radius));                    currTipPos = ((currTipPos - trs.position).normalized * springLength) + trs.position;                }            }            prevTipPos = temp;            Vector3 aimVector = trs.TransformDirection (boneAxis);            Quaternion aimRotation = Quaternion.FromToRotation (aimVector, currTipPos - trs.position);            Quaternion secondaryRotation = aimRotation * trs.rotation;            trs.rotation = Quaternion.Lerp (org.rotation, secondaryRotation, managerRef.dynamicRatio);        }        private void OnDrawGizmos ()        {            if (debug) {                Gizmos.color = Color.yellow;                Gizmos.DrawWireSphere (currTipPos, radius);            }        }    }}

到此全部代码贴出

大家根据自己需要灵活运用就可以得到想要的真实物理模拟反馈啦
主要注意的是 主管理类 请绑定到骨骼根节点哦.其次这个模拟是根据骨骼节点数量来运行的
主节点统一对根节点进行力传递.然后跟节点根据各自的特性系数进行不同的力衰减力回馈还有力传导的计算模拟.
感谢大家阅读了.
以后我会有时间有心情了在和大家分享一些有价值的东西
^_^
[转载请注明作者和出处]
====================我是分割线====================

0 0
原创粉丝点击