using UnityEngine; using System.Collections; using System.Collections.Generic; using SXR; namespace Ximmerse.XR.Internal { /// /// Polyengine mathf methods library. /// internal static class Math { /// /// Approximately the specified a and b. /// /// The alpha component. /// The blue component. public static bool Approximately(Vector4 a, Vector4 b) { return Mathf.Approximately(a.x, b.x) && Mathf.Approximately(a.y, b.y) && Mathf.Approximately(a.z, b.z) && Mathf.Approximately(a.w, b.w); } /// /// Approximately the specified a and b. /// /// The alpha component. /// The blue component. public static bool Approximately(Vector3 a, Vector3 b) { return Mathf.Approximately(a.x, b.x) && Mathf.Approximately(a.y, b.y) && Mathf.Approximately(a.z, b.z); } /// /// Approximately the specified a and b. /// /// The alpha component. /// The blue component. public static bool Approximately(Vector2 a, Vector2 b) { return Mathf.Approximately(a.x, b.x) && Mathf.Approximately(a.y, b.y); } /// /// Makes the angle a pretty value between [-180 ... 180] /// /// The angle. /// Angle. public static float PrettyAngle(this float angle) { if (angle >= -180 && angle <= 180) { return angle; } if (angle <= -180) { float mod = Mathf.Repeat(-angle, 360); if (mod >= 180) { return -360 + mod; } else { return -mod; } } else if (angle > 180 && angle <= 360) { return angle - 360; } else { float mod = Mathf.Repeat(angle, 360); if (mod >= 180) { return -360 + mod; } else { return mod; } } } /// /// Makes the euler a pretty value between [-180 ... 180] /// /// The euler. /// Euler. public static Vector3 PrettyAngle(this Vector3 euler) { return new Vector3(PrettyAngle(euler.x), PrettyAngle(euler.y), PrettyAngle(euler.z)); } /// /// Makes the euler a pretty value between [-180 ... 180] /// /// The euler. public static Vector3 PrettyAngle(this Quaternion q) { return q.eulerAngles.PrettyAngle(); } /// /// 把 rotation 的X和Z轴旋转角度设置为0。 /// Flatten 之后的方向只有水平旋转角度。 /// /// Rotation. public static void FlattenXZ(ref Quaternion rotation) { var euler = rotation.eulerAngles; euler.x = 0; euler.z = 0; rotation.eulerAngles = euler; } /// /// 把 rotation 的X和Z轴旋转角度设置为0。 /// Flatten 之后的方向只有水平旋转角度。 /// /// Rotation. public static void FlattenXZ(this Quaternion rotation) { FlattenXZ(ref rotation); } /// /// Get the XZ d of dir1 and dir2 (on XZ surface) /// /// The X. /// Dir1. /// Dir2. public static float DistanceXZ(this Vector3 pos1, Vector3 pos2) { Vector3 newPos2 = new Vector3(pos2.x, pos1.y, pos2.z); return Vector3.Distance(pos1, newPos2); } /// /// Get the XZ DOT of dir1 and dir2 (on XZ surface) /// /// The X. /// Dir1. /// Dir2. public static float DotXZ(this Vector3 dir1, Vector3 dir2) { Vector3 newDir1 = new Vector3(dir1.x, dir2.y, dir1.z); return Vector3.Dot(newDir1, dir2); } /// /// Get the XZ signed angle of dir1 and dir2 (on XZ surface) /// /// The X. /// Dir1. /// Dir2. public static float SignedAngleXZ(this Vector3 dir1, Vector3 dir2) { Vector2 newDir1 = new Vector2(dir1.x, dir1.z); Vector2 newDir2 = new Vector2(dir2.x, dir2.z); return SignedAngle(newDir1, newDir2); } /// /// Steps the input, return a float that is multiple step to stepValue, and not bigger than input. /// For example, input value = 0.7, step = 0.5, return = 0.5. Input vlaue = 1.2. step = 0.5, return = 1 /// /// Value. /// Step. public static float FloorStep(float input, float step) { int stepCount = Mathf.FloorToInt(input / step); return stepCount * step; } /// /// Steps the input, return a float that is multiple step to stepValue, and not smaller than input. /// For example, input value = 0.7, step = 0.5, return = 1. Input value = 1.2, step = 0.5, return = 1.5 /// /// The step. /// Input. /// Step. public static float CeilStep(float input, float step) { int stepCount = Mathf.CeilToInt(input / step); return stepCount * step; } /// /// Get the XZ angle of dir1 and dir2 (on XZ surface) /// /// The X. /// Dir1. /// Dir2. public static float AngleXZ(this Vector3 dir1, Vector3 dir2) { Vector2 newDir1 = new Vector3(dir1.x, dir1.z); Vector2 newDir2 = new Vector3(dir2.x, dir2.z); return Vector2.Angle(newDir1, newDir2); } /// /// Rounds the float. /// /// The float. /// F. /// Digit. public static float RoundSingle(this float f, int digit = 2) { if (digit <= 0) { throw new System.Exception("Digit must GE 0"); } double d = (double)f; d = System.Math.Round(d, digit); float round = (float)d; return round; } /// /// Rounds the vector2. /// /// The float. /// F. /// Digit. public static Vector2 RoundVector2(this Vector2 vector2, int digit = 2) { if (digit <= 0) { throw new System.Exception("Digit must GE 0"); } float roundX = vector2.x.RoundSingle(digit); float roundY = vector2.y.RoundSingle(digit); return new Vector2(roundX, roundY); } /// /// Rounds the vector3. /// /// The float. /// F. /// Digit. public static Vector3 RoundVector3(this Vector3 vector3, int digit = 2) { if (digit <= 0) { throw new System.Exception("Digit must GE 0"); } float roundX = vector3.x.RoundSingle(digit); float roundY = vector3.y.RoundSingle(digit); float roundZ = vector3.z.RoundSingle(digit); return new Vector3(roundX, roundY, roundZ); } /// /// Rounds the vector4. /// /// The float. /// F. /// Digit. public static Vector4 RoundVector4(this Vector4 vector4, int digit = 2) { if (digit <= 0) { throw new System.Exception("Digit must GE 0"); } float roundX = vector4.x.RoundSingle(digit); float roundY = vector4.y.RoundSingle(digit); float roundZ = vector4.z.RoundSingle(digit); float roundW = vector4.w.RoundSingle(digit); return new Vector4(roundX, roundY, roundZ, roundW); } /// /// Gets the signed angle of baseDir and dir2 /// /// The angle. /// Base dir. /// Dir2. public static float SignedAngle(Vector3 baseDir, Vector3 dir2) { var angle = Vector3.Angle(baseDir, dir2); return angle * Mathf.Sign(Vector3.Cross(baseDir, dir2).y); } public static float SignedAngle(Quaternion qBase, Quaternion qDir) { Vector3 v1 = qBase * Vector3.forward; Vector3 v2 = qDir * Vector3.forward; return SignedAngle(v1, v2); } /// /// 返回 dir2 到 baseDir 的带符号角度。 /// 如果在dir2在baseDir右边,返回1. /// 否则返回-1. /// 如果方向相同,返回0 /// /// The angle. /// Base dir. /// Dir2. public static float SignedAngle(Vector2 baseDir, Vector2 dir2) { Vector3 vB = new Vector3(baseDir.x, 0, baseDir.y); Vector3 v2 = new Vector3(dir2.x, 0, dir2.y); var angle = Vector3.Angle(vB, v2); return angle * Mathf.Sign(Vector3.Cross(vB, v2).y); } /// /// 计算两个float 的绝对值距离 /// /// The diff. /// The alpha component. /// The blue component. public static float AbsDiff(float a, float b) { if (a == b || Mathf.Approximately(a, b)) { return 0; } if (Mathf.Sign(a) == Mathf.Sign(b)) { var a1 = Mathf.Abs(a); var a2 = Mathf.Abs(b); return Mathf.Abs(a1 - a2); } else { var bigger = a > b ? a : b; var smaller = a > b ? b : a; return bigger - smaller; } } /// /// Minimum of two vectors /// /// V1. /// V2. public static Vector3 Min(Vector3 v1, Vector3 v2) { Vector3 ret = new Vector3(Mathf.Min(v1.x, v2.x), Mathf.Min(v1.y, v2.y), Mathf.Min(v1.z, v2.z)); return ret; } /// /// 把 vect.x,y,z 的值 Clamp 在 [0..1] /// /// Vect. public static Vector3 Clamp01(Vector3 vect) { return new Vector3(Mathf.Clamp01(vect.x), Mathf.Clamp01(vect.y), Mathf.Clamp01(vect.z)); } /// /// Maximum of two vectors /// /// V1. /// V2. public static Vector3 Max(Vector3 v1, Vector3 v2) { Vector3 ret = new Vector3(Mathf.Max(v1.x, v2.x), Mathf.Max(v1.y, v2.y), Mathf.Max(v1.z, v2.z)); return ret; } /// /// 对 rotation 做Yaw(水平旋转 N个角度) /// /// Rotation. public static Quaternion YawByAngle(this Quaternion rotation, float yaw) { rotation = rotation * Quaternion.Euler(0, yaw, 0); return rotation; } /// /// 对 rotation 做 Pitch (以X为轴旋转 N个角度) /// /// Rotation. public static Quaternion PitchByAngle(this Quaternion rotation, float pitch) { rotation = rotation * Quaternion.Euler(pitch, 0, 0); return rotation; } /// /// Rolls by angle. /// /// The by angle. /// Rotation. /// Roll. public static Quaternion RollByAngle(this Quaternion rotation, float roll) { rotation = rotation * Quaternion.Euler(0, 0, roll); return rotation; } /// /// Clamps the vector2. /// /// The vector2. /// V2. /// Minimum v2. /// Max v2. public static Vector2 ClampVector2(this Vector2 v2, Vector2 minV2, Vector2 maxV2) { v2.x = Mathf.Clamp(v2.x, minV2.x, maxV2.x); v2.y = Mathf.Clamp(v2.y, minV2.y, maxV2.y); return v2; } /// /// 给出原数值 single, 和目标值 target, 速度 speed, 令 single 以speed的速度逼近 target。 /// /// Single. /// Target. /// Speed. public static float Approach(this float single, float target, float speed, float deltaTime) { if (single == target || Mathf.Approximately(single, target)) { return target; } int dir = target > single ? 1 : -1;//1:正向逼近, -1:负向逼近 float velocity = speed * dir * deltaTime; single += velocity; if (single == target || Mathf.Approximately(single, target) || (dir == 1 && single > target)//正向超越 || (dir == -1 && single < target)) //负向超越 { return target; } else { return single; } } /// /// 转换整形数字为小数点后的浮点值: 12345 --> 0.12345 /// /// The fractional float. /// Int. public static float Int2FractionalFloat(this int Int) { if (Int == 0) return 0; var absInt = Mathf.Abs(Int); int seed = 1; float sign = Mathf.Sign(Int); for (int i = 1; seed <= int.MaxValue; i++) { seed *= 10; if (absInt < seed) { float ret = (((float)absInt) / ((float)seed)) * sign; return ret; } } //畸大数: 溢出 return -1; } /// /// Calculate three plane's intersection position. /// /// The plane intersection. /// P1. /// P2. /// P3. public static Vector3 ThreePlaneIntersection(Plane p1, Plane p2, Plane p3) { //get the intersection point of 3 planes return ((-p1.distance * Vector3.Cross(p2.normal, p3.normal)) + (-p2.distance * Vector3.Cross(p3.normal, p1.normal)) + (-p3.distance * Vector3.Cross(p1.normal, p2.normal))) / (Vector3.Dot(p1.normal, Vector3.Cross(p2.normal, p3.normal))); } /// /// Calculate two line segment's intersection point. /// Do not calculate the intersection point, faster than another version. /// /// true, if intersection was lined, false otherwise. /// P1 - Line 1 start point /// P2 - Line 1 end point /// P3 - Line 2 start point /// P4 - Line 2 end point /// Intersection. public static bool LineIntersection(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4) { float Ax, Bx, Cx, Ay, By, Cy, d, e, f/*, num,offset*/; float x1lo, x1hi, y1lo, y1hi; Ax = p2.x - p1.x; Bx = p3.x - p4.x; // X bound box test/ if (Ax < 0) { x1lo = p2.x; x1hi = p1.x; } else { x1hi = p2.x; x1lo = p1.x; } if (Bx > 0) { if (x1hi < p4.x || p3.x < x1lo) return false; } else { if (x1hi < p3.x || p4.x < x1lo) return false; } Ay = p2.y - p1.y; By = p3.y - p4.y; // Y bound box test// if (Ay < 0) { y1lo = p2.y; y1hi = p1.y; } else { y1hi = p2.y; y1lo = p1.y; } if (By > 0) { if (y1hi < p4.y || p3.y < y1lo) return false; } else { if (y1hi < p3.y || p4.y < y1lo) return false; } Cx = p1.x - p3.x; Cy = p1.y - p3.y; d = By * Cx - Bx * Cy; // alpha numerator// f = Ay * Bx - Ax * By; // both denominator// // alpha tests// if (f > 0) { if (d < 0 || d > f) return false; } else { if (d > 0 || d < f) return false; } e = Ax * Cy - Ay * Cx; // beta numerator// // beta tests // if (f > 0) { if (e < 0 || e > f) return false; } else { if (e > 0 || e < f) return false; } // check if they are parallel if (f == 0) return false; return true; } /// /// Calculate two line segment's intersection point. /// /// true, if intersection was lined, false otherwise. /// P1 - Line 1 start point /// P2 - Line 1 end point /// P3 - Line 2 start point /// P4 - Line 2 end point /// Intersection. public static bool LineIntersection(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, ref Vector2 intersection) { float Ax, Bx, Cx, Ay, By, Cy, d, e, f, num/*,offset*/; float x1lo, x1hi, y1lo, y1hi; Ax = p2.x - p1.x; Bx = p3.x - p4.x; // X bound box test/ if (Ax < 0) { x1lo = p2.x; x1hi = p1.x; } else { x1hi = p2.x; x1lo = p1.x; } if (Bx > 0) { if (x1hi < p4.x || p3.x < x1lo) return false; } else { if (x1hi < p3.x || p4.x < x1lo) return false; } Ay = p2.y - p1.y; By = p3.y - p4.y; // Y bound box test// if (Ay < 0) { y1lo = p2.y; y1hi = p1.y; } else { y1hi = p2.y; y1lo = p1.y; } if (By > 0) { if (y1hi < p4.y || p3.y < y1lo) return false; } else { if (y1hi < p3.y || p4.y < y1lo) return false; } Cx = p1.x - p3.x; Cy = p1.y - p3.y; d = By * Cx - Bx * Cy; // alpha numerator// f = Ay * Bx - Ax * By; // both denominator// // alpha tests// if (f > 0) { if (d < 0 || d > f) return false; } else { if (d > 0 || d < f) return false; } e = Ax * Cy - Ay * Cx; // beta numerator// // beta tests // if (f > 0) { if (e < 0 || e > f) return false; } else { if (e > 0 || e < f) return false; } // check if they are parallel if (f == 0) return false; // compute intersection coordinates // num = d * Ax; // numerator // // offset = same_sign(num,f) ? f*0.5f : -f*0.5f; // round direction // // intersection.x = p1.x + (num+offset) / f; intersection.x = p1.x + num / f; num = d * Ay; // offset = same_sign(num,f) ? f*0.5f : -f*0.5f; // intersection.y = p1.y + (num+offset) / f; intersection.y = p1.y + num / f; return true; } /// /// Remove roll from euler angle. /// /// The roll. /// Quaternion. public static Quaternion PitchNYaw(this Quaternion quaternion) { Vector3 euler = quaternion.eulerAngles; return Quaternion.Euler(euler.x, euler.y, 0); } /// /// Remove yaw and roll from euler angle. /// /// The roll. /// Quaternion. public static Quaternion Pitch(this Quaternion quaternion) { Vector3 euler = quaternion.eulerAngles; return Quaternion.Euler(euler.x, 0, 0); } /// /// Remove pitch and roll from euler angle. /// /// The roll. /// Quaternion. public static Quaternion Yaw(this Quaternion quaternion) { Vector3 euler = quaternion.eulerAngles; return Quaternion.Euler(0, PrettyAngle(euler.y), 0); } /// /// Remove pitch and yaw from euler angle. /// /// The roll. /// Quaternion. public static Quaternion Roll(this Quaternion quaternion) { Vector3 euler = quaternion.eulerAngles; return Quaternion.Euler(0, 0, euler.z); } /// /// Calculate quaternion diff = lhs - rhs /// /// The iff. /// Lhs. /// Rhs. public static Quaternion QDiff(this Quaternion lhs, Quaternion rhs) { return Quaternion.Inverse(rhs) * lhs; } /// /// Calculate quaternion sum : lhs + rhs[0] + rhs[1] + rhs[2] ... /// /// The plus. /// Lhs. /// Rhs. public static Quaternion QSum(this Quaternion lhs, params Quaternion[] rhs) { Quaternion qSum = lhs; for (int i = 0; i < rhs.Length; i++) { qSum = qSum * rhs[i]; } return qSum; } /// /// yaw angle diff : lhs.yaw - rhs.yaw /// /// The diff. /// lhs. /// rhs. public static float YawDiff(this Quaternion lhs, Quaternion rhs) { Quaternion yawlhs = lhs.Yaw(); Quaternion yawrhs = rhs.Yaw(); var qdiff = yawlhs.QDiff(yawrhs); return PrettyAngle(qdiff.eulerAngles.y); } /// /// 输出内部归一化参数配置的双目 View Frustum /// /// /// /// /// /// /// /// /// internal static void GetViewFrustum(out float near, out float far, out float left, out float right, out float top, out float bottom, out float hFov, out float vFov) { near = ParamLoader.ParamLoaderGetFloat((int)ParamType.Render_Frustum_Near_FLOAT); far = ParamLoader.ParamLoaderGetFloat((int)ParamType.Render_Frustum_Far_FLOAT); left = ParamLoader.ParamLoaderGetFloat((int)ParamType.Render_Frustum_Left_FLOAT); right = ParamLoader.ParamLoaderGetFloat((int)ParamType.Render_Frustum_Right_FLOAT); top = ParamLoader.ParamLoaderGetFloat((int)ParamType.Render_Frustum_Top_FLOAT); bottom = ParamLoader.ParamLoaderGetFloat((int)ParamType.Render_Frustum_Bottom_FLOAT); hFov = ParamLoader.ParamLoaderGetFloat((int)ParamType.Render_EyeBufferFovX_FLOAT); vFov = ParamLoader.ParamLoaderGetFloat((int)ParamType.Render_EyeBufferFovY_FLOAT); } /// /// Gets view frustum from ParamLoader /// /// internal static Matrix4x4 GetViewFrustum() { GetViewFrustum(out float near, out float far, out float left, out float right, out float top, out float bottom, out float hFov, out float vFov); return Perspective(left, right, bottom, top, near, far); } static internal Matrix4x4 Perspective(float left, float right, float bottom, float top, float near, float far) { float x = 2.0F * near / (right - left); float y = 2.0F * near / (top - bottom); float a = (right + left) / (right - left); float b = (top + bottom) / (top - bottom); float c = -(far + near) / (far - near); float d = -(2.0F * far * near) / (far - near); float e = -1.0F; Matrix4x4 m = new Matrix4x4(); m[0, 0] = x; m[0, 1] = 0; m[0, 2] = a; m[0, 3] = 0; m[1, 0] = 0; m[1, 1] = y; m[1, 2] = b; m[1, 3] = 0; m[2, 0] = 0; m[2, 1] = 0; m[2, 2] = c; m[2, 3] = d; m[3, 0] = 0; m[3, 1] = 0; m[3, 2] = e; m[3, 3] = 0; return m; } } }