using System.Collections; using System.Collections.Generic; using UnityEngine; using System; using System.Linq; using UnityEngine.Serialization; [AddComponentMenu("Miscellaneous/Bezier Spline")] public class Bezier3DSpline : MonoBehaviour{ public int KnotCount { get { return curves.Length+(closed?0:1); } } public int CurveCount { get { return curves.Length; } } /// <summary> Interpolation steps per curve </summary> public int cacheDensity { get { return _cacheDensity; } } [SerializeField] protected int _cacheDensity = 60; /// <summary> Whether the end of the spline connects to the start of the spline </summary> public bool closed { get { return _closed; } } [SerializeField] protected bool _closed = false; /// <summary> Sum of all curve lengths </summary> public float totalLength { get { return _totalLength; } } [SerializeField] protected float _totalLength = 2.370671f; /// <summary> Curves of the spline </summary> [SerializeField] protected Bezier3DCurve[] curves = new Bezier3DCurve[] { new Bezier3DCurve( new Vector3(-1,0,0), new Vector3(1,0,1), new Vector3(-1,0,-1), new Vector3(1,0,0), 60)}; /// <summary> Automatic knots don't have handles. Instead they have a percentage and adjust their handles accordingly. A percentage of 0 indicates that this is not automatic </summary> [SerializeField] protected List<float> autoKnot = new List<float>() { 0, 0 }; [SerializeField] protected List<NullableQuaternion> orientations = new List<NullableQuaternion>() { new NullableQuaternion(null), new NullableQuaternion(null) }; [SerializeField] protected Vector3[] tangentCache = new Vector3[0]; #region Public methods #region Public: get public float DistanceToTime(float dist) { float t = 0f; for (int i = 0; i < CurveCount; i++) { if (curves[i].length < dist) { dist -= curves[i].length; t += 1f / CurveCount; } else { t += curves[i].Dist2Time(dist) / CurveCount; return t; } } return 1f; } /// <summary> Get <see cref="Bezier3DCurve"/> by index </summary> public Bezier3DCurve GetCurve(int i) { if (i >= CurveCount || i < 0) throw new System.IndexOutOfRangeException("Cuve index " + i + " out of range"); return curves[i]; } /// <summary> Return <see cref="Knot"/> info in local coordinates </summary> public Knot GetKnot(int i) { if (i == 0) { if (closed) return new Knot(curves[0].a, curves[CurveCount - 1].c, curves[0].b, autoKnot[i], orientations[i].NullableValue); else return new Knot(curves[0].a, Vector3.zero, curves[0].b, autoKnot[i], orientations[i].NullableValue); } else if (i == CurveCount) { return new Knot(curves[i - 1].d, curves[i - 1].c, Vector3.zero, autoKnot[i], orientations[i].NullableValue); } else { return new Knot(curves[i].a, curves[i - 1].c, curves[i].b, autoKnot[i], orientations[i].NullableValue); } } #region Public get: Forward /// <summary> Return forward vector at set distance along the <see cref="Bezier3DSpline"/>. </summary> public Vector3 GetForward(float dist) { return transform.TransformDirection(GetForwardLocal(dist)); } /// <summary> Return forward vector at set distance along the <see cref="Bezier3DSpline"/> in local coordinates. </summary> public Vector3 GetForwardLocal(float dist) { Bezier3DCurve curve = GetCurveDistance(dist, out dist); return curve.GetForward(curve.Dist2Time(dist)); } /// <summary> Return forward vector at set distance along the <see cref="Bezier3DSpline"/>. Uses approximation. </summary> public Vector3 GetForwardFast(float dist) { return transform.TransformDirection(GetForwardLocalFast(dist)); } /// <summary> Return forward vector at set distance along the <see cref="Bezier3DSpline"/> in local coordinates. Uses approximation. </summary> public Vector3 GetForwardLocalFast(float dist) { Bezier3DCurve curve = GetCurveDistance(dist, out dist); return curve.GetForwardFast(curve.Dist2Time(dist)); } #endregion #region Public get: Up /// <summary> Return up vector at set distance along the <see cref="Bezier3DSpline"/>. </summary> public Vector3 GetUp(float dist) { return GetUp(dist, GetForward(dist), false); } /// <summary> Return up vector at set distance along the <see cref="Bezier3DSpline"/> in local coordinates. </summary> public Vector3 GetUpLocal(float dist) { return GetUp(dist, GetForward(dist), true); } #endregion #region Public get: Point /// <summary> Return up vector at set distance along the <see cref="Bezier3DSpline"/>. </summary> public Vector3 GetPoint(float dist) { Bezier3DCurve curve = GetCurveDistance(dist, out dist); return transform.TransformPoint(curve.GetPoint(curve.Dist2Time(dist))); } /// <summary> Return point at lerped position where 0 = start, 1 = end </summary> public Vector3 GetPointLocal(float dist) { Bezier3DCurve curve = GetCurveDistance(dist, out dist); return curve.GetPoint(curve.Dist2Time(dist)); } #endregion #region Public get: Orientation public Quaternion GetOrientation(float dist) { Vector3 forward = GetForward(dist); Vector3 up = GetUp(dist, forward, false); if (forward.sqrMagnitude != 0) return Quaternion.LookRotation(forward, up); else return Quaternion.identity; } public Quaternion GetOrientationFast(float dist) { Vector3 forward = GetForwardFast(dist); Vector3 up = GetUp(dist, forward, false); if (forward.sqrMagnitude != 0) return Quaternion.LookRotation(forward, up); else return Quaternion.identity; } public Quaternion GetOrientationLocal(float dist) { Vector3 forward = GetForwardLocal(dist); Vector3 up = GetUp(dist, forward, true); if (forward.sqrMagnitude != 0) return Quaternion.LookRotation(forward, up); else return Quaternion.identity; } public Quaternion GetOrientationLocalFast(float dist) { Vector3 forward = GetForwardLocalFast(dist); Vector3 up = GetUp(dist, forward, true); if (forward.sqrMagnitude != 0) return Quaternion.LookRotation(forward, up); else return Quaternion.identity; } #endregion #endregion #region Public: Set /// <summary> Setting spline to closed will generate an extra curve, connecting end point to start point </summary> public void SetClosed(bool closed) { if (closed != _closed) { _closed = closed; if (closed) { List<Bezier3DCurve> curveList = new List<Bezier3DCurve>(curves); curveList.Add(new Bezier3DCurve(curves[CurveCount - 1].d, -curves[CurveCount - 1].c, -curves[0].b, curves[0].a, cacheDensity)); curves = curveList.ToArray(); } else { List<Bezier3DCurve> curveList = new List<Bezier3DCurve>(curves); curveList.RemoveAt(CurveCount - 1); curves = curveList.ToArray(); } _totalLength = GetTotalLength(); } } /// <summary> Recache all individual curves with new step amount </summary> /// <param name="density"> Number of steps per curve </param> public void SetCacheDensity(int steps) { _cacheDensity = steps; for (int i = 0; i < CurveCount; i++) { curves[i] = new Bezier3DCurve(curves[i].a, curves[i].b, curves[i].c, curves[i].d, _cacheDensity); } _totalLength = GetTotalLength(); } public void RemoveKnot(int i) { if (i == 0) { Knot knot = GetKnot(1); List<Bezier3DCurve> curveList = new List<Bezier3DCurve>(curves); curveList.RemoveAt(0); curves = curveList.ToArray(); autoKnot.RemoveAt(0); orientations.RemoveAt(0); SetKnot(0, knot); } else if (i == CurveCount) { List<Bezier3DCurve> curveList = new List<Bezier3DCurve>(curves); curveList.RemoveAt(i - 1); curves = curveList.ToArray(); autoKnot.RemoveAt(i); orientations.RemoveAt(i); if (autoKnot[KnotCount - 1] != 0) SetKnot(KnotCount - 1, GetKnot(KnotCount - 1)); } else { int preCurveIndex, postCurveIndex; GetCurveIndicesForKnot(i, out preCurveIndex, out postCurveIndex); Bezier3DCurve curve = new Bezier3DCurve(curves[preCurveIndex].a, curves[preCurveIndex].b, curves[postCurveIndex].c, curves[postCurveIndex].d, cacheDensity); curves[preCurveIndex] = curve; List<Bezier3DCurve> curveList = new List<Bezier3DCurve>(curves); curveList.RemoveAt(postCurveIndex); curves = curveList.ToArray(); autoKnot.RemoveAt(i); orientations.RemoveAt(i); int preKnotIndex, postKnotIndex; GetKnotIndicesForKnot(i, out preKnotIndex, out postKnotIndex); SetKnot(preKnotIndex, GetKnot(preKnotIndex)); } } public void AddKnot(Knot knot) { Bezier3DCurve curve = new Bezier3DCurve(curves[CurveCount - 1].d, -curves[CurveCount - 1].c, knot.handleIn, knot.position, cacheDensity); List<Bezier3DCurve> curveList = new List<Bezier3DCurve>(curves); curveList.Add(curve); curves = curveList.ToArray(); autoKnot.Add(knot.auto); orientations.Add(knot.orientation); SetKnot(KnotCount - 1, knot); } public void InsertKnot(int i, Knot knot) { Bezier3DCurve curve; if (i == 0) curve = new Bezier3DCurve(knot.position, knot.handleOut, -curves[0].b, curves[0].a, cacheDensity); else if (i == CurveCount) curve = GetCurve(i - 1); else curve = GetCurve(i); List<Bezier3DCurve> curveList = new List<Bezier3DCurve>(curves); curveList.Insert(i, curve); curves = curveList.ToArray(); autoKnot.Insert(i, knot.auto); orientations.Insert(i, knot.orientation); SetKnot(i, knot); } /// <summary> Set Knot info in local coordinates </summary> public void SetKnot(int i, Knot knot) { //If knot is set to auto, adjust handles accordingly orientations[i] = knot.orientation; autoKnot[i] = knot.auto; if (knot.auto != 0) AutomateHandles(i, ref knot); //Automate knots around this knot int preKnotIndex, postKnotIndex; GetKnotIndicesForKnot(i, out preKnotIndex, out postKnotIndex); Knot preKnot = new Knot(); if (preKnotIndex != -1) { preKnot = GetKnot(preKnotIndex); if (preKnot.auto != 0) { int preKnotPreCurveIndex, preKnotPostCurveIndex; GetCurveIndicesForKnot(preKnotIndex, out preKnotPreCurveIndex, out preKnotPostCurveIndex); if (preKnotPreCurveIndex != -1) { AutomateHandles(preKnotIndex, ref preKnot, curves[preKnotPreCurveIndex].a, knot.position); curves[preKnotPreCurveIndex] = new Bezier3DCurve(curves[preKnotPreCurveIndex].a, curves[preKnotPreCurveIndex].b, preKnot.handleIn, preKnot.position, cacheDensity); } else { AutomateHandles(preKnotIndex, ref preKnot, Vector3.zero, knot.position); } } } Knot postKnot = new Knot(); if (postKnotIndex != -1) { postKnot = GetKnot(postKnotIndex); if (postKnot.auto != 0) { int postKnotPreCurveIndex, postKnotPostCurveIndex; GetCurveIndicesForKnot(postKnotIndex, out postKnotPreCurveIndex, out postKnotPostCurveIndex); if (postKnotPostCurveIndex != -1) { AutomateHandles(postKnotIndex, ref postKnot, knot.position, curves[postKnotPostCurveIndex].d); curves[postKnotPostCurveIndex] = new Bezier3DCurve(postKnot.position, postKnot.handleOut, curves[postKnotPostCurveIndex].c, curves[postKnotPostCurveIndex].d, cacheDensity); } else { AutomateHandles(postKnotIndex, ref postKnot, knot.position, Vector3.zero); } } } //Get the curve indices in direct contact with knot int preCurveIndex, postCurveIndex; GetCurveIndicesForKnot(i, out preCurveIndex, out postCurveIndex); //Adjust curves in direct contact with the knot if (preCurveIndex != -1) curves[preCurveIndex] = new Bezier3DCurve(preKnot.position, preKnot.handleOut, knot.handleIn, knot.position, cacheDensity); if (postCurveIndex != -1) curves[postCurveIndex] = new Bezier3DCurve(knot.position, knot.handleOut, postKnot.handleIn, postKnot.position, cacheDensity); _totalLength = GetTotalLength(); } /// <summary> Flip the spline </summary> public void Flip() { Bezier3DCurve[] curves = new Bezier3DCurve[CurveCount]; for (int i = 0; i < CurveCount; i++) { curves[CurveCount - 1 - i] = new Bezier3DCurve(this.curves[i].d, this.curves[i].c, this.curves[i].b, this.curves[i].a, cacheDensity); } this.curves = curves; autoKnot.Reverse(); orientations.Reverse(); } #endregion #endregion public struct Knot { public Vector3 position; public Vector3 handleIn; public Vector3 handleOut; public float auto; public Quaternion? orientation; /// <summary> Constructor </summary> /// <param name="position">Position of the knot local to spline transform</param> /// <param name="handleIn">Left handle position local to knot position</param> /// <param name="handleOut">Right handle position local to knot position</param> /// <param name="automatic">Any value above 0 will result in an automatically configured knot (ignoring handle inputs)</param> public Knot(Vector3 position, Vector3 handleIn, Vector3 handleOut, float automatic = 0f, Quaternion? orientation = null) { this.position = position; this.handleIn = handleIn; this.handleOut = handleOut; this.auto = automatic; this.orientation = orientation; } } #region Private methods private Vector3 GetUp(float dist, Vector3 tangent, bool local) { float t = DistanceToTime(dist); t *= CurveCount; Quaternion rot_a = Quaternion.identity, rot_b = Quaternion.identity; int t_a = 0, t_b = 0; //Find preceding rotation for (int i = Mathf.Min((int)t, CurveCount); i >= 0; i--) { i = (int)Mathf.Repeat(i, KnotCount - 1); if (orientations[i].HasValue) { rot_a = orientations[i].Value; rot_b = orientations[i].Value; t_a = i; t_b = i; break; } } //Find proceding rotation for (int i = Mathf.Max((int)t + 1, 0); i < orientations.Count; i++) { if (orientations[i].HasValue) { rot_b = orientations[i].Value; t_b = i; break; } } t = Mathf.InverseLerp(t_a, t_b, t); Quaternion rot = Quaternion.Lerp(rot_a, rot_b, t); if (!local) rot = transform.rotation * rot; //Debug.Log(t_a + " / " + t_b + " / " + t); return Vector3.ProjectOnPlane(rot * Vector3.up, tangent).normalized; } /// <summary> Get the curve indices in direct contact with knot </summary> private void GetCurveIndicesForKnot(int knotIndex, out int preCurveIndex, out int postCurveIndex) { //Get the curve index in direct contact with, before the knot preCurveIndex = -1; if (knotIndex != 0) preCurveIndex = knotIndex - 1; else if (closed) preCurveIndex = CurveCount - 1; //Get the curve index in direct contact with, after the knot postCurveIndex = -1; if (knotIndex != CurveCount) postCurveIndex = knotIndex; else if (closed) postCurveIndex = 0; } /// <summary> Get the knot indices in direct contact with knot </summary> private void GetKnotIndicesForKnot(int knotIndex, out int preKnotIndex, out int postKnotIndex) { //Get the curve index in direct contact with, before the knot preKnotIndex = -1; if (knotIndex != 0) preKnotIndex = knotIndex - 1; else if (closed) preKnotIndex = KnotCount - 1; //Get the curve index in direct contact with, after the knot postKnotIndex = -1; if (knotIndex != KnotCount - 1) postKnotIndex = knotIndex + 1; else if (closed) postKnotIndex = 0; } private Bezier3DCurve GetCurve(float splineT, out float curveT) { splineT *= CurveCount; for (int i = 0; i < CurveCount; i++) { if (splineT > 1f) splineT -= 1f; else { curveT = splineT; return curves[i]; } } curveT = 1f; return curves[CurveCount - 1]; } private Bezier3DCurve GetCurveDistance(float splineDist, out float curveDist) { for (int i = 0; i < CurveCount; i++) { if (curves[i].length < splineDist) splineDist -= curves[i].length; else { curveDist = splineDist; return curves[i]; } } curveDist = curves[CurveCount -1].length; return curves[CurveCount - 1]; } /// <summary> Automate handles based on previous and next point positions </summary> private void AutomateHandles(int i, ref Knot knot) { //Terminology: Points are referred to as A B and C //A = prev point, B = current point, C = next point Vector3 prevPos; if (i != 0) prevPos = curves[i - 1].a; else if (closed) prevPos = curves[CurveCount - 1].a; else prevPos = Vector3.zero; Vector3 nextPos; if (i != KnotCount - 1) nextPos = curves[i].d; else if (closed) nextPos = curves[0].a; else nextPos = Vector3.zero; AutomateHandles(i, ref knot, prevPos, nextPos); } /// <summary> Automate handles based on previous and next point positions </summary> private void AutomateHandles(int i, ref Knot knot, Vector3 prevPos, Vector3 nextPos) { //Terminology: Points are referred to as A B and C //A = prev point, B = current point, C = next point float amount = knot.auto; //Calculate directional vectors Vector3 AB = knot.position - prevPos; Vector3 CB = knot.position - nextPos; //Calculate the across vector Vector3 AB_CB = (CB.normalized - AB.normalized).normalized; if (!closed) { if (i == 0) { knot.handleOut = CB * -amount; } else if (i == CurveCount) { knot.handleIn = AB * -amount; } else { knot.handleOut = -AB_CB * CB.magnitude * amount; knot.handleIn = AB_CB * AB.magnitude * amount; } } else { if (KnotCount == 2) { Vector3 left = new Vector3(AB.z, 0,-AB.x) * amount; if (i == 0) { knot.handleIn = left; knot.handleOut = -left; } if (i == 1) { knot.handleIn = left; knot.handleOut = -left; } } else { knot.handleIn = AB_CB * AB.magnitude * amount; knot.handleOut = -AB_CB * CB.magnitude * amount; } } } private float GetTotalLength() { float length = 0f; for (int i = 0; i < CurveCount; i++) { length += curves[i].length; } return length; } #endregion /// <summary> Unity doesn't support serialization of nullable types, so here's a custom struct that does exactly the same thing </summary> [Serializable] protected struct NullableQuaternion { public Quaternion Value { get { return rotation; } } public Quaternion? NullableValue { get { if (hasValue) return rotation; else return null; } } public bool HasValue { get { return hasValue; } } [SerializeField] private Quaternion rotation; [SerializeField] private bool hasValue; public NullableQuaternion(Quaternion? rot) { rotation = rot.HasValue?rot.Value:Quaternion.identity; hasValue = rot.HasValue; } // User-defined conversion from nullable type to NullableQuaternion public static implicit operator NullableQuaternion(Quaternion? r) { return new NullableQuaternion(r); } } #if UNITY_EDITOR void OnDrawGizmos() { //Set color depending on selection if (Array.IndexOf(UnityEditor.Selection.gameObjects, gameObject) >= 0) { Gizmos.color = Color.yellow; } else Gizmos.color = new Color(1, 0.6f, 0f); //Loop through each curve in spline for (int i = 0; i < CurveCount; i++) { Bezier3DCurve curve = GetCurve(i); //Get curve in world space Vector3 a, b, c, d; a = transform.TransformPoint(curve.a); b = transform.TransformPoint(curve.b + curve.a); c = transform.TransformPoint(curve.c + curve.d); d = transform.TransformPoint(curve.d); int segments = 50; float spacing = 1f / segments; Vector3 prev = Bezier3DCurve.GetPoint(a, b, c, d, 0f); for (int k = 0; k <= segments; k++) { Vector3 cur = Bezier3DCurve.GetPoint(a, b, c, d, k * spacing); Gizmos.DrawLine(prev, cur); prev = cur; } } } #endif }
https://youtu.be/ziarrVCK0G4
https://youtu.be/oTNI8hpWUrw
using System.Collections; using System.Collections.Generic; using UnityEngine; using ProceduralToolkit; using UnityEngine.UI; using System; using ArgosTweenSpacePuppy; using VRTK; using System.IO; using UnityEngine.EventSystems; using System.Linq; public class Sphere_Expander : MonoBehaviour { public bool bSeparate_Faces = false; public bool bDrawTetrahedron = false; public int totalVerts = 0; public int filteredVerts = 0; public int vSort_Count_0; public int vSort_Count_1; public int vSort_Count_2; private ArgosMeshDraft aMD_TetraTerrean; private ArgosMeshDraft aMD_TT_Sleeve; private ArgosMeshDraft[] aMD_tt_Faces = new ArgosMeshDraft[4]; private GameObject[] tt_Faces = new GameObject[4]; private ArgosMeshDraft aMD_Spheres; private ArgosMeshDraft cylinder_MD; private ArgosMeshDraft scythe_MD; private GameObject scythe_GO; public Color col_edge_Cylinder; public Color col_Sphere; private GameObject[] spheres = new GameObject[4]; private Vector3[] sphere_pos = new Vector3[4]; public GameObject meshPF; public GameObject tetra_Vert_GOPF; private GameObject[] tetra_Verts_GO = new GameObject[4]; private GameObject[] tetra_Edges = new GameObject[6]; private GameObject TetraTerrien_GO; private GameObject TT_Sleeve_GO; public float[] lengths = new float[256]; public float[] hyperbola_of_R = new float[256]; public int all_Shape_Depth = 4; Vector3[] vC = new Vector3[4]; public class Vector_Sort { public Vector3 vert; public float dist = 0; public int vIDX = 0; } internal class PlaneHelper { /// <summary> /// Returns a value indicating what side (positive/negative) of a plane a point is /// </summary> /// <param name="point">The point to check with</param> /// <param name="plane">The plane to check against</param> /// <returns>Greater than zero if on the positive side, less than zero if on the negative size, 0 otherwise</returns> public static float ClassifyPoint(ref Vector3 point, ref Plane plane) { return point.x * plane.Normal.x + point.y * plane.Normal.y + point.z * plane.Normal.z + plane.D; } /// <summary> /// Returns the perpendicular distance from a point to a plane /// </summary> /// <param name="point">The point to check</param> /// <param name="plane">The place to check</param> /// <returns>The perpendicular distance from the point to the plane</returns> public static float PerpendicularDistance(ref Vector3 point, ref Plane plane) { // dist = (ax + by + cz + d) / sqrt(a*a + b*b + c*c) return Mathf.Abs((plane.Normal.x * point.x + plane.Normal.y * point.y + plane.Normal.z * point.z) / Mathf.Sqrt(plane.Normal.x * plane.Normal.x + plane.Normal.y * plane.Normal.y + plane.Normal.z * plane.Normal.z)); } } public struct Plane { #region Public Fields public float D; public Vector3 Normal; #endregion Public Fields #region Constructors public Plane(Vector4 value) : this(new Vector3(value.x, value.y, value.z), value.w) { } public Plane(Vector3 normal, float d) { Normal = normal; D = d; } public Plane(Vector3 a, Vector3 b, Vector3 c) { Vector3 ab = b - a; Vector3 ac = c - a; Vector3 cross = Vector3.Cross(ab, ac); Normal = Vector3.Normalize(cross); D = -(Vector3.Dot(Normal, a)); } public Plane(float a, float b, float c, float d) : this(new Vector3(a, b, c), d) { } #endregion Constructors public override string ToString() { return string.Format("{{Normal:{0} D:{1}}}", Normal, D); } } public enum TT_TYPE { SPHERICAL, HYPERBOLIC, OTHER, NONE, } public TT_TYPE ttType = TT_TYPE.SPHERICAL; public bool bSpheresON = true; public bool bTetraTerrean_On = false; [Range(0, 50f)] public float tetra_Radius; private float tetra_Radius_Last = 0; [Range(0, 100f)] public float scale_TT= 100f; [Range(0, 500f)] public float sphere_Radius; private float sphere_Radius_Last = 0; [Range(0, 0.5f)] public float cylinder_Radius; private Vector3[] tetra_Verts = new Vector3[4]; private Vector3[] face_Centers = new Vector3[4]; [Space(12)] [Header("Hyperbolic Settings")] [Space(12)] [Range(0, 1f)] public float base_Distance; [Range(0, 1f)] public float tangent_Base; [Range(0, 1f)] public float tangent_H; [Range(0, 1f)] public float smidge; public GameObject H_Editor_Label; public GameObject C_Editor_Label; public GameObject B_Editor_Label; public GameObject I_Editor_Label; public GameObject T1_Editor_Label; public GameObject T2_Editor_Label; private int frameCount = 1; private Vector3 vCHn, vIHn, vT1n, vT2n; private Vector3 vIH; StreamWriter sWrite; public bool bPrint_Trace = false; private Vector3[] beeS = new Vector3[4]; StreamWriter sLineVectors; private ArgosMeshDraft aMD_Nurbs_Mesh; GameObject pQuad_CARBON_LINE_go; private ArgosMeshDraft aMD_PQUAD_TMP; public enum RESOLUTION { RES_LOW, RES_MED, RES_HIGH, } public RESOLUTION rESOLUTION = RESOLUTION.RES_LOW; private RESOLUTION resolution_Last = RESOLUTION.RES_LOW; private int nRESOLUTION = 7; private List<Vector3> lst_mesh_v = new List<Vector3>(); public float[] spline_lengths = new float[256]; [Range(0, 10f)] public float short_Tan_mag = 1; [Range(0, 10f)] public float long_Tan_mag = 1; void Start() { sLineVectors = new StreamWriter("sLineVectors.txt"); aMD_TetraTerrean = new ArgosMeshDraft(); aMD_Spheres = new ArgosMeshDraft(); aMD_Spheres.Add(MeshDraft.Sphere(1,16,16)); cylinder_MD = new ArgosMeshDraft(); aMD_TT_Sleeve = new ArgosMeshDraft(); scythe_MD = new ArgosMeshDraft(); scythe_GO = Instantiate(meshPF, transform); scythe_GO.name = "SCYTHE_OUTLINE"; aMD_Nurbs_Mesh = new ArgosMeshDraft(); pQuad_CARBON_LINE_go = Instantiate(meshPF, transform); pQuad_CARBON_LINE_go.name = "pQuad_CARBON_LINE_go"; pQuad_CARBON_LINE_go.GetComponent<MeshRenderer>().enabled = false;//so we can see the TT sWrite = new StreamWriter("Hyperbolic_Params.txt"); for (int i = 0; i<4; i++) { spheres[i] = Instantiate(meshPF, transform); spheres[i].name = "sphere_" + i.ToString(); SetColor_Element(col_Sphere, spheres[i]); spheres[i].GetComponent<MeshFilter>().mesh = aMD_Spheres.ToMeshInternal(); tetra_Verts_GO[i] = Instantiate(tetra_Vert_GOPF, transform); tetra_Verts_GO[i].name = "TetVERT_" + i.ToString(); tt_Faces[i] = Instantiate(meshPF, transform); tt_Faces[i].name = "TT_Face_" + i.ToString(); aMD_tt_Faces[i] = new ArgosMeshDraft(); } for(int i = 0; i<6; i++) { tetra_Edges[i] = Instantiate(meshPF, transform); tetra_Edges[i].name = "edge_" + i.ToString(); SetColor_Element(col_edge_Cylinder, tetra_Edges[i]); tetra_Edges[i].GetComponent<MeshFilter>().mesh = cylinder_MD.ToMeshInternal(); } Set_Tetra_Verts(tetra_Radius); TetraTerrien_GO = Instantiate(meshPF, transform); TetraTerrien_GO.name = "TetraTerrien_GO"; aMD_TetraTerrean.Clear(); //Create_TETRA_TERREAN(all_Shape_Depth); //TetraTerrien_GO.GetComponent<MeshFilter>().mesh = aMD_TetraTerrean.ToMeshInternal(); TT_Sleeve_GO = Instantiate(meshPF, transform); TT_Sleeve_GO.name = "TT_Sleeve_GO"; aMD_TT_Sleeve.Clear(); aMD_PQUAD_TMP = new ArgosMeshDraft(); } /// <image url="$(SolutionDir)\EMB\Quad_Nurb.png" scale="0.15" /> public void PQuad_SetUp_VertsAndTans() { Vector3 v0; Vector3 v1; Vector3 v2; Vector3 v3; Vector3 t01; Vector3 t10; Vector3 t13; Vector3 t31; Vector3 t23; Vector3 t32; Vector3 t20; Vector3 t02; v0 = tetra_Verts[2]; v1 = v0; v1.y = -v1.y; v2 = tetra_Verts[3]; v3 = v2; v3.y = -v3.y; //short_Tan_mag; //long_Tan_mag; Vector3[] vTansNorm = new Vector3[4]; vTansNorm[0] = -v0.normalized; vTansNorm[1] = -v1.normalized; vTansNorm[2] = -v2.normalized; vTansNorm[3] = -v3.normalized; t01 = v0 + vTansNorm[0] * short_Tan_mag; t02 = v0 + vTansNorm[0] * long_Tan_mag; t10 = v1 + vTansNorm[1] * short_Tan_mag; t13 = v1 + vTansNorm[1] * long_Tan_mag; t23 = v2 + vTansNorm[2] * short_Tan_mag; t20 = v2 + vTansNorm[2] * long_Tan_mag; t32 = v3 + vTansNorm[3] * short_Tan_mag; t31 = v3 + vTansNorm[3] * long_Tan_mag; P_Quad_Generate(v0, v1, v2, v3, t01, t10, t13, t31, t23, t32, t20, t02); } public void P_Quad_Generate(Vector3 v0, Vector3 v1, Vector3 v2, Vector3 v3, Vector3 t01, Vector3 t10, Vector3 t13, Vector3 t31, Vector3 t23, Vector3 t32, Vector3 t20, Vector3 t02) { Set_Resolution(); lst_mesh_v.Clear(); aMD_Nurbs_Mesh.Clear(); float u = 0; float v = 0; float du = 1 / (float)nRESOLUTION; float dv = 1 / (float)nRESOLUTION; Vector3 t0, t1; Vector3 p0, p1; Vector3 p; for (int i = 0; i < nRESOLUTION + 1; i++) { t0 = GetPointOnBezierCurve(t02, t01, t10, t13, get_Adjusted(u, ref spline_lengths)); p0 = GetPointOnBezierCurve(v0, t01, t10, v1, get_Adjusted(u, ref spline_lengths)); t1 = GetPointOnBezierCurve(t20, t23, t32, t31, get_Adjusted(u, ref spline_lengths)); p1 = GetPointOnBezierCurve(v2, t23, t32, v3, get_Adjusted(u, ref spline_lengths)); Compute_Dist(ref spline_lengths, v0, t02, t20, v2); v = 0f; for (int j = 0; j < nRESOLUTION + 1; j++) { p = GetPointOnBezierCurve(p0, t0, t1, p1, get_Adjusted(v, ref spline_lengths)); lst_mesh_v.Add(p); v += dv; } u += du; } int stride = nRESOLUTION + 1; int k = 0; for (int i = 0; i < nRESOLUTION; i++) { for (int j = 0; j < nRESOLUTION; j++) { aMD_Nurbs_Mesh.Add(MeshDraft.Quad(lst_mesh_v[k], lst_mesh_v[k + 1], lst_mesh_v[k + stride + 1], lst_mesh_v[k + stride])); k++; } k++; } Quaternion q; float angle = 120; ArgosMeshDraft amdTmp = new ArgosMeshDraft(); amdTmp.Copy_MeshDraft(aMD_Nurbs_Mesh); amdTmp.Rotate(Quaternion.AngleAxis(angle, Vector3.up)); aMD_Nurbs_Mesh.Add(amdTmp); amdTmp.Rotate(Quaternion.AngleAxis(angle, Vector3.up)); aMD_Nurbs_Mesh.Add(amdTmp); aMD_PQUAD_TMP.Clear(); subdivide_PQUAD_TRIANGLE(tetra_Verts[2], tetra_Verts[3], tetra_Verts[1], all_Shape_Depth, spheres[2].transform.localPosition, 3, true); aMD_Nurbs_Mesh.Add(aMD_PQUAD_TMP); aMD_PQUAD_TMP.Rotate(Quaternion.AngleAxis(180, Vector3.forward)); aMD_Nurbs_Mesh.Add(aMD_PQUAD_TMP); pQuad_CARBON_LINE_go.GetComponent<MeshFilter>().mesh = aMD_Nurbs_Mesh.ToMeshInternal(); pQuad_CARBON_LINE_go.GetComponent<MeshFilter>().mesh.RecalculateNormals(60); } void subdivide_PQUAD_TRIANGLE(Vector3 v1, Vector3 v2, Vector3 v3, int depth, Vector3 sector_Foc, int nID, bool bFlipNorm) { Vector3 v12, v23, v31; Vector3 v12_n, v23_n, v31_n; if (depth == 0) { if (bFlipNorm) { addTriangle_UV_Tag_PQUAD(v1, v3, v2, (float)nID); } else { //if (nID == 1) //{ // vTest[i] = v1; // vTest2[i] = v2; // i++; //} addTriangle_UV_Tag_PQUAD(v3, v2, v1, (float)nID); } return; } v12 = (v1 + v2) / 2.0f; v23 = (v2 + v3) / 2.0f; v31 = (v3 + v1) / 2.0f; v12_n = Sphere_Surf(v12, sector_Foc); //sector_Foc v23_n = Sphere_Surf(v23, sector_Foc); v31_n = Sphere_Surf(v31, sector_Foc); //v12_n = v12; //sector_Foc //v23_n = v23; //v31_n = v31; /* recursively subdivide new triangles */ subdivide_PQUAD_TRIANGLE(v1, v12_n, v31_n, depth - 1, sector_Foc, 1, bFlipNorm); subdivide_PQUAD_TRIANGLE(v12_n, v2, v23_n, depth - 1, sector_Foc, 2, bFlipNorm); subdivide_PQUAD_TRIANGLE(v31_n, v23_n, v3, depth - 1, sector_Foc, 3, bFlipNorm); subdivide_PQUAD_TRIANGLE(v23_n, v31_n, v12_n, depth - 1, sector_Foc, 4, bFlipNorm); } private void Create_Top_Bottom(int depth) { //sleeve(tetra_Verts[1], tetra_Verts[2], tetra_Verts[3], spheres[2].transform.localPosition); subdivide_CarbonLine(tetra_Verts[1], tetra_Verts[3], tetra_Verts[2], depth, spheres[2].transform.localPosition, 3, false); List<Vector_Sort>[] vsortList = new List<Vector_Sort>[3]; vsortList[0] = new List<Vector_Sort>(); vsortList[1] = new List<Vector_Sort>(); vsortList[2] = new List<Vector_Sort>(); int[] id = new int[] { 0, 1, 2, 0, 2, 3, 0, 3, 1 }; Vector3 vert; for (int j = 0; j < 3; j++) { Plane p = new Plane(tetra_Verts[id[3 * j]], tetra_Verts[id[3 * j + 1]], tetra_Verts[id[3 * j + 2]]); p.D = p.D * 0.999f; Vector_Sort vs; filteredVerts = 0; for (int i = 0; i < aMD_TT_Sleeve.vertices.Count; i++) { vert = aMD_TT_Sleeve.vertices[i]; float res = PlaneHelper.ClassifyPoint(ref vert, ref p); if (res > 0) { filteredVerts++; vs = new Vector_Sort(); vs.vert = vert; vs.vIDX = i; vsortList[j].Add(vs); } } RemoveDuplicates(vsortList[j]); for (int i = 0; i < vsortList[j].Count; i++) { vsortList[j][i].dist = (tetra_Verts[j + 1] - vsortList[j][i].vert).magnitude; } var ordered = from element in vsortList[j] orderby element.dist select element; vsortList[j] = ordered.ToList<Vector_Sort>(); } for (int i = 0; i < aMD_TT_Sleeve.vertices.Count; i++) { aMD_TT_Sleeve.vertices[i] = Sphere_Surf(aMD_TT_Sleeve.vertices[i], spheres[2].transform.localPosition); } Plane p2 = new Plane(Vector3.up, 0); int vertCount = aMD_TT_Sleeve.vertices.Count; ArgosMeshDraft amdTemp = new ArgosMeshDraft(); amdTemp.Add(aMD_TT_Sleeve); aMD_TT_Sleeve.FlipTriangles(); aMD_TT_Sleeve.Add(amdTemp); aMD_TT_Sleeve.FlipNormals(); float d; for (int i = 0; i < vertCount; i++)//FLIP { vert = aMD_TT_Sleeve.vertices[i]; d = PlaneHelper.ClassifyPoint(ref vert, ref p2); aMD_TT_Sleeve.vertices[i] = vert - 2f * d * Vector3.up; } List<Vector3> vInnerLower = new List<Vector3>(); List<Vector3> vInnerUpper = new List<Vector3>(); List<Vector3> vPrint = new List<Vector3>(); for (int j = 0; j < 3; j++) { for (int i = 0; i < vsortList[j].Count; i++) { vert = aMD_TT_Sleeve.vertices[vsortList[j][i].vIDX]; //vCurr.y = 0; d = PlaneHelper.ClassifyPoint(ref vert, ref p2); if (j == 0) { vPrint.Add(vert - 2f * d * Vector3.up); } vInnerLower.Add(vert); vInnerUpper.Add(vert - 2f * d * Vector3.up); } } aMD_TT_Sleeve.Add(MeshDraft.Band(vInnerUpper, vInnerLower)); aMD_TT_Sleeve.Add(MeshDraft.Band(vInnerLower, vInnerUpper)); Generate_Line_List(vPrint); vSort_Count_0 = vsortList[0].Count; vSort_Count_1 = vsortList[1].Count; vSort_Count_2 = vsortList[2].Count; } private float get_Adjusted(float t, ref float[] lengths) { int i = 0; while (i < 256 && lengths[i] < t) { i++; } return (float)i / 256; } private void Compute_Dist(ref float[] lengths, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3) { float t = 0.0f; float dt = 1f / 256; Vector3 vB = GetPointOnBezierCurve(p0, p1, p2, p3, t); Vector3 vB_Last = vB; float running_Len = 0; for (int i = 0; i < 256; i++) { vB = GetPointOnBezierCurve(p0, p1, p2, p3, t); running_Len += (vB - vB_Last).magnitude; lengths[i] = running_Len; vB_Last = vB; t += dt; } for (int i = 0; i < 256; i++) { lengths[i] /= running_Len; } } private void Set_Resolution() { if (rESOLUTION != resolution_Last) { if (rESOLUTION == RESOLUTION.RES_LOW) { nRESOLUTION = 7; } else if (rESOLUTION == RESOLUTION.RES_MED) { nRESOLUTION = 18; } else if (rESOLUTION == RESOLUTION.RES_HIGH) { nRESOLUTION = 36; } } resolution_Last = rESOLUTION; } //void OnDrawGizmos() //{ // Gizmos.DrawIcon(H_Editor_Label.transform.position, "H.png", true); // Gizmos.DrawIcon(C_Editor_Label.transform.position, "C.png", true); // Gizmos.DrawIcon(I_Editor_Label.transform.position, "I.png", true); // Gizmos.DrawIcon(B_Editor_Label.transform.position, "B.png", true); // Gizmos.DrawIcon(T1_Editor_Label.transform.position, "T1.png", true); // Gizmos.DrawIcon(T2_Editor_Label.transform.position, "T2.png", true); // Gizmos.color = Color.green; // Gizmos.DrawLine(B_Editor_Label.transform.position, T1_Editor_Label.transform.position); // Gizmos.DrawLine(H_Editor_Label.transform.position, T2_Editor_Label.transform.position); //} private void OnApplicationQuit() { sWrite.Close(); } /// <image url="$(SolutionDir)\EMB\hyperbole2.png" scale="0.35"></image> private void build_Reference_Hyperbolic_Spline(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, Vector3 vI) { //p4 = H float t = 0.0f; float dt = 1f / 256; Vector3 vB = GetPointOnBezierCurve(p0, p1, p2, p3, t); Vector3 vB_Last = vB; float running_Len = 0; float vI_Len = vI.magnitude; Vector3 vIn = vI.normalized; for (int i = 0; i < 256; i++) { vB = GetPointOnBezierCurve(p0, p1, p2, p3, t); running_Len += (vB - vB_Last).magnitude; lengths[i] = running_Len; hyperbola_of_R[i] = Vector3.Dot(vB, vIn); vB_Last = vB; t += dt; } for (int i = 0; i < 256; i++) { lengths[i] /= running_Len; } } public void Print_Trace(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, Vector3 vI) { for (int i = 0; i < 256; i++) { sWrite.WriteLine(i.ToString() + "\t " + " -\t " + hyperbola_of_R[i].ToString("F2")); } sWrite.WriteLine("p0 Base " + "\t " + " -\t " + p0.ToString("F2")); sWrite.WriteLine("p1 Tangent_0 " + "\t " + " -\t " + p1.ToString("F2")); sWrite.WriteLine("p2 Tangent_1 " + "\t " + " -\t " + p2.ToString("F2")); sWrite.WriteLine("p3 H " + "\t " + " -\t " + p3.ToString("F2")); sWrite.WriteLine("vI " + "\t " + " -\t " + vI.ToString("F2")); } private void SetColor_Element(Color col, GameObject go) { float alpha = col.a; float alpha_out = alpha / 3f; Color cola = col; cola.a = alpha_out; go.GetComponent<MeshRenderer>().material.SetColor("_EmissionColor", cola); go.GetComponent<MeshRenderer>().material.SetColor("_Color", col); } public void Set_Tetra_Verts(float radius) { float tetrahedralAngle = Mathf.PI * -19.471220333f / 180; float segmentAngle = Mathf.PI * 2 / 3; float currentAngle = 0f; Vector3 v = new Vector3(0, radius, 0); tetra_Verts[0] = v; for (var i = 1; i < 4; i++) { tetra_Verts[i] = PTUtils.PointOnSphere(radius, currentAngle, tetrahedralAngle); currentAngle += segmentAngle; } face_Centers[0] = (tetra_Verts[0] + tetra_Verts[1] + tetra_Verts[2]) / 3f; face_Centers[1] = (tetra_Verts[0] + tetra_Verts[2] + tetra_Verts[3]) / 3f; face_Centers[2] = (tetra_Verts[1] + tetra_Verts[2] + tetra_Verts[3]) / 3f; face_Centers[3] = (tetra_Verts[0] + tetra_Verts[1] + tetra_Verts[3]) / 3f; float edge_length = (tetra_Verts[0] - tetra_Verts[1]).magnitude; edge_length = radius * 2f * Mathf.Sqrt(2f) / Mathf.Sqrt(3); cylinder_MD.Add(MeshDraft.Cylinder_Z(cylinder_Radius, 5, edge_length)); //tetra_Edges[0].transform.localPosition = tetra_Verts[0]; //tetra_Edges[0].transform.localRotation = Quaternion.LookRotation(tetra_Verts[1] - tetra_Verts[0]); //tetra_Edges[0].GetComponent<MeshFilter>().mesh = cylinder_MD.ToMeshInternal(); //tetra_Edges[1].transform.localPosition = tetra_Verts[1]; //tetra_Edges[1].transform.localRotation = Quaternion.LookRotation(tetra_Verts[2] - tetra_Verts[1]); //tetra_Edges[1].GetComponent<MeshFilter>().mesh = cylinder_MD.ToMeshInternal(); //tetra_Edges[2].transform.localPosition = tetra_Verts[2]; //tetra_Edges[2].transform.localRotation = Quaternion.LookRotation(tetra_Verts[3] - tetra_Verts[2]); //tetra_Edges[2].GetComponent<MeshFilter>().mesh = cylinder_MD.ToMeshInternal(); //tetra_Edges[3].transform.localPosition = tetra_Verts[3]; //tetra_Edges[3].transform.localRotation = Quaternion.LookRotation(tetra_Verts[0] - tetra_Verts[3]); //tetra_Edges[3].GetComponent<MeshFilter>().mesh = cylinder_MD.ToMeshInternal(); //tetra_Edges[4].transform.localPosition = tetra_Verts[1]; //tetra_Edges[4].transform.localRotation = Quaternion.LookRotation(tetra_Verts[3] - tetra_Verts[1]); //tetra_Edges[4].GetComponent<MeshFilter>().mesh = cylinder_MD.ToMeshInternal(); //tetra_Edges[5].transform.localPosition = tetra_Verts[2]; //tetra_Edges[5].transform.localRotation = Quaternion.LookRotation(tetra_Verts[0] - tetra_Verts[2]); //tetra_Edges[5].GetComponent<MeshFilter>().mesh = cylinder_MD.ToMeshInternal(); } private void Create_Scythe(int depth) { subdivide_CarbonLine(tetra_Verts[1], tetra_Verts[3], tetra_Verts[2], depth, spheres[2].transform.localPosition, 3, false); } void Update() { PQuad_SetUp_VertsAndTans(); cylinder_MD.Clear(); scythe_MD.Clear(); Set_Tetra_Verts(tetra_Radius); if (sphere_Radius_Last != sphere_Radius) { float face_dist; float tetra_Height; Vector3 face_Norm; float a, b; aMD_Spheres.Clear(); aMD_Spheres.Add(MeshDraft.Sphere(sphere_Radius, 36, 32)); for (int i = 0; i < 4; i++) { face_dist = face_Centers[i].magnitude; tetra_Height = 1.33333f * tetra_Radius; a = 2 * Mathf.Sqrt(2) / 3; b = Mathf.Sqrt(sphere_Radius * sphere_Radius - tetra_Radius * tetra_Radius * 8f / 9f); face_Norm = face_Centers[i].normalized; spheres[i].transform.localPosition = face_Norm * (tetra_Radius / 3 + b); spheres[i].transform.localRotation = Quaternion.LookRotation(sphere_pos[i]); spheres[i].GetComponent<MeshFilter>().mesh = aMD_Spheres.ToMeshInternal(); tetra_Verts_GO[i].transform.localPosition = tetra_Verts[i]; } } sphere_Radius_Last = sphere_Radius; tetra_Radius_Last = tetra_Radius; if (bSpheresON) { ShowSpheres(true); } else { ShowSpheres(false); } aMD_TetraTerrean.Clear(); for (int i = 0; i < 4; i++) { aMD_tt_Faces[i].Clear(); } Create_TETRA_TERREAN(all_Shape_Depth); if (bSeparate_Faces) { for (int i = 0; i < 4; i++) { tt_Faces[i].GetComponent<MeshFilter>().mesh = aMD_tt_Faces[i].ToMeshInternal(); } } else { aMD_TetraTerrean.FlipTriangles(); aMD_TetraTerrean.FlipNormals(); TetraTerrien_GO.GetComponent<MeshFilter>().mesh = aMD_TetraTerrean.ToMeshInternal(); TetraTerrien_GO.GetComponent<MeshFilter>().mesh.RecalculateNormals(60); } //Create_Scythe(all_Shape_Depth); //aMD_TT_Sleeve.Clear(); //Create_TETRA_TERREAN_Sleeve(all_Shape_Depth); //TT_Sleeve_GO.GetComponent<MeshFilter>().mesh = aMD_TT_Sleeve.ToMeshInternal(); //TT_Sleeve_GO.GetComponent<MeshFilter>().mesh.RecalculateNormals(60); sphere_Radius_Last = sphere_Radius; tetra_Radius_Last = tetra_Radius; } private void ShowSpheres(bool bOn) { for(int i = 0; i<4; i++) { spheres[i].GetComponent<MeshRenderer>().enabled = bOn; } } public void Calc_Tetra_Verts(float radius) { float tetrahedralAngle = Mathf.PI * -19.471220333f / 180; float segmentAngle = Mathf.PI * 2 / 3; float currentAngle = 0f; Vector3 v = new Vector3(0, radius, 0); sphere_pos[0] = v; for (var i = 1; i < 4; i++) { sphere_pos[i] = PTUtils.PointOnSphere(radius, currentAngle, tetrahedralAngle); currentAngle += segmentAngle; } } private Vector3 Sphere_Surf(Vector3 vP0, Vector3 sector_Focus) { Vector3 l = vP0.normalized; Vector3 OminC = -sector_Focus; float rsqr = sphere_Radius * sphere_Radius; float dotLOminC = Vector3.Dot(l, OminC); float Omag = OminC.magnitude; float d = -dotLOminC - Mathf.Sqrt(dotLOminC * dotLOminC - Omag * Omag + sphere_Radius * sphere_Radius); return l * d; } private Vector3 Hyperbolic(Vector3 vP0, Vector3 face_Center) { Vector3 vFCn = face_Center.normalized; Vector3 dotV = Vector3.Dot(vP0, vFCn)* vFCn; Vector3 radV = vP0 - dotV; Vector3 vP0n = vP0.normalized; float radial_mag = radV.magnitude; float perc = (radial_mag / vIH.magnitude)*255; float gVal = 0f; //if (perc < 256) //{ gVal = hyperbola_of_R[(int)perc]; //} return (gVal*vFCn + radV); } void Extrude_1(Vector3 v1, Vector3 v2, Vector3 v3, int nID, Vector3 sector_Foc) { Vector3 nSect = tetra_Verts[0].normalized; float spar = (1f / 9f) * sphere_Radius; float d1, d2, d3; d1 = Vector3.Dot(v1, nSect); d2 = Vector3.Dot(v2, nSect); d3 = Vector3.Dot(v3, nSect); Vector3 ob1 = (spar - d1) * nSect; Vector3 ob2 = (spar - d2) * nSect; Vector3 ob3 = (spar - d3) * nSect; if (nID == 0) { addTriangle(v1 + 2 * ob1, v2 + 2 * ob2, v3 + 2 * ob3); } else { ob1 = PosCheck(nSect, d1, (d1 / spar), v1 - d1 * nSect); ob2 = PosCheck(nSect, d2, (d2 / spar), v2 - d2 * nSect); ob3 = PosCheck(nSect, d3, (d3 / spar), v3 - d3 * nSect); addTriangle(v1 + ob1, v2 + ob2, v3 + ob3); } } private Vector3 PosCheck(Vector3 v1, float d, float multiplier, Vector3 vHorz) { return Vector3.zero; } public static void RemoveDuplicates(List<Vector_Sort> list) { if (list == null) { return; } int i = 1; while (i < list.Count) { int j = 0; bool remove = false; while (j < i && !remove) { if (list[i].vert.Equals(list[j].vert)) { remove = true; } j++; } if (remove) { list.RemoveAt(i); } else { i++; } } } private void Create_TETRA_TERREAN_Sleeve(int depth) { //sleeve(tetra_Verts[1], tetra_Verts[2], tetra_Verts[3], spheres[2].transform.localPosition); subdivide_CarbonLine(tetra_Verts[1], tetra_Verts[3], tetra_Verts[2], depth, spheres[2].transform.localPosition, 3, false); List<Vector_Sort>[] vsortList = new List<Vector_Sort>[3]; vsortList[0] = new List<Vector_Sort>(); vsortList[1] = new List<Vector_Sort>(); vsortList[2] = new List<Vector_Sort>(); int[] id = new int [] { 0, 1, 2, 0, 2, 3, 0, 3, 1 }; Vector3 vert; for (int j = 0; j < 3; j++) { Plane p = new Plane(tetra_Verts[id[3*j]], tetra_Verts[id[3*j+1]], tetra_Verts[id[3*j+2]]); p.D = p.D * 0.999f; Vector_Sort vs; filteredVerts = 0; for (int i = 0; i < aMD_TT_Sleeve.vertices.Count; i++) { vert = aMD_TT_Sleeve.vertices[i]; float res = PlaneHelper.ClassifyPoint(ref vert, ref p); if (res > 0) { filteredVerts++; vs = new Vector_Sort(); vs.vert = vert; vs.vIDX = i; vsortList[j].Add(vs); } } RemoveDuplicates(vsortList[j]); for (int i = 0; i < vsortList[j].Count; i++) { vsortList[j][i].dist = (tetra_Verts[j+1] - vsortList[j][i].vert).magnitude; } var ordered = from element in vsortList[j] orderby element.dist select element; vsortList[j] = ordered.ToList<Vector_Sort>(); } for(int i = 0; i < aMD_TT_Sleeve.vertices.Count; i++) { aMD_TT_Sleeve.vertices[i] = Sphere_Surf(aMD_TT_Sleeve.vertices[i], spheres[2].transform.localPosition); } Plane p2 = new Plane(Vector3.up, 0); int vertCount = aMD_TT_Sleeve.vertices.Count; ArgosMeshDraft amdTemp = new ArgosMeshDraft(); amdTemp.Add(aMD_TT_Sleeve); aMD_TT_Sleeve.FlipTriangles(); aMD_TT_Sleeve.Add(amdTemp); aMD_TT_Sleeve.FlipNormals(); float d; for(int i = 0; i < vertCount; i++)//FLIP { vert = aMD_TT_Sleeve.vertices[i]; d = PlaneHelper.ClassifyPoint(ref vert, ref p2); aMD_TT_Sleeve.vertices[i] = vert - 2f * d * Vector3.up; } List<Vector3> vInnerLower = new List<Vector3>(); List<Vector3> vInnerUpper = new List<Vector3>(); List<Vector3> vPrint = new List<Vector3>(); for (int j = 0; j < 3; j++) { for (int i = 0; i < vsortList[j].Count; i++) { vert = aMD_TT_Sleeve.vertices[vsortList[j][i].vIDX]; //vCurr.y = 0; d = PlaneHelper.ClassifyPoint(ref vert, ref p2); if(j==0) { vPrint.Add(vert - 2f * d * Vector3.up); } vInnerLower.Add(vert); vInnerUpper.Add(vert - 2f * d * Vector3.up); } } aMD_TT_Sleeve.Add(MeshDraft.Band(vInnerUpper, vInnerLower)); aMD_TT_Sleeve.Add(MeshDraft.Band(vInnerLower, vInnerUpper)); Generate_Line_List(vPrint); vSort_Count_0 = vsortList[0].Count; vSort_Count_1 = vsortList[1].Count; vSort_Count_2 = vsortList[2].Count; } bool bwritten = false; void Generate_Line_List(List<Vector3> vPrint) { if (!bwritten) { vPrint.Insert(0, tetra_Verts[1]); vPrint.Add(tetra_Verts[2]); //vPrint[0] = tetra_Verts[1]; //vPrint[vPrint.Count - 1] = tetra_Verts[2]; for (int i = 0; i < vPrint.Count-1; i++) { sLineVectors.Write("new Vector3(" + vPrint[i].x.ToString("F3") + "f, " + vPrint[i].y.ToString("F3") + "f, " + vPrint[i].z.ToString("F3") + "f), " + "new Vector3(" + vPrint[i+1].x.ToString("F3") + "f, " + vPrint[i+1].y.ToString("F3") + "f, " + vPrint[i+1].z.ToString("F3") + "f), "); } Quaternion q; float angle = 120f; Vector3 axis = Vector3.up; q = Quaternion.AngleAxis(angle, axis); Vector3 vRota; Vector3 vRota2; for (int i = 0; i< vPrint.Count-1; i++) { vRota = q * vPrint[i]; vRota2 = q * vPrint[i+1]; sLineVectors.Write("new Vector3(" + vRota.x.ToString("F3") + "f, " + vRota.y.ToString("F3") + "f, " + vRota.z.ToString("F3") + "f), " + "new Vector3(" + vRota2.x.ToString("F3") + "f, " + vRota2.y.ToString("F3") + "f, " + vRota2.z.ToString("F3") + "f), "); } angle = 240; q = Quaternion.AngleAxis(angle, axis); for (int i = 0; i < vPrint.Count - 1; i++) { vRota = q * vPrint[i]; vRota2 = q * vPrint[i + 1]; sLineVectors.Write("new Vector3(" + vRota.x.ToString("F3") + "f, " + vRota.y.ToString("F3") + "f, " + vRota.z.ToString("F3") + "f), " + "new Vector3(" + vRota2.x.ToString("F3") + "f, " + vRota2.y.ToString("F3") + "f, " + vRota2.z.ToString("F3") + "f), "); } /////////////////////////UPPERS////////////////////// List<Vector3> vlUppers = new List<Vector3>(); axis = tetra_Verts[1].normalized; angle = 120; q = Quaternion.AngleAxis(angle, axis); for (int i = 0; i < vPrint.Count - 1; i++) { vRota = q * vPrint[i]; vRota2 = q * vPrint[i + 1]; vlUppers.Add(vRota); vlUppers.Add(vRota2); sLineVectors.Write("new Vector3(" + vRota.x.ToString("F3") + "f, " + vRota.y.ToString("F3") + "f, " + vRota.z.ToString("F3") + "f), " + "new Vector3(" + vRota2.x.ToString("F3") + "f, " + vRota2.y.ToString("F3") + "f, " + vRota2.z.ToString("F3") + "f), "); } axis = Vector3.up; angle = 120; q = Quaternion.AngleAxis(angle, axis); for (int i = 0; i < vlUppers.Count - 1; i++) { vRota = q * vlUppers[i]; vRota2 = q * vlUppers[i + 1]; sLineVectors.Write("new Vector3(" + vRota.x.ToString("F3") + "f, " + vRota.y.ToString("F3") + "f, " + vRota.z.ToString("F3") + "f), " + "new Vector3(" + vRota2.x.ToString("F3") + "f, " + vRota2.y.ToString("F3") + "f, " + vRota2.z.ToString("F3") + "f), "); } angle = 240; q = Quaternion.AngleAxis(angle, axis); for (int i = 0; i < vlUppers.Count - 1; i++) { vRota = q * vlUppers[i]; vRota2 = q * vlUppers[i + 1]; sLineVectors.Write("new Vector3(" + vRota.x.ToString("F3") + "f, " + vRota.y.ToString("F3") + "f, " + vRota.z.ToString("F3") + "f), " + "new Vector3(" + vRota2.x.ToString("F3") + "f, " + vRota2.y.ToString("F3") + "f, " + vRota2.z.ToString("F3") + "f), "); } } sLineVectors.Close(); bwritten = true; } void sleeve(Vector3 v1, Vector3 v2, Vector3 v3, Vector3 sector_Foc) { Vector3 vCurr; //v1.y = v2.y = v3.y = 0; List<Vector3> vInnerLower = new List<Vector3>(); List<Vector3> vInnerUpper = new List<Vector3>(); Vector3 vUp = Vector3.up; Vector3[] vAlpha = new[] { v1, v2, v3 }; Vector3[] vOmega = new[] { v2, v3, v1 }; float t = 0; float dt = 1 / 60f; float d; float el; for (int j = 0; j < 3; j++) { t = 0; for (int i = 0; i < 60; i++) { vCurr = Sphere_Surf(Vector3.Lerp(vAlpha[j], vOmega[j], t), sector_Foc); //vCurr.y = 0; d = vCurr.y; el = Mathf.Sqrt(tetra_Radius * tetra_Radius - d * d); //vInnerLower.Add(vCurr + el*vUp); //vInnerUpper.Add(vCurr - el*vUp); vInnerLower.Add(vCurr); vInnerUpper.Add(vCurr - 2f * d * vUp); t += dt; } } aMD_TT_Sleeve.Add(MeshDraft.Band(vInnerUpper, vInnerLower)); aMD_TT_Sleeve.Add(MeshDraft.Band(vInnerLower, vInnerUpper)); } Vector3[] vTest = new Vector3[1024]; Vector3[] vTest2 = new Vector3[1024]; int i = 0; void subdivide_CarbonLine(Vector3 v1, Vector3 v2, Vector3 v3, int depth, Vector3 sector_Foc, int nID, bool bFlipNorm) { Vector3 v12, v23, v31; Vector3 v12_n, v23_n, v31_n; if (depth == 0) { if (bFlipNorm) { addTriangle_UV_Tag_CarbonLine(v1, v3, v2, (float)nID); } else { //if (nID == 1) //{ // vTest[i] = v1; // vTest2[i] = v2; // i++; //} addTriangle_UV_Tag_CarbonLine(v1, v2, v3, (float)nID); } return; } v12 = (v1 + v2) / 2.0f; v23 = (v2 + v3) / 2.0f; v31 = (v3 + v1) / 2.0f; //v12_n = Sphere_Surf(v12, sector_Foc); //sector_Foc //v23_n = Sphere_Surf(v23, sector_Foc); //v31_n = Sphere_Surf(v31, sector_Foc); v12_n = v12; //sector_Foc v23_n = v23; v31_n = v31; /* recursively subdivide new triangles */ subdivide_CarbonLine(v1, v12_n, v31_n, depth - 1, sector_Foc, 1, bFlipNorm); subdivide_CarbonLine(v12_n, v2, v23_n, depth - 1, sector_Foc, 2, bFlipNorm); subdivide_CarbonLine(v31_n, v23_n, v3, depth - 1, sector_Foc, 3, bFlipNorm); subdivide_CarbonLine(v23_n, v31_n, v12_n, depth - 1, sector_Foc, 4, bFlipNorm); } private void Create_TETRA_TERREAN(int depth) { float scl = scale_TT / 100f; if (ttType == TT_TYPE.SPHERICAL) { subdivide(tetra_Verts[0], tetra_Verts[1], tetra_Verts[2], depth, spheres[0].transform.localPosition, 0, true); subdivide(tetra_Verts[0], tetra_Verts[2], tetra_Verts[3], depth, spheres[1].transform.localPosition, 1, true); subdivide(tetra_Verts[0], tetra_Verts[3], tetra_Verts[1], depth, spheres[3].transform.localPosition, 2, true); subdivide(tetra_Verts[1], tetra_Verts[3], tetra_Verts[2], depth, spheres[2].transform.localPosition, 3, true); //subdivide(tetra_Verts[0], tetra_Verts[1], tetra_Verts[2], depth, spheres[0].transform.localPosition, 0, false);//Inside //subdivide(tetra_Verts[0], tetra_Verts[2], tetra_Verts[3], depth, spheres[1].transform.localPosition, 1, false); //subdivide(tetra_Verts[0], tetra_Verts[3], tetra_Verts[1], depth, spheres[3].transform.localPosition, 2, false); } else if(ttType == TT_TYPE.HYPERBOLIC) { Vector3[] fc = new Vector3[4]; fc[0] = (tetra_Verts[0] + tetra_Verts[1] + tetra_Verts[2]) / 3f; fc[1] = (tetra_Verts[0] + tetra_Verts[2] + tetra_Verts[3]) / 3f; fc[2] = (tetra_Verts[1] + tetra_Verts[3] + tetra_Verts[2]) / 3f; fc[3] = (tetra_Verts[0] + tetra_Verts[3] + tetra_Verts[1]) / 3f; beeS[0] = base_Distance * tetra_Radius * fc[0].normalized; beeS[1] = base_Distance * tetra_Radius * fc[1].normalized; beeS[2] = base_Distance * tetra_Radius * fc[2].normalized; beeS[3] = base_Distance * tetra_Radius * fc[3].normalized; subdivide(tetra_Verts[0], tetra_Verts[1], tetra_Verts[2], depth, fc[0], 0, false); subdivide(tetra_Verts[0], tetra_Verts[2], tetra_Verts[3], depth, fc[1], 1, false); subdivide(tetra_Verts[1], tetra_Verts[3], tetra_Verts[2], depth, fc[2], 2, false); subdivide(tetra_Verts[0], tetra_Verts[3], tetra_Verts[1], depth, fc[3], 3, false); Scale_Radially(); } } private void Scale_Radially() { float ratio = 0; Vector3 v; float fidx; float len; for (int i = 0; i<aMD_TetraTerrean.vertices.Count; i++) { fidx = aMD_TetraTerrean.uv[i].x; ratio = aMD_TetraTerrean.vertices[i].magnitude / tetra_Radius; aMD_TetraTerrean.vertices[i] *= ((smidge * ratio) + (1 - smidge)); } } void subdivide(Vector3 v1, Vector3 v2, Vector3 v3, int depth, Vector3 sector_Foc, int nID, bool bFlipNorm) { Vector3 v12, v23, v31; Vector3 v12_n, v23_n, v31_n; if (depth == 0) { if (ttType == TT_TYPE.SPHERICAL || ttType == TT_TYPE.HYPERBOLIC) { if (bFlipNorm) { addTriangle_UV_Tag(v1, v3, v2, (float)nID); } else { addTriangle_UV_Tag(v1, v2, v3, (float)nID); } } else if (ttType == TT_TYPE.OTHER) { Extrude_1(v1, v2, v3, nID, sector_Foc); } return; } v12 = (v1 + v2) / 2.0f; v23 = (v2 + v3) / 2.0f; v31 = (v3 + v1) / 2.0f; //intrude midpoints if (ttType == TT_TYPE.SPHERICAL) { v12_n = Sphere_Surf(v12, sector_Foc); //sector_Foc v23_n = Sphere_Surf(v23, sector_Foc); v31_n = Sphere_Surf(v31, sector_Foc); } else if(ttType == TT_TYPE.HYPERBOLIC) { v12_n = Hyperbolic(v12, sector_Foc); //sector_Foc v23_n = Hyperbolic(v23, sector_Foc); v31_n = Hyperbolic(v31, sector_Foc); } else if (ttType == TT_TYPE.OTHER) { v12_n = Extrude_1(v12, sector_Foc); //sector_Foc v23_n = Extrude_1(v23, sector_Foc); v31_n = Extrude_1(v31, sector_Foc); } else { v12_n = Vector3.zero; v23_n = Vector3.zero; v31_n = Vector3.zero; } /* recursively subdivide new triangles */ subdivide(v1, v12_n, v31_n, depth - 1, sector_Foc, nID, bFlipNorm); subdivide(v12_n, v2, v23_n, depth - 1, sector_Foc, nID, bFlipNorm); subdivide(v31_n, v23_n, v3, depth - 1, sector_Foc, nID, bFlipNorm); subdivide(v23_n, v31_n, v12_n, depth - 1, sector_Foc, nID, bFlipNorm); } private Vector3 Extrude_1(Vector3 vP0, Vector3 sector_Focus) { Vector3 l = vP0.normalized; Vector3 OminC = -sector_Focus; float rsqr = sphere_Radius * sphere_Radius; float dotLOminC = Vector3.Dot(l, OminC); float Omag = OminC.magnitude; float d = -dotLOminC - Mathf.Sqrt(dotLOminC * dotLOminC - Omag * Omag + sphere_Radius * sphere_Radius); return (l * d); } void addTriangle(Vector3 v0, Vector3 v1, Vector3 v2) { aMD_TetraTerrean.Add(MeshDraft.Triangle(v0, v1, v2)); } void addTriangle_UV_Tag(Vector3 v0, Vector3 v1, Vector3 v2, float uvTag) { if (bSeparate_Faces) { aMD_tt_Faces[(int)uvTag].Add(MeshDraft.Triangl_UV_Tag(v0, v1, v2, uvTag)); } else { aMD_TetraTerrean.Add(MeshDraft.Triangl_UV_Tag(v0, v1, v2, uvTag)); } } void addTriangle_UV_Tag_CarbonLine(Vector3 v0, Vector3 v1, Vector3 v2, float uvTag) { aMD_TT_Sleeve.Add(MeshDraft.Triangl_UV_Tag(v0, v1, v2, uvTag)); } void addTriangle_Skythe(Vector3 v0, Vector3 v1, Vector3 v2, float uvTag) { scythe_MD.Add(MeshDraft.Triangl_UV_Tag(v0, v1, v2, uvTag)); } void addTriangle_UV_Tag_PQUAD(Vector3 v0, Vector3 v1, Vector3 v2, float uvTag) { aMD_PQUAD_TMP.Add(MeshDraft.Triangl_UV_Tag(v0, v1, v2, uvTag)); } public Vector3 GetPointOnBezierCurve(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t) { float u = 1f - t; float t2 = t * t; float u2 = u * u; float u3 = u2 * u; float t3 = t2 * t; Vector3 result = (u3) * p0 + (3f * u2 * t) * p1 + (3f * u * t2) * p2 + (t3) * p3; return result; } /// <image url="$(SolutionDir)\EMB\hyperbole.png" scale="0.45"></image> /// } /// <image url="$(SolutionDir)\EMB\CD.png" scale="0.16803" /> //int countDown = 10; //void Update() // Original //{ // H_Editor_Label.transform.position = tetra_Verts_GO[0].transform.position; // C_Editor_Label.transform.position = transform.position; // Vector3 v = (tetra_Verts_GO[0].transform.localPosition + tetra_Verts_GO[1].transform.localPosition + tetra_Verts_GO[2].transform.localPosition) /3; // I_Editor_Label.transform.position = v + transform.position; // B_Editor_Label.transform.position = transform.position + base_Distance*tetra_Radius*v.normalized; // vCHn = (H_Editor_Label.transform.localPosition - C_Editor_Label.transform.localPosition).normalized; // vIH = (H_Editor_Label.transform.localPosition - I_Editor_Label.transform.localPosition); // vIHn = vIH.normalized; // vT1n = Vector3.Dot(vCHn, vIHn) * vIHn; // vT2n = vCHn; // T1_Editor_Label.transform.localPosition = (vT1n * tangent_Base * tetra_Radius + B_Editor_Label.transform.localPosition); // T2_Editor_Label.transform.localPosition = (H_Editor_Label.transform.localPosition - vT2n * tangent_H * tetra_Radius); // if(frameCount-- == 0 || bPrint_Trace) // { // frameCount = 10; // build_Reference_Hyperbolic_Spline(B_Editor_Label.transform.localPosition, T1_Editor_Label.transform.localPosition, // T2_Editor_Label.transform.localPosition, H_Editor_Label.transform.localPosition, // I_Editor_Label.transform.localPosition); // if(--countDown == 0 || bPrint_Trace) // { // Print_Trace(B_Editor_Label.transform.localPosition, T1_Editor_Label.transform.localPosition, // T2_Editor_Label.transform.localPosition, H_Editor_Label.transform.localPosition, // I_Editor_Label.transform.localPosition); // } // } // bPrint_Trace = false; // aMD_Spheres.Clear(); // aMD_Spheres.Add(MeshDraft.Sphere(sphere_Radius, 36, 32)); // cylinder_MD.Clear(); // Set_Tetra_Verts(tetra_Radius); // float face_dist; // float tetra_Height; // Vector3 face_Norm; // float a, b; // if (sphere_Radius_Last != sphere_Radius) // { // for (int i = 0; i < 4; i++) // { // face_dist = face_Centers[i].magnitude; // tetra_Height = 1.33333f * tetra_Radius; // a = 2 * Mathf.Sqrt(2) / 3; // b = Mathf.Sqrt(sphere_Radius * sphere_Radius - tetra_Radius * tetra_Radius * 8f / 9f); // face_Norm = face_Centers[i].normalized; // spheres[i].transform.localPosition = face_Norm * (tetra_Radius / 3 + b); // spheres[i].transform.localRotation = Quaternion.LookRotation(sphere_pos[i]); // spheres[i].GetComponent<MeshFilter>().mesh = aMD_Spheres.ToMeshInternal(); // tetra_Verts_GO[i].transform.localPosition = tetra_Verts[i]; // } // } // sphere_Radius_Last = sphere_Radius; // tetra_Radius_Last = tetra_Radius; // //if ((sphere_Radius_Last != sphere_Radius || tetra_Radius_Last != tetra_Radius) && bTetraTerrean_On) // //{ // aMD_TetraTerrean.Clear(); // for (int i = 0; i < 4; i++) // { // aMD_tt_Faces[i].Clear(); // } // Create_TETRA_TERREAN(all_Shape_Depth); // if (bSeparate_Faces) // { // for (int i = 0; i < 4; i++) // { // tt_Faces[i].GetComponent<MeshFilter>().mesh = aMD_tt_Faces[i].ToMeshInternal(); // } // } // else // { // TetraTerrien_GO.GetComponent<MeshFilter>().mesh = aMD_TetraTerrean.ToMeshInternal(); // TetraTerrien_GO.GetComponent<MeshFilter>().mesh.RecalculateNormals(60); // } // aMD_TT_Sleeve.Clear(); // Create_TETRA_TERREAN_Sleeve(); // TT_Sleeve_GO.GetComponent<MeshFilter>().mesh = aMD_TT_Sleeve.ToMeshInternal(); // TT_Sleeve_GO.GetComponent<MeshFilter>().mesh.RecalculateNormals(60); // sphere_Radius_Last = sphere_Radius; // tetra_Radius_Last = tetra_Radius; // if (bSpheresON) // { // ShowSpheres(true); // } // else // { // ShowSpheres(false); // } //}
public void OnShow_Differential_Rings() { if (amd == null) { amd = new ArgosMeshDraft(); } else { amd.Clear(); } GetComponent<MeshRenderer>().enabled = true; setColor(orbitColor); List<Vector3> vInnerLower = new List<Vector3>(); List<Vector3> vOuterLower = new List<Vector3>(); List<Vector3> vInnerUpper = new List<Vector3>(); List<Vector3> vOuterUpper = new List<Vector3>(); List<Vector3> vDisk = new List<Vector3>(); float op = Mathf.PI * 2f; float delta_theta = op / 180; float theta = 0; Vector3 vPos_Lower; Vector3 vPos_Upper; Vector3 vNorm; float w_by_2 = cylinder_Width * 0.66666f;//to differentiate from Helix float rad = cylinder_Radius; Vector3 vZero = (cylinder_Offset + cylinder_Height / 2) * Vector3.up; vDisk.Add(vZero); for (int i = 0; i < 180; i++) { vPos_Lower = rad * Mathf.Cos(theta) * Vector3.right + rad * Mathf.Sin(theta) * Vector3.forward; float theta_Mod = theta % (Mathf.PI*2f/3f); float lout = rad; if (theta_Mod < 60) { lout = (1f - 0.5f * theta_Mod / (Mathf.PI/ 3f)); } else { lout = (0.5f + 0.5f * (theta_Mod - (Mathf.PI / 3f)) / (Mathf.PI / 3f)); } vPos_Lower *= lout; vPos_Upper = vPos_Lower; vNorm = vPos_Lower.normalized; vPos_Lower += cylinder_Offset * Vector3.up; vInnerLower.Add(vPos_Lower - w_by_2 * vNorm); vOuterLower.Add(vPos_Lower + w_by_2 * vNorm); vPos_Lower += (cylinder_Height / 2) * Vector3.up; vDisk.Add(vPos_Lower - w_by_2 * vNorm); vPos_Upper += cylinder_Height * Vector3.up + cylinder_Offset * Vector3.up; vInnerUpper.Add(vPos_Upper - w_by_2 * vNorm); vOuterUpper.Add(vPos_Upper + w_by_2 * vNorm); theta += delta_theta; } amd.Add(MeshDraft.Band(vOuterLower, vInnerLower)); amd.Add(MeshDraft.Band(vInnerUpper, vOuterUpper)); amd.Add(MeshDraft.Band(vInnerLower, vInnerUpper)); amd.Add(MeshDraft.Band(vOuterUpper, vOuterLower)); if (bAdd_Disk) { amd.Add(MeshDraft.TriangleFan(vDisk)); } GetComponent<MeshFilter>().mesh = amd.ToMeshInternal(); }