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;
}
|
|||
|
}
|
|||
|
|
|||
|
}
|