{"id":2003,"date":"2019-01-21T16:17:12","date_gmt":"2019-01-21T08:17:12","guid":{"rendered":"http:\/\/www.clonefactor.com\/wordpress\/?p=2003"},"modified":"2019-01-21T16:31:39","modified_gmt":"2019-01-21T08:31:39","slug":"%e7%ad%86%e8%a8%98-%e8%87%aa%e5%ae%9a%e7%be%a9%e7%89%a9%e7%90%86-physics-computepenetration","status":"publish","type":"post","link":"https:\/\/www.clonefactor.com\/wordpress\/program\/c\/2003\/","title":{"rendered":"\u7b46\u8a18: \u81ea\u5b9a\u7fa9\u7269\u7406 Physics.ComputePenetration"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">\u5728\u7de8\u5beb\u904a\u6232\u6642\u7d93\u5e38\u9700\u8981\u505a\u4e00\u4e9b\u9055\u8fd4\u7269\u7406\u7684\u4e8b. <br>\u9019\u6642\u5019\u5f88\u5bb9\u6613\u7684\u5c31\u60f3\u7528 tweening \u6216\u8005\u81ea\u5df1\u8a08\u7b97\u7684\u8def\u7d93\u4f86\u8986\u5beb\u7269\u7406\u5f15\u64ce\u7684\u7d50\u679c.\u4f46\u662f\u5728\u5be6\u969b\u904b\u4f5c\u6642\u53c8\u6703\u9677\u5165\u60f3\u4f7f\u7528\u7269\u7406\u5f15\u64ce\u7684\u60c5\u6cc1.<br>\u9019\u6642\u5019\u5c31\u6703\u60f3 : &#8220;\u5982\u679c\u6709\u65b9\u6cd5\u53ef\u4ee5\u5f97\u77e5\u7269\u7406\u5f15\u64ce\u7684\u904b\u7b97\u7d50\u679c\u5c31\u597d\u4e86.&#8221; \u7684\u60f3\u6cd5<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We always want to redefine physics during game development. <br>usually implement it by tweening or custom path to complete ignore the physic engine result.<br>however at some point we still wanted to respect the result from physic engine.<br><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u5728 Unity3D \u88e1\u7684 Physics.ComputePenetration \u5c31\u662f\u4e00\u500b\u5c0d\u9019\u60c5\u6cc1\u4f7f\u7528\u7684\u63a5\u53e3.<br>Ref : <a href=\"https:\/\/docs.unity3d.com\/ScriptReference\/Physics.ComputePenetration.html\">https:\/\/docs.unity3d.com\/ScriptReference\/Physics.ComputePenetration.html<\/a><br>\u5728\u5b98\u65b9\u7684\u6587\u4ef6\u4e2d\u6709\u6a19\u660e\u9019\u662f\u500b\u4f54\u7528\u8cc7\u6e90\u7684 API,<br>\u4e26\u5efa\u8b70\u5118\u91cf\u65bc Physics.Overlap \u5f8c\u4f7f\u7528.<br><br>\u4ee5\u4e0b\u70ba\u6211\u6240\u505a\u7684\u5c0f\u6e2c\u8a66, \u65b9\u4fbf\u660e\u767d\u9019\u500b API \u5728\u505a\u751a\u9ebc.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">in Unity3D, there is an API : Physics.ComputePentration to handle this situation.<br>Ref : <a href=\"https:\/\/docs.unity3d.com\/ScriptReference\/Physics.ComputePenetration.html\">https:\/\/docs.unity3d.com\/ScriptReference\/Physics.ComputePenetration.html<\/a> <br><\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>In official document, there is a warning about this API.<\/p><cite>This function is useful to write custom depenetration functions. One particular example is an implementation of a character controller where a specific reaction to collision with the surrounding physics objects is required. In this case, one would first query for the colliders nearby using OverlapSphere and then adjust the character&#8217;s position using the data returned by ComputePenetration. <br><\/cite><\/blockquote>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"600\" height=\"433\" src=\"http:\/\/www.clonefactor.com\/wordpress\/wp-content\/uploads\/2019\/01\/PhysicsComputePenetration.gif\" alt=\"\" class=\"wp-image-2004\"\/><figcaption>PhysicsComputePenetration test (red arrow represent the final result of all overlap object vector(s))<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">\u53ef\u4ee5\u770b\u898b\u96a8\u8457 Capsule \u7684\u4f4d\u7f6e\u6539\u8b8a, ComputePenetration \u7684\u7d50\u679c\u7e3d\u662f\u6307\u5411\u6c92\u6709\u969c\u7919\u7269\u7684\u7a7a\u9593.<br>\u90a3\u662f\u7269\u7406\u5f15\u64ce\u907f\u514d\u7269\u4ef6\u4e92\u76f8\u4ea4\u758a\u800c\u6307\u51fa\u7684\u5efa\u8b70\u8def\u7d93.<br>\u6e2c\u8a66\u4e2d, \u7531\u65bc\u6bcf\u652f\u5411\u91cf\u662f\u55ae\u7368\u5c0d\u65bc\u8a72 Collider \u7684\u6240\u4ee5\u6700\u5f8c\u7684\u6307\u5411\u53ca\u8ddd\u96e2\u9700\u8981\u81ea\u5df1\u4f86\u7b97.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">As you can see based on the capsule position changed, the result from ComputePenetration are always pointing to the avoid collision direction.<br>that&#8217;s what physic engine will do on your object to avoid those collide overlap each others.<br>however you need to handle each collision vector by yourself, it return <code>direction<\/code> and <code>distance<\/code> and only able to return one object,<br>so for multiple objects you will need to calculate the final direction &amp; distance after combine all of it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Here is the implement of above test script.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">using UnityEngine;\nusing Kit;\n\n[RequireComponent(typeof(CapsuleCollider))]\npublic class PhyTest : MonoBehaviour\n{\n\t[SerializeField] CapsuleCollider m_Self = null;\n\t[SerializeField, Range(0f, 89f)] float m_Angle = 3f;\n\t[SerializeField, Range(0f, 1f)] float m_Length = .3f;\n\t[SerializeField] Color m_DebugColor = Color.yellow;\n\n\t[SerializeField] Color m_Color = new Color(1f, 1f, 1f, 0.3f);\n\t[SerializeField] Color m_HitColor = new Color(1f, 0f, 0f, 0.4f);\n\tprivate Collider[] m_OverlapColliders = new Collider[128];\n\tprivate int HitCount { get; set; } = 0;\n\n\tprivate Vector3 SuggestedDirectionFromEngine(Collider[] objArr, int validRange)\n\t{\n\t\tVector3 finalVector = Vector3.zero;\n\t\tfloat distance = 0f;\n\t\tint total = 0;\n\t\tfor (int i = 0; i &lt; validRange; i++)\n\t\t{\n\t\t\tCollider obstacle = objArr[i];\n\t\t\tif (obstacle == m_Self)\n\t\t\t\tcontinue;\n\t\t\tVector3 pushBackDirection;\n\t\t\tfloat pushBackDistance;\n\t\t\tbool isCollision = Physics.ComputePenetration(m_Self, transform.position, transform.rotation,\n\t\t\t\tobstacle, obstacle.transform.position, obstacle.transform.rotation, out pushBackDirection, out pushBackDistance);\n\t\t\tif (!isCollision)\n\t\t\t\tcontinue;\n\n\t\t\ttotal++;\n\t\t\tdistance += pushBackDistance;\n\t\t\tfinalVector += pushBackDirection;\n\n\t\t\tDebug.DrawRay(transform.position, pushBackDirection * pushBackDistance, Color.magenta, 0f, false);\n\t\t}\n\n\t\treturn finalVector.normalized * (distance \/ (float)total);\n\t}\n\n\tprivate void Reset()\n\t{\n\t\tif (m_Self == null)\n\t\t\tm_Self = GetComponent&lt;CapsuleCollider>();\n\t}\n\n\tprivate void OnDrawGizmos()\n\t{\n\t\tif (KitBox.IsEditorMode)\n\t\t{\n\t\t\tMatrix4x4 matrix = Matrix4x4.TRS(transform.position, transform.rotation, transform.lossyScale);\n\t\t\tfloat half = Mathf.Clamp((m_Self.height \/ 2f) - m_Self.radius, 0f, float.PositiveInfinity);\n\t\t\tVector3 p0 = matrix.MultiplyPoint3x4(m_Self.center + new Vector3(0f, half, 0f));\n\t\t\tVector3 p1 = matrix.MultiplyPoint3x4(m_Self.center + new Vector3(0f, -half, 0f));\n\t\t\tHitCount = Physics.OverlapCapsuleNonAlloc(p0, p1, m_Self.radius, m_OverlapColliders);\n\t\t}\n\t\t\n\t\tVector3 dir = SuggestedDirectionFromEngine(m_OverlapColliders, HitCount);\n\t\tGizmosExtend.DrawRay(transform.position, dir, Color.green);\n\n\t\tGizmosExtend.DrawArrow(transform.position, dir, m_DebugColor, m_Angle, m_Length);\n\t}\n}<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>\u5728\u7de8\u5beb\u904a\u6232\u6642\u7d93\u5e38\u9700\u8981\u505a\u4e00\u4e9b\u9055\u8fd4\u7269\u7406\u7684\u4e8b. \u9019\u6642\u5019\u5f88\u5bb9\u6613\u7684\u5c31\u60f3\u7528 tweening \u6216\u8005\u81ea\u5df1\u8a08\u7b97\u7684\u8def\u7d93 &hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9,78,11],"tags":[79,43],"class_list":["post-2003","post","type-post","status-publish","format-standard","hentry","category-c","category-math","category-unity3d","tag-physical","tag-unity3d-2"],"_links":{"self":[{"href":"https:\/\/www.clonefactor.com\/wordpress\/wp-json\/wp\/v2\/posts\/2003","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.clonefactor.com\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.clonefactor.com\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.clonefactor.com\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.clonefactor.com\/wordpress\/wp-json\/wp\/v2\/comments?post=2003"}],"version-history":[{"count":0,"href":"https:\/\/www.clonefactor.com\/wordpress\/wp-json\/wp\/v2\/posts\/2003\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.clonefactor.com\/wordpress\/wp-json\/wp\/v2\/media?parent=2003"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.clonefactor.com\/wordpress\/wp-json\/wp\/v2\/categories?post=2003"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.clonefactor.com\/wordpress\/wp-json\/wp\/v2\/tags?post=2003"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}