using CSNetwork.GPDataType; using System; using UnityEngine; using UnityEngine.UIElements; namespace BrewMonster.Scripts { public class CHalfSpace { public static float DistThresh; //空间一顶点到halfspace平面的距离阈值,作为判断是在半空间内部、外部,or 边界上 //该阈值属于整个类而不是某一个对象,因此定义为静态成员 //根据三个顶点构造平面及半空间区域 //Attributes public const float HS_DEFAULT_DISTTHRESH = 0.000001f; //距离差的阈值,作为判断是在半空间内部or边界上 protected A3DVECTOR3 m_vNormal; protected float m_d; public void Set(A3DVECTOR3 v1, A3DVECTOR3 v2) { m_vNormal = A3DVECTOR3.CrossProduct(v2 - v1, new A3DVECTOR3(0.0f, 0.0f, 1.0f)); m_vNormal.Normalize(); m_d = A3DVECTOR3.DotProduct(v1, m_vNormal); } public void Set(A3DVECTOR3 v1, A3DVECTOR3 v2, A3DVECTOR3 v3) { m_vNormal = A3DVECTOR3.CrossProduct(v2 - v1, v3 - v1); m_vNormal.Normalize(); m_d = A3DVECTOR3.DotProduct(v1, m_vNormal); } //直接设置法向 public void SetNormal(A3DVECTOR3 n) { m_vNormal = n; m_vNormal.Normalize(); } public float GetDist() { return m_d; } //直接设置距离d public void SetD(float d) { m_d = d; } public CHalfSpace(A3DVECTOR3 v1, A3DVECTOR3 v2, A3DVECTOR3 v3) { Set(v1, v2, v3); } //根据两个顶点构造平行于Z轴的平面及半空间区域 public CHalfSpace(A3DVECTOR3 v1, A3DVECTOR3 v2) { Set(v1, v2); } public CHalfSpace() { } public CHalfSpace(CHalfSpace hs) { m_vNormal = hs.m_vNormal; m_d = hs.m_d; } // 对决定Halfspace的平面进行变换!变换矩阵为mtxTrans public virtual void Transform(A3DMATRIX4 mtxTrans) { //从mtxTrans分解出Scale,Rotate,Translate分量 A3DVECTOR3 vTranslate = mtxTrans.GetRow(3); float fScale = mtxTrans.GetCol(0).Magnitude(); // 与mtxTrans一样,仍定义为右乘矩阵 A3DMATRIX3 mtx3Rotate = new A3DMATRIX3(); mtx3Rotate.m = new float[3 * 3]; for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) mtx3Rotate.m[(i * 3) + j] = mtxTrans.m[(i * 4) + j] / fScale; //对于平面方程N.X=D的变换(s,R,t)如下: // N'=NR SetNormal(m_vNormal * mtx3Rotate); //D'=s*D+N'.t SetD(fScale * m_d + A3DVECTOR3.DotProduct(m_vNormal, vTranslate)); } public void Translate(float Delta) { m_d += Delta; } //沿法线方向作一个平移 public void Inverse() { m_d = -m_d; m_vNormal = -m_vNormal; } //翻转半空间的正反方向 //点v到半空间定义平面的距离,此距离带符号! public float DistV2Plane(A3DVECTOR3 v) { float d = A3DVECTOR3.DotProduct(v, m_vNormal); return (d - m_d); } //与线段求交 public int IntersectLineSeg(A3DVECTOR3 v1, A3DVECTOR3 v2, A3DVECTOR3 vIntersection) { vIntersection = new A3DVECTOR3(0.0f, 0.0f, 0.0f); //先处理在平面上的情况 bool v1InPlane = OnPlane(v1); bool v2InPlane = OnPlane(v2); if (v1InPlane && v2InPlane) return 3; if (v1InPlane) return 1; if (v2InPlane) return 2; if (Outside(v1) ^ Outside(v2)) { //两顶点分别在两侧,计算交点 A3DVECTOR3 vd = v2 - v1; float t = m_d - A3DVECTOR3.DotProduct(m_vNormal, v1); t /= A3DVECTOR3.DotProduct(m_vNormal, vd); //assert(t < 1.0f && t > 0.0f); vIntersection = v1 + t * vd; return 4; } else return 0; } //////////////////////////////////////////////////////////// // 判断一个三维点是否处于半空间内部,或者说处于平面的一侧 // 注意halfspace的OutSide,Inside定义方式 // /\ // /||\ // || // || normal (Outside) //------------------------------------------Plane // (Inside) // public bool Inside(A3DVECTOR3 v) { float d = A3DVECTOR3.DotProduct(v, m_vNormal); bool bInside = (m_d - d > DistThresh); return (bInside); } public bool Outside(A3DVECTOR3 v) { float d = A3DVECTOR3.DotProduct(v, m_vNormal); bool bOutside = (d - m_d > DistThresh); return (bOutside); } public bool OnPlane(A3DVECTOR3 v) { float d = A3DVECTOR3.DotProduct(v, m_vNormal); bool bOnPlane = (Math.Abs(m_d - d) <= DistThresh); return bOnPlane; } //set && get operations public static void SetDistThresh(float DThresh = HS_DEFAULT_DISTTHRESH) //并设定一个缺省值 { DistThresh = DThresh; } public A3DVECTOR3 GetNormal() { return m_vNormal; } //点法式 public void SetNV(A3DVECTOR3 n, A3DVECTOR3 v) { m_vNormal = n; m_vNormal.Normalize(); m_d = A3DVECTOR3.DotProduct(m_vNormal, v); } } }