Version: 2021.3

Physics.ComputePenetration

切换到手册
public static bool ComputePenetration (Collider colliderA, Vector3 positionA, Quaternion rotationA, Collider colliderB, Vector3 positionB, Quaternion rotationB, out Vector3 direction, out float distance);

参数

colliderA 第一个碰撞体。
positionA 第一个碰撞体的位置。
rotationA 第一个碰撞体的旋转。
colliderB 第二个碰撞体。
positionB 第二个碰撞体的位置。
rotationB 第二个碰撞体的旋转。
direction 将碰撞体分开所需的最小平移所沿的方向。
distance 沿该方向将碰撞体分开所需的距离。

返回

bool 如果碰撞体在给定姿势下重叠,则返回 true。

描述

计算在指定姿势下将给定碰撞体分开所需的最小平移。

如果函数返回 true,则将第一个碰撞体平移方向 * 距离将使两个碰撞体分开。否则,方向和距离未定义。

其中一个碰撞体必须为 BoxCollider、SphereCollider、CapsuleCollider 或凸面 MeshCollider。另一个可以是任何类型。

注意,进行调用时,不受碰撞体位置和旋转的限制。如果传递不同于当前设置的位置或旋转,则不具有物理移动任何碰撞体的效果,因此对场景没有副作用。

不要求先更新任何空间结构,因此也可以在 FixedUpdate 时间范围以外使用。

忽略背面三角形,不遵从 Physics.queriesHitBackfaces

在编写自定义 depenetration 函数时,该函数很有用。一个具体示例是实现需要对与周围物理对象的碰撞作出特定反应的角色控制器。在这种情况下,您可以先使用 OverlapSphere 查询附近的碰撞体,然后使用 ComputePenetration 返回的数据调整角色的位置。

using UnityEngine;

// Visualises the minimum translation vectors required to separate apart from other colliders found in a given radius // Attach to a GameObject that has a Collider attached. [ExecuteInEditMode()] public class ShowPenetration : MonoBehaviour { public float radius = 3f; // show penetration into the colliders located inside a sphere of this radius public int maxNeighbours = 16; // maximum amount of neighbours visualised

private Collider[] neighbours;

public void Start() { neighbours = new Collider[maxNeighbours]; }

public void OnDrawGizmos() { var thisCollider = GetComponent<Collider>();

if (!thisCollider) return; // nothing to do without a Collider attached

int count = Physics.OverlapSphereNonAlloc(transform.position, radius, neighbours);

for (int i = 0; i < count; ++i) { var collider = neighbours[i];

if (collider == thisCollider) continue; // skip ourself

Vector3 otherPosition = collider.gameObject.transform.position; Quaternion otherRotation = collider.gameObject.transform.rotation;

Vector3 direction; float distance;

bool overlapped = Physics.ComputePenetration( thisCollider, transform.position, transform.rotation, collider, otherPosition, otherRotation, out direction, out distance );

// draw a line showing the depenetration direction if overlapped if (overlapped) { Gizmos.color = Color.red; Gizmos.DrawRay(otherPosition, direction * distance); } } } }