Great conversation last week.
Great conversation last week.
It was great to meet up on Skype today.
Here are a few references from the conversation:
Hopf fibration
24,000 cycle – Esoteric
Also find included, some info on the Solvay Conferences – (wanted to check it out)
Have a great week, I’ll touch base over the weekend.
🙂
/dj
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);
// }
//}