_xiaofang/xiaofang/Assets/Obi/Editor/Common/Blueprints/ObiMeshUtils.cs

93 lines
4.1 KiB
C#
Raw Normal View History

2024-12-18 02:18:45 +08:00
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; }
}
}