Lossless movement in hinge joints - Unity
我已经在Unity中创建了一个简单的摆锤-带有刚体和铰链接头组件的GameObject。我已经将两个拖动角度和角度拖动都设置为0。在90度的起始位置,我希望钟摆能从90度到-90度来回摆动。但是,情况并非如此-幅度衰减非常快,但是对于小角度,摆似乎永远不会停止。
我的问题是:我应该如何配置铰链接头,以完全控制物理和抵抗运动的力???我的目标是使物理模拟尽可能精确,即使以性能为代价。
我已经尝试过减少固定步长的时间间隔并增加求解器的迭代次数-这些都没有解决。
我为什么需要它?我打算为一个推车上的多个倒立摆设计一个控制系统。我有一个在Matlab中实现的摆锤的数学模型,我想在Unity中使用一个简单的模型对其进行验证(因为在这种情况下,我会调整所有参数,初始条件等,而物理引擎正在为我计算一切)。如果事实证明支持Unity的物理引擎不够可靠,您还会推荐我使用什么其他软件?
将刚体上的maxAngularVelocity设置为Mathf.Infinity。
我知道这个话题已经有9个月了,但是由于这个问题,我最近一直在撞墙。由于某些原因,Unity开发人员认为将刚性体的最大旋转速度限制为每秒7弧度是一个好主意!每秒仅旋转一圈多一点,对于任何需要物理精度的应用来说太低了。最重要的是,该属性在检查器或物理设置中不可见!
希望对您有帮助(如果您还没有自己解决),以及将来可能与这个问题作斗争的其他任何人都可以欢呼!
我的理解是,由于Unity物理学的运行方式,如果仅使用铰链关节,则这种摆运动会随着时间的流逝而失去动能。基本上,如果您想进行精确的摆锤模拟,则必须绕过物理引擎并直接实现它。
MLM最初在gamedev stackexchange上有一篇非常好的文章,内容涉及如何在Unity中实现更精确的摆锤模拟,我在下面进行了粘贴。
我以为这是一个相对简单的问题,但是我花了几天的时间试图弄清楚如何模拟摆运动。我不想作弊,只是根据sin(theta)和cos(theta)曲线更改x,y位置。相反,我想应对现实生活中应用的两种力量:重力和张力。我所缺少的主要是向心力。
摆锤(数学)维基百科页面上有一个很棒的动画(在左下),用于说明摆锤的运动。您可以看到我的结果(右)与该图非常相似
" bob"是摆动的对象," pivot"是起点/根。
当鲍勃接近平衡点(中间)时,张力更大的原因是由于向心力:
因此,随着鲍勃摆动,总体张力公式如下:
摆系统中有两种作用力:
-
重力
-
GravityForce = mass * gravity.magnitude -
GravityDirection = gravity.normalized
-
-
张力
-
TensionForce = (mass * gravity * Cos(theta)) + ((mass * velocityTangent^2)/ropeLength) -
TensionDirection = ropeDirection = bob to pivot
-
只需像对待普通物体一样对物体施加重力,然后施加张力即可。施加力时,只需将力乘以方向和deltaTime。
下面是
该脚本可在3D模式下运行,但当然只能在2D平面内摆动。它也可以在任何方向上与重力共同作用。因此,例如,如果您反转重力,则钟摆将上下颠倒。
在更新钟摆时,始终保持相对较小的deltaTime非常重要,这样您就不会在曲线周围反弹。我正在使用本文中发现的技巧,修复您的时间!由Glenn Fiedler完成。检查下面的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 | using UnityEngine; using System.Collections; // Author: Eric Eastwood (ericeastwood.com) // // Description: // Written for this gd.se question: http://gamedev.stackexchange.com/a/75748/16587 // Simulates/Emulates pendulum motion in code // Works in any 3D direction and with any force/direciton of gravity // // Demonstration: https://i.imgur.com/vOQgFMe.gif // // Usage: https://i.imgur.com/BM52dbT.png public class Pendulum : MonoBehaviour { public GameObject Pivot; public GameObject Bob; public float mass = 1f; float ropeLength = 2f; Vector3 bobStartingPosition; bool bobStartingPositionSet = false; // You could define these in the `PendulumUpdate()` loop // But we want them in the class scope so we can draw gizmos `OnDrawGizmos()` private Vector3 gravityDirection; private Vector3 tensionDirection; private Vector3 tangentDirection; private Vector3 pendulumSideDirection; private float tensionForce = 0f; private float gravityForce = 0f; // Keep track of the current velocity Vector3 currentVelocity = new Vector3(); // We use these to smooth between values in certain framerate situations in the `Update()` loop Vector3 currentStatePosition; Vector3 previousStatePosition; // Use this for initialization void Start () { // Set the starting position for later use in the context menu reset methods this.bobStartingPosition = this.Bob.transform.position; this.bobStartingPositionSet = true; this.PendulumInit(); } float t = 0f; float dt = 0.01f; float currentTime = 0f; float accumulator = 0f; void Update() { /* */ // Fixed deltaTime rendering at any speed with smoothing // Technique: http://gafferongames.com/game-physics/fix-your-timestep/ float frameTime = Time.time - currentTime; this.currentTime = Time.time; this.accumulator += frameTime; while (this.accumulator >= this.dt) { this.previousStatePosition = this.currentStatePosition; this.currentStatePosition = this.PendulumUpdate(this.currentStatePosition, this.dt); //integrate(state, this.t, this.dt); accumulator -= this.dt; this.t += this.dt; } float alpha = this.accumulator/this.dt; Vector3 newPosition = this.currentStatePosition*alpha + this.previousStatePosition*(1f-alpha); this.Bob.transform.position = newPosition; //this.currentStatePosition; /* */ //this.Bob.transform.position = this.PendulumUpdate(this.Bob.transform.position, Time.deltaTime); } // Use this to reset forces and go back to the starting position [ContextMenu("Reset Pendulum Position")] void ResetPendulumPosition() { if(this.bobStartingPositionSet) this.MoveBob(this.bobStartingPosition); else this.PendulumInit(); } // Use this to reset any built up forces [ContextMenu("Reset Pendulum Forces")] void ResetPendulumForces() { this.currentVelocity = Vector3.zero; // Set the transition state this.currentStatePosition = this.Bob.transform.position; } void PendulumInit() { // Get the initial rope length from how far away the bob is now this.ropeLength = Vector3.Distance(Pivot.transform.position, Bob.transform.position); this.ResetPendulumForces(); } void MoveBob(Vector3 resetBobPosition) { // Put the bob back in the place we first saw it at in `Start()` this.Bob.transform.position = resetBobPosition; // Set the transition state this.currentStatePosition = resetBobPosition; } Vector3 PendulumUpdate(Vector3 currentStatePosition, float deltaTime) { // Add gravity free fall this.gravityForce = this.mass * Physics.gravity.magnitude; this.gravityDirection = Physics.gravity.normalized; this.currentVelocity += this.gravityDirection * this.gravityForce * deltaTime; Vector3 pivot_p = this.Pivot.transform.position; Vector3 bob_p = this.currentStatePosition; Vector3 auxiliaryMovementDelta = this.currentVelocity * deltaTime; float distanceAfterGravity = Vector3.Distance(pivot_p, bob_p + auxiliaryMovementDelta); // If at the end of the rope if(distanceAfterGravity > this.ropeLength || Mathf.Approximately(distanceAfterGravity, this.ropeLength)) { this.tensionDirection = (pivot_p - bob_p).normalized; this.pendulumSideDirection = (Quaternion.Euler(0f, 90f, 0f) * this.tensionDirection); this.pendulumSideDirection.Scale(new Vector3(1f, 0f, 1f)); this.pendulumSideDirection.Normalize(); this.tangentDirection = (-1f * Vector3.Cross(this.tensionDirection, this.pendulumSideDirection)).normalized; float inclinationAngle = Vector3.Angle(bob_p-pivot_p, this.gravityDirection); this.tensionForce = this.mass * Physics.gravity.magnitude * Mathf.Cos(Mathf.Deg2Rad * inclinationAngle); float centripetalForce = ((this.mass * Mathf.Pow(this.currentVelocity.magnitude, 2))/this.ropeLength); this.tensionForce += centripetalForce; this.currentVelocity += this.tensionDirection * this.tensionForce * deltaTime; } // Get the movement delta Vector3 movementDelta = Vector3.zero; movementDelta += this.currentVelocity * deltaTime; //return currentStatePosition + movementDelta; float distance = Vector3.Distance(pivot_p, currentStatePosition + movementDelta); return this.GetPointOnLine(pivot_p, currentStatePosition + movementDelta, distance <= this.ropeLength ? distance : this.ropeLength); } Vector3 GetPointOnLine(Vector3 start, Vector3 end, float distanceFromStart) { return start + (distanceFromStart * Vector3.Normalize(end - start)); } void OnDrawGizmos() { // purple Gizmos.color = new Color(.5f, 0f, .5f); Gizmos.DrawWireSphere(this.Pivot.transform.position, this.ropeLength); Gizmos.DrawWireCube(this.bobStartingPosition, new Vector3(.5f, .5f, .5f)); // Blue: Auxilary Gizmos.color = new Color(.3f, .3f, 1f); // blue Vector3 auxVel = .3f * this.currentVelocity; Gizmos.DrawRay(this.Bob.transform.position, auxVel); Gizmos.DrawSphere(this.Bob.transform.position + auxVel, .2f); // Yellow: Gravity Gizmos.color = new Color(1f, 1f, .2f); Vector3 gravity = .3f * this.gravityForce*this.gravityDirection; Gizmos.DrawRay(this.Bob.transform.position, gravity); Gizmos.DrawSphere(this.Bob.transform.position + gravity, .2f); // Orange: Tension Gizmos.color = new Color(1f, .5f, .2f); // Orange Vector3 tension = .3f * this.tensionForce*this.tensionDirection; Gizmos.DrawRay(this.Bob.transform.position, tension); Gizmos.DrawSphere(this.Bob.transform.position + tension, .2f); // Red: Resultant Gizmos.color = new Color(1f, .3f, .3f); // red Vector3 resultant = gravity + tension; Gizmos.DrawRay(this.Bob.transform.position, resultant); Gizmos.DrawSphere(this.Bob.transform.position + resultant, .2f); /* * / // Green: Pendulum side direction Gizmos.color = new Color(.3f, 1f, .3f); Gizmos.DrawRay(this.Bob.transform.position, 3f*this.pendulumSideDirection); Gizmos.DrawSphere(this.Bob.transform.position + 3f*this.pendulumSideDirection, .2f); /* */ /* * / // Cyan: tangent direction Gizmos.color = new Color(.2f, 1f, 1f); // cyan Gizmos.DrawRay(this.Bob.transform.position, 3f*this.tangentDirection); Gizmos.DrawSphere(this.Bob.transform.position + 3f*this.tangentDirection, .2f); /* */ } } |
更多魅力照片: