93 lines
4.1 KiB
C#
93 lines
4.1 KiB
C#
using UnityEngine;
|
||
using System.Collections;
|
||
|
||
namespace Obi
|
||
{
|
||
public static class ObiMeshUtils
|
||
{
|
||
// Temporary vector3 values
|
||
static Vector3 tv1, tv2, tv3, tv4;
|
||
|
||
public static bool RayIntersectsTriangle(Vector3 origin,
|
||
Vector3 dir,
|
||
Vector3 vert0,
|
||
Vector3 vert1,
|
||
Vector3 vert2,
|
||
ref float distance,
|
||
ref Vector3 normal)
|
||
{
|
||
float det;
|
||
|
||
ObiVectorMath.Subtract(vert0, vert1, ref tv1);
|
||
ObiVectorMath.Subtract(vert0, vert2, ref tv2);
|
||
|
||
ObiVectorMath.Cross(dir, tv2, ref tv4);
|
||
det = Vector3.Dot(tv1, tv4);
|
||
|
||
if (det < Mathf.Epsilon)
|
||
return false;
|
||
|
||
ObiVectorMath.Subtract(vert0, origin, ref tv3);
|
||
|
||
float u = Vector3.Dot(tv3, tv4);
|
||
|
||
if (u < 0f || u > det)
|
||
return false;
|
||
|
||
ObiVectorMath.Cross(tv3, tv1, ref tv4);
|
||
|
||
float v = Vector3.Dot(dir, tv4);
|
||
|
||
if (v < 0f || u + v > det)
|
||
return false;
|
||
|
||
distance = Vector3.Dot(tv2, tv4) * (1f / det);
|
||
ObiVectorMath.Cross(tv1, tv2, ref normal);
|
||
|
||
return true;
|
||
}
|
||
/**
* Find the nearest triangle intersected by InWorldRay on this mesh. InWorldRay is in world space.
* @hit contains information about the hit point. @distance limits how far from @InWorldRay.origin the hit
* point may be. @cullingMode determines what face orientations are tested (Culling.Front only tests front
* faces, Culling.Back only tests back faces, and Culling.FrontBack tests both).
* Ray origin and position values are in local space.
*/
public static bool WorldRaycast(Ray InWorldRay, Matrix4x4 transform, Vector3[] vertices, int[] triangles, out ObiRaycastHit hit, float distance = Mathf.Infinity)
{
|
||
Ray ray = InWorldRay;
|
||
if (transform != null)
|
||
{
|
||
Matrix4x4 inv = transform.inverse;
|
||
ray.origin = inv.MultiplyPoint3x4(ray.origin);
|
||
ray.direction = inv.MultiplyVector(ray.direction);
|
||
}
return MeshRaycast(ray, vertices, triangles, out hit, distance);
}
/**
* Cast a ray (in model space) against a mesh.
*/
public static bool MeshRaycast(Ray InRay, Vector3[] vertices, int[] triangles, out ObiRaycastHit hit, float distance = Mathf.Infinity)
{
|
||
Vector3 hitNormal = Vector3.zero; // vars used in loop
|
||
Vector3 vert0, vert1, vert2;
|
||
Vector3 origin = InRay.origin, direction = InRay.direction;
|
||
|
||
hit = new ObiRaycastHit(Mathf.Infinity,
|
||
Vector3.zero,
|
||
Vector3.zero,
|
||
-1);
|
||
/**
|
||
* Iterate faces, testing for nearest hit to ray origin.
|
||
*/
|
||
for (int CurTri = 0; CurTri < triangles.Length; CurTri += 3)
|
||
{
|
||
if (CurTri + 2 >= triangles.Length) continue;
|
||
if (triangles[CurTri + 2] >= vertices.Length) continue;
|
||
|
||
vert0 = vertices[triangles[CurTri + 0]];
|
||
vert1 = vertices[triangles[CurTri + 1]];
|
||
vert2 = vertices[triangles[CurTri + 2]];
|
||
|
||
// Second pass, test intersection with triangle
|
||
if (RayIntersectsTriangle(origin, direction, vert0, vert1, vert2, ref distance, ref hitNormal))
|
||
{
|
||
if (distance < hit.distance)
|
||
{
|
||
hit.distance = distance;
|
||
hit.triangle = CurTri / 3;
|
||
hit.position = InRay.GetPoint(hit.distance);
|
||
hit.normal = hitNormal;
|
||
}
|
||
}
|
||
}
|
||
|
||
return hit.triangle > -1;
}
|
||
}
|
||
|
||
} |