1
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.

UnityでRayとMeshの交点の取得を実装する ~裏面でも取得して欲しい~

Last updated at Posted at 2023-05-01

「Moller-Trumbore」アルゴリズムです

コード説明

Unityでメッシュの内部からのRayで、交点を取得する必要があったので自前で実装しました。上の方の関数がメッシュフィルターとの判定で、下が一つの三角形との判定です。引数seeFront,seeBackを変更することで、用途に応じて使い分けられます。

参考文献

これらを読んだらコードの中身が理解できます。複雑な計算の実装に関しては(あー大学の授業でやったわこんなん)みたいな感じで、参考文献のものをコピペしました。これを読んでるあなたも、私のコードをコピペするか、wikiのをコピペするといいと思います。
https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm
https://shikousakugo.wordpress.com/2012/05/29/ray-intersection/
https://shikousakugo.wordpress.com/2012/06/27/ray-intersection-2/
https://shikousakugo.wordpress.com/2012/07/01/ray-intersection-3/

コード

using UnityEngine;

//https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm
//https://shikousakugo.wordpress.com/2012/05/29/ray-intersection/
//https://shikousakugo.wordpress.com/2012/06/27/ray-intersection-2/
//https://shikousakugo.wordpress.com/2012/07/01/ray-intersection-3/
public static class MollerTrumboreRayChack
{
    public static bool GetRayIntersectMesh(Vector3 rayOrigin, Vector3 rayVector,MeshFilter mf, out Vector3 Intersect, bool seeFront = true, bool seeBack = true)
    { 
        Intersect = Vector3.zero;
        Mesh mesh = mf.mesh;
        int[] triangles = mesh.triangles;
        Vector3[] vertices=mesh.vertices;

        Vector3[] verticesWorldPos=new Vector3[vertices.Length];
        Matrix4x4 localToWorld = mf.transform.localToWorldMatrix;
        for(int i = 0; i < vertices.Length; i++)
        {
            verticesWorldPos[i]= localToWorld.MultiplyPoint3x4(vertices[i]);
        }
        for (int i = 0; i < triangles.Length; i+=3)
        {
            if (RayIntersectsTriangle(rayOrigin, rayVector, verticesWorldPos[triangles[i]], verticesWorldPos[triangles[i+1]], verticesWorldPos[triangles[i+2]], out Vector3 thisout,seeFront,seeBack))
            {
                Intersect=thisout;
                return true;
            }
        }
        return false;
    }
    public static bool RayIntersectsTriangle(Vector3 rayOrigin,Vector3 rayVector,Vector3 vertex0, Vector3 vertex1, Vector3 vertex2, out Vector3 outIntersectionPoint,bool seeFront=true ,bool seeBack=true)
    {
        outIntersectionPoint = new Vector3();

        const float EPSILON = 0.000001f;
        Vector3 edge1, edge2, h, s, q;
        float a, f, u, v;
        edge1 = vertex1 - vertex0;
        edge2 = vertex2 - vertex0;
        h = Vector3.Cross(rayVector,edge2);
        a = Vector3.Dot(edge1,h);
        if (-EPSILON < a && a < EPSILON) return false;//aがに近いとき、平行なので偽
        if (a < -EPSILON && !seeBack) return false;//aが0以下の時、判定する面はRayに対して裏面を向いているので、裏面を判定しないならば偽
        if (EPSILON < a && !seeFront) return false;//aが0以上の時、判定する面はRayに対して表面を向いているので、表面を判定しないならば偽
        f = 1.0f / a;
        s = rayOrigin - vertex0;
        u = f * Vector3.Dot(s,h);

        if (u < 0.0f || u > 1.0f) return false;

        q = Vector3.Cross(s,edge1);
        v = f * Vector3.Dot(rayVector,q);

        if (v < 0.0f || u + v > 1.0f)
            return false;

        // At this stage we can compute t to find out where the intersection point is on the line.
        float t = f * Vector3.Dot(edge2,q);

        if (t > EPSILON) // ray intersection
        {
            outIntersectionPoint = rayOrigin + rayVector * t;
            return true;
        }
        else // This means that there is a line intersection but not a ray intersection.
            return false;
    }
}

1
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
1
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?