mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-03-28 21:34:54 -05:00
285 lines
9.6 KiB
C#
285 lines
9.6 KiB
C#
using UnityEngine;
|
|
|
|
|
|
namespace SphereTriangle
|
|
{
|
|
/// <summary>
|
|
/// 三角形との交差が 2 => 交点 と 交点
|
|
/// 三角形との交差が 1 => 交点 と 三角形内の線分端点
|
|
/// 三角形との交差が 0 => 線分の端点が両方とも三角形内の場合。端点 と 端点
|
|
/// </summary>
|
|
public struct TriangleSegmentIntersection
|
|
{
|
|
public float t0;
|
|
public float t1;
|
|
public TriangleSegmentIntersection(float _t0, float _t1)
|
|
{
|
|
if (_t0 <= _t1)
|
|
{
|
|
t0 = _t0;
|
|
t1 = _t1;
|
|
}
|
|
else
|
|
{
|
|
t0 = _t1;
|
|
t1 = _t0;
|
|
}
|
|
}
|
|
}
|
|
|
|
public struct Triangle
|
|
{
|
|
public Plane Plane;
|
|
public Vector3[] Points;
|
|
|
|
public Vector3 a => Points[0];
|
|
public Vector3 b => Points[1];
|
|
public Vector3 c => Points[2];
|
|
|
|
public Triangle(Vector3 a, Vector3 b, Vector3 c)
|
|
{
|
|
Plane = new Plane(a, b, c);
|
|
Points = new Vector3[] { a, b, c };
|
|
}
|
|
|
|
/// <summary>
|
|
/// p がすべての辺の同じ側(内積的な意味で)にある => 三角形の内側にある
|
|
/// </summary>
|
|
/// <param name="p"></param>
|
|
/// <returns></returns>
|
|
public bool IsSameSide(Vector3 p)
|
|
{
|
|
var da = Vector3.Dot(Vector3.Cross(p - a, b - a), Plane.normal);
|
|
var db = Vector3.Dot(Vector3.Cross(p - b, c - b), Plane.normal);
|
|
var dc = Vector3.Dot(Vector3.Cross(p - c, a - c), Plane.normal);
|
|
|
|
if (da > 0)
|
|
{
|
|
if (db > 0)
|
|
{
|
|
if (dc > 0)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
else if (da < 0)
|
|
{
|
|
if (db < 0)
|
|
{
|
|
if (dc < 0)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// /// <summary>
|
|
// /// p から lerp の係数を計算
|
|
// /// </summary>
|
|
// /// <param name="p0"></param>
|
|
// /// <param name="p1"></param>
|
|
// /// <param name="p"></param>
|
|
// /// <returns></returns>
|
|
// static float getT(in Vector3 p0, in Vector3 p1, in Vector3 p)
|
|
// {
|
|
// return (p - p0).magnitude / (p1 - p0).magnitude;
|
|
// }
|
|
|
|
// /// <summary>
|
|
// /// 三角形と線分の交差を判定する。
|
|
// /// </summary>
|
|
// /// <param name="p0">線分始点(t=0)。三角形 abc と同一平面を期待</param>
|
|
// /// <param name="p1">線分終点(t=1)。三角形 abc と同一平面を期待</param>
|
|
// /// <returns></returns>
|
|
// public bool TryIntersectSegment(in Vector3 p0, in Vector3 p1, out TriangleSegmentIntersection intersection)
|
|
// {
|
|
// // [ab bc ca]
|
|
// // [ab bc] [bc ca] [ca ab]
|
|
// // [ab] [bc] [ca]
|
|
// // []
|
|
// if (TryIntersectSegments(p0, p1, a, b, out var ab))
|
|
// {
|
|
// if (TryIntersectSegments(p0, p1, b, c, out var bc))
|
|
// {
|
|
// // [ab bc] or [ab bc ca]
|
|
// intersection = new TriangleSegmentIntersection(getT(p0, p1, ab), getT(p0, p1, bc));
|
|
// return true;
|
|
// }
|
|
// else
|
|
// {
|
|
// if (TryIntersectSegments(p0, p1, c, a, out var ca))
|
|
// {
|
|
// // [ab ca]
|
|
// intersection = new TriangleSegmentIntersection(getT(p0, p1, ab), getT(p0, p1, ca));
|
|
// return true;
|
|
// }
|
|
// else
|
|
// {
|
|
// // [ab]
|
|
// if (IsSameSide(p0))
|
|
// {
|
|
// intersection = new TriangleSegmentIntersection(0, getT(p0, p1, ab));
|
|
// return true;
|
|
// }
|
|
// else
|
|
// {
|
|
// intersection = new TriangleSegmentIntersection(getT(p0, p1, ab), 1.0f);
|
|
// return true;
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
// else
|
|
// {
|
|
// if (TryIntersectSegments(p0, p1, b, c, out var bc))
|
|
// {
|
|
// if (TryIntersectSegments(p0, p1, c, a, out var ca))
|
|
// {
|
|
// // [bc ca]
|
|
// intersection = new TriangleSegmentIntersection(getT(p0, p1, bc), getT(p0, p1, ca));
|
|
// return true;
|
|
// }
|
|
// else
|
|
// {
|
|
// // [bc]
|
|
// if (IsSameSide(p0))
|
|
// {
|
|
// intersection = new TriangleSegmentIntersection(0, getT(p0, p1, bc));
|
|
// return true;
|
|
// }
|
|
// else
|
|
// {
|
|
// intersection = new TriangleSegmentIntersection(getT(p0, p1, bc), 1.0f);
|
|
// return true;
|
|
// }
|
|
// }
|
|
// }
|
|
// else
|
|
// {
|
|
// if (TryIntersectSegments(p0, p1, c, a, out var ca))
|
|
// {
|
|
// // [ca]
|
|
// if (IsSameSide(p0))
|
|
// {
|
|
// intersection = new TriangleSegmentIntersection(0, getT(p0, p1, ca));
|
|
// return true;
|
|
// }
|
|
// else
|
|
// {
|
|
// intersection = new TriangleSegmentIntersection(getT(p0, p1, ca), 1.0f);
|
|
// return true;
|
|
// }
|
|
// }
|
|
// else
|
|
// {
|
|
// // []
|
|
// if (IsSameSide(p0) && IsSameSide(p1))
|
|
// {
|
|
// intersection = new TriangleSegmentIntersection(0, 1);
|
|
// return true;
|
|
// }
|
|
// else
|
|
// {
|
|
// intersection = default;
|
|
// return false;
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
// /// <summary>
|
|
// /// 線分と線分の交差を判定する
|
|
// /// a-b d
|
|
// /// /
|
|
// /// c
|
|
// /// https://qiita.com/zu_rin/items/09876d2c7ec12974bc0f
|
|
// /// </summary>
|
|
// /// <param name="a"></param>
|
|
// /// <param name="b"></param>
|
|
// /// <param name="c"></param>
|
|
// /// <param name="d"></param>
|
|
// /// <returns></returns>
|
|
// static bool TryIntersectSegments(in Vector3 a, in Vector3 b, in Vector3 c, in Vector3 d, out Vector3 p)
|
|
// {
|
|
// var deno = Vector3.Cross(b - a, d - c).magnitude;
|
|
// if (deno < 1e-5)
|
|
// {
|
|
// // 線分が平行
|
|
// p = default;
|
|
// return false;
|
|
// }
|
|
|
|
// var s = Vector3.Cross(c - a, d - c).magnitude / deno;
|
|
// var t = Vector3.Cross(b - a, a - c).magnitude / deno;
|
|
// if (s < 0.0 || 1.0 < s || t < 0.0 || 1.0 < t)
|
|
// {
|
|
// // 線分が交差していない
|
|
// p = default;
|
|
// return false;
|
|
// }
|
|
|
|
// p = new Vector3(
|
|
// a.x + s * (b - a).x,
|
|
// a.y + s * (b - a).y,
|
|
// a.z + s * (b - a).z
|
|
// );
|
|
// return true;
|
|
// }
|
|
|
|
// public (Vector3, float) ProjectAB(in Vector3 p)
|
|
// {
|
|
// var ab = (b - a).normalized;
|
|
// var d = Vector3.Dot(ab, (p - a));
|
|
// var x = a + ab * d;
|
|
// return (x, d / (b - a).magnitude);
|
|
// }
|
|
// public (Vector3, float) ProjectBC(in Vector3 p)
|
|
// {
|
|
// var bc = (c - b).normalized;
|
|
// var d = Vector3.Dot(bc, (p - b));
|
|
// var x = b + bc * d;
|
|
// return (x, d / (c - b).magnitude);
|
|
// }
|
|
// public (Vector3, float) ProjectCA(in Vector3 p)
|
|
// {
|
|
// var ca = (a - c).normalized;
|
|
// var d = Vector3.Dot(ca, (p - c));
|
|
// var x = c + ca * d;
|
|
// return (x, d / (a - c).magnitude);
|
|
// }
|
|
|
|
// public TriangleProjection Project(in Vector3 p)
|
|
// {
|
|
// var (ab, ta) = ProjectAB(p);
|
|
// var (bc, tb) = ProjectBC(p);
|
|
// var (ca, tc) = ProjectCA(p);
|
|
// return new TriangleProjection
|
|
// {
|
|
// ab = ab,
|
|
// ta = ta,
|
|
// bc = bc,
|
|
// tb = tb,
|
|
// ca = ca,
|
|
// tc = tc,
|
|
// };
|
|
// }
|
|
|
|
public void DrawGizmos()
|
|
{
|
|
#if UNITY_2022_3_OR_NEWER
|
|
Gizmos.DrawLineStrip(Points, true);
|
|
#else
|
|
for (int i = 0; i < Points.Length - 1; ++i)
|
|
{
|
|
Gizmos.DrawLine(Points[i], Points[i + 1]);
|
|
}
|
|
Gizmos.DrawLine(Points[Points.Length - 1], Points[0]);
|
|
#endif
|
|
}
|
|
}
|
|
} |