Unity Native Spline
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 }
Wave Fields WR
https://youtu.be/ziarrVCK0G4
https://youtu.be/oTNI8hpWUrw
FOCUS ANDROID DEBUG BRIDGE QUICK TIPS
CODE REFERENCE
SPHERE EXPANDER – FROM Fundamental Flower
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); // } //}
Unexpected Result
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(); }
MultiVerse – Electric Universe Introduction
plasma discharge in laboratory
The are three types of mode of electrified plasma.
1, Dark Mode when the voltage is low so we don’t see anything but can still measure it (I though prefer to call it ‘invisible mode’ to differentiate from mystical substances like dark matter which can’t be in any way be detected or measured), just like radio waves which are not seen.
2, Glow Mode when there is an increase in power and we start to see it, like in a fluorescent tube.
3, When there is even more power and it arcs, like a lighting bolt or the surface of the sun as a arcing plasmoid. This is clearly seen in bipolar nebular with the Z-Pinch clearly in effect by constricting the ionized gas and then making it glow.
It was reported and confirmed this week that the mainstream scientific community are as much in the dark as they have ever been. So once again we must ask, is this more evidence of ignorance in the main stream because they have been blinded by quasi religious doctrine and tenet?
To me this is probably the reason for most, which means that they should be just sacked without delay so they can give up on science, go back to school and learn some physics.
&
As we see from the video the crater at the top looks like it has dendritic ridges in the crater walls and is similar to one on mars but without the whole underneath.
I have shown this before but that was a while ago now, so is worth a look if you haven’t seen it yet. Even though it goes with the traditional estimation as to when it was built, the importance of this is the construction.
I haven’t touched on this for a while so in light of our electrically active earth environment and the amount of metal particulates in chemtrails that are being pumped into the atmosphere, I think we should once again remind ourselves of the phenomena. I like the report @ 07:55 because it happened at a live sports event and was commented on.
Because of the size of their own self importance this wouldn’t even occur to them because apart from being able to do some complicated sums and spout unproven doctrine, there really isn’t too much else there. Personally I couldn’t watch much of the following video (about 15 mins) because I have heard it all before and it’s the same poor guess fiction and so is pointless and a waist of time in my life.