2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

任意形状のColliderとSphereColliderの接触判定を行う [Unity]

Posted at

はじめに

IKを使って歩行アニメーションを行う場合などに、任意形状の地面との距離や接している場所の法線を取得したいことがあります。
そんなときに使える、任意形状のColliderSphereColliderの接触判定を行い、接している場合はSphereColliderから見て任意形状のCollider上の1番近い位置とその位置の法線ベクトルなどを返す静的メソッドを紹介します。

実装

PhysicsUtil.cs
using UnityEngine;

public static class PhysicsUtil
{
    /// <summary>
    /// sphereColliderがtargetColliderに接しているか調べ、接している場合はclosestPosとsurfaceNormalを計算する
    /// </summary>
    /// <param name="targetCollider">sphereColliderが接しているかを調べる任意のコライダー</param>
    /// <param name="sphereCollider">targetColliderに接しているかを調べる球体コライダー</param>
    /// <param name="closestPos">
    /// targetCollider表面上の、sphereColliderの中心に最も近い点。
    /// 接触していない場合はゼロベクトルを返す
    /// </param>
    /// <param name="surfaceNormal">
    /// 接触しているtargetCollider表面の法線ベクトル。
    /// 接触していない場合はゼロベクトルを返す
    /// </param>
    /// <param name="surfacePenetrationDepth">
    /// sphereColliderをtargetColliderから引き離すのに必要なsurfaceNormalに沿った距離(どれだけtargetColliderがめり込んでいるか)。
    /// 接触していない場合は0を返す
    /// </param>
    /// <param name="scale">sphereColliderで考慮するスケール</param>
    /// <returns>sphereColliderがtargetColliderに接しているか</returns>
    public static bool ComputeClosestPosition(Collider targetCollider, SphereCollider sphereCollider,
        out Vector3 closestPos, out Vector3 surfaceNormal, out float surfacePenetrationDepth,
        float scale = 1f)
    {
        closestPos = Vector3.zero;
        surfaceNormal = Vector3.zero;
        surfacePenetrationDepth = 0f;

        if (targetCollider == sphereCollider) return false;

        Transform targetTrans = targetCollider.transform;
        Transform sphereTrans = sphereCollider.transform;
        Vector3 spherePos = sphereTrans.position;


        bool isOverlap = Physics.ComputePenetration(targetCollider, targetTrans.position, targetTrans.rotation,
            sphereCollider, spherePos, Quaternion.identity, out surfaceNormal, out surfacePenetrationDepth);

        if (isOverlap)
        {
            closestPos = spherePos + surfaceNormal * (sphereCollider.radius * scale - surfacePenetrationDepth);
            surfaceNormal = -surfaceNormal;
        }

        return isOverlap;
    }

    public static bool ComputeClosestPosition(Collider targetCollider, SphereCollider sphereCollider,
        out Vector3 closestPos, out Vector3 surfaceNormal)
    {
        return ComputeClosestPosition(targetCollider, sphereCollider, out closestPos, out surfaceNormal, out _);
    }

    /// <summary>
    /// LayerMaskに指定のLayerが含まれているかを調べる
    /// </summary>
    /// <param name="layerMask"></param>
    /// <param name="layer"></param>
    /// <returns></returns>
    public static bool Contains(this LayerMask layerMask, int layer)
    {
        return layerMask == (layerMask | (1 << layer));
    }
}
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?