C#
Unity
当たり判定

Unity C# で線分と三角形ポリゴンの当たり判定を実装する。

b.gif

線分と三角形ポリゴンの当たり判定を行うことになりました。

Unityのレイキャストとコライダを使えばできるのですが、単純な処理なので、自前で実装することにしたほうが早くできる?と思い自前で実装しました。

smというインスタンスがありますが、これは独自で作ったクラスのインスタンスです。
sm.GetVtxFromMesh();ではポリゴンを構成している3頂点を取得しているだけです。
sm.meshは、UnityのMeshクラスです。

コードについて

GIF動画のように、カメラからレイキャストしたレイを成分として、用意されたメッシュと当たり判定を起こすと、Gizmos.DrawSphereが描画されます。三角形の各頂点にある球体は、添付のソースコードには関係ありません。

下のコードを直接空のゲームオブジェクトにアタッチしても使うことはできません。どれぐらいのコード量で当たり判定が実装できるかなどの目安や、参考にしてくれると嬉しいです。

private void OnDrawGizmos()
    {
        if (!Application.isPlaying)
            return; // プレイモードが終了したとき、ヌルリファレンスを出さないようにする。

        // 自前の当たり判定
        Ray mouseRay = Camera.main.ScreenPointToRay(Input.mousePosition);
        Vector3 pos1 = Camera.main.transform.position;
        Vector3 pos2 = pos1 + mouseRay.direction * 5;

        Gizmos.DrawLine(pos1, pos2);
        Vector3[] v = sm.GetVtxFromMesh();

        Vector3 v1 = pos1 - v[0];
        Vector3 v2 = pos2 - v[0];

        Vector3 n = sm.mesh.normals[0];
        Vector3 c = (v[0] + v[1] + v[2]) / 3;

        Gizmos.DrawRay(c, n);

        if (Vector3.Dot(v1, n) * Vector3.Dot(v2, n) <= 0)
        {
            // print("hit");

            // d = |Dot(vn,v1)| / |vn|
            // 法線ベクトルは常に1なので、ここでは、割らない。
            float d1 = Mathf.Abs(Vector3.Dot(n, v1));
            float d2 = Mathf.Abs(Vector3.Dot(n, v2));

            // a : 1-a = d1 : d2
            // a = d1 / (d1 + d2)
            // v3 = (1-a)*v1 + a*v2
            float a = d1 / (d1 + d2);
            Vector3 v3 = (1 - a) * v1 + a * v2;

            Vector3 AB = v[1] - v[0];
            Vector3 BC = v[2] - v[1];
            Vector3 CA = v[0] - v[2];

            Vector3 AP = v3 - v[0];
            Vector3 BP = v3 - v[1];
            Vector3 CP = v3 - v[2];

            Vector3 c1 = Vector3.Cross(AB, BP);
            Vector3 c2 = Vector3.Cross(BC, CP);
            Vector3 c3 = Vector3.Cross(CA, AP);

            float dot_12 = Vector3.Dot(c1, c2);
            float dot_13 = Vector3.Dot(c1, c3);

            if (dot_12 > 0 && dot_13 > 0)
            {
                //三角形の内側に点がある
                Gizmos.DrawSphere(v3, 0.1f);
            }
        }
    }

参考ページ

http://marupeke296.com/COL_3D_No4_LineToPlanePolygon.html
http://marupeke296.com/COL_3D_No3_LineToPlane.html
http://www.sousakuba.com/Programming/gs_hittest_point_triangle.html