List<Vector3> pts_catesian = new List<Vector3>(); void sphere_fibonacci_build_cartesian(int num) { //pts_cartesian = new Vector3[num]; float rnd = Random.Range(0, 1) * num; //not sure why they rand here? -- which jacks with phi float offset = 2.0f / num; float increment = Mathf.PI * (3 - Mathf.Sqrt(5.0f)); for (int i = 0; i < num; i++) { float y = (i * offset) - 1 + (offset / 2.0f); float r = Mathf.Sqrt(1 - Mathf.Pow(y, 2)); float phi = ((i + rnd) % num) * increment; float x = Mathf.Cos(phi) * r; float z = Mathf.Sin(phi) * r; pts_catesian.Add(new Vector3(x, y, z)); } }
Verify 3
Verify 2
Verify 1
in Cosahedra.cs
using UnityEngine; using System.Collections; using ProceduralToolkit; using UnityEngine.UI; using System.Collections.Generic; using System.IO; public class Cosahedra : MonoBehaviour { public Text NumTrisText; public float m_fRadius = 1.5f; public ArgosMeshDraft aMD = new ArgosMeshDraft(); public ArgosMeshDraft aMD_IcosaSphere = new ArgosMeshDraft(); MeshDraft mD_Tri = new MeshDraft(); public GameObject hexPreFab; public float m_fFact = 1; // force Multiplier StreamWriter sWrite; public int depth = 3; bool bSimulateForces = false; public enum ICO_Type { HEX, TRIANGLE, ICO_TREE_GENERATOR, }; public ICO_Type icoType; public class GO_Tracker { public GameObject go; public ArgVert aVNode; } public List<GO_Tracker> lstHex_GO = new List<GO_Tracker>(); void Start () { sWrite = new StreamWriter("Argos_ICO_Tree_Hex_Construction.txt"); aMD.Clear(); aMD.Add(MeshDraft.Icosahedron(m_fRadius)); aMD_IcosaSphere.Clear(); Create_GP(depth); Vector3 vApex = new Vector3(0.0f, 5.0f, 0.0f); Quaternion q; Vector3 vN_In; for(int i = 0; i<aMD_IcosaSphere.icoPointCloud.Count-1;i++) { vN_In = aMD_IcosaSphere.icoPointCloud[i].vPos.normalized; q = Quaternion.LookRotation(vN_In); int lev0, lev1, lev2, lev3; GameObject gO; GO_Tracker gT; gO = (GameObject)Instantiate(hexPreFab, aMD_IcosaSphere.icoPointCloud[i].vPos, q); gT = new GO_Tracker(); gT.go = gO; gT.aVNode = aMD_IcosaSphere.icoPointCloud[i]; lstHex_GO.Add(gT); lev3 = aMD_IcosaSphere.icoPointCloud[i].itn.nodePath; lev0 = lev3 >> 6; lev1 = lev3 >> 4 & 3; lev2 = lev3 >> 2 & 3; lev3 = lev3 & 3; //lstHex_GO[lstHex_GO.Count - 1].go.GetComponentInChildren<Text>().text = lev0.ToString() + lev1.ToString() + lev2.ToString() + lev3.ToString(); lstHex_GO[lstHex_GO.Count - 1].go.GetComponentInChildren<Text>().text = i.ToString(); } foreach (GO_Tracker gActedUpon in lstHex_GO) { gActedUpon.go.transform.position = gActedUpon.aVNode.vPos; } aMD_IcosaSphere.FlipNormals(); GetComponent<MeshFilter>().mesh = aMD_IcosaSphere.ToMesh(); } public void ArgosVoronoi(bool bDoNeighbors) { Vector3 vForce; Vector3 vAccumForce; float dist_sqd; float fMag = 0; float delta = 0.05f; foreach (GO_Tracker gActedUpon in lstHex_GO) { vAccumForce = Vector3.zero; foreach (GO_Tracker gPushing in lstHex_GO) { if (gActedUpon != gPushing) { vForce = gActedUpon.aVNode.vPos - gPushing.aVNode.vPos; dist_sqd = vForce.x * vForce.x + vForce.y * vForce.y + vForce.z * vForce.z; vAccumForce += vForce.normalized / dist_sqd; if (bDoNeighbors) { gActedUpon.aVNode.insNeighbor_One_Shot(dist_sqd, gPushing.aVNode); } } } fMag = vAccumForce.magnitude; vAccumForce = vAccumForce.normalized; gActedUpon.aVNode.vForce = 100f * vAccumForce; gActedUpon.aVNode.vPos += gActedUpon.aVNode.vForce * (delta * delta); gActedUpon.aVNode.vPos = gActedUpon.aVNode.vPos.normalized; gActedUpon.aVNode.vPos *= m_fRadius; } } public void OnStartButtonDown() { bSimulateForces = true; } public void OnStopButtonDown() { ArgosVoronoi(true); bSimulateForces = false; List<ArgVert> aVL = aMD_IcosaSphere.icoPointCloud; for (int i = 0; i < aMD_IcosaSphere.icoPointCloud.Count - 1; i++) { sWrite.WriteLine(i.ToString() + "| N0 = " + aVL[i].avNeigbor[0].aV.idx.ToString() + " d = " + Mathf.Sqrt(aVL[i].avNeigbor[0].distFrom).ToString("F4") + " N1 = " + aVL[i].avNeigbor[1].aV.idx.ToString() + " d = " + Mathf.Sqrt(aVL[i].avNeigbor[1].distFrom).ToString("F4") + " N2 = " + aVL[i].avNeigbor[2].aV.idx.ToString() + " d = " + Mathf.Sqrt(aVL[i].avNeigbor[2].distFrom).ToString("F4") + " N3 = " + aVL[i].avNeigbor[3].aV.idx.ToString() + " d = " + Mathf.Sqrt(aVL[i].avNeigbor[3].distFrom).ToString("F4") + " N4 = " + aVL[i].avNeigbor[4].aV.idx.ToString() + " d = " + Mathf.Sqrt(aVL[i].avNeigbor[4].distFrom).ToString("F4") + " N5 = " + aVL[i].avNeigbor[5].aV.idx.ToString() + " d = " + Mathf.Sqrt(aVL[i].avNeigbor[5].distFrom).ToString("F4") + " v = " + aVL[i].vPos.ToString("F3") ); } sWrite.Close(); } void Update () { if (bSimulateForces) { ArgosVoronoi(false); foreach (GO_Tracker gActedUpon in lstHex_GO) { gActedUpon.go.transform.position = gActedUpon.aVNode.vPos; } } } void OnApplicationQuit() { //sWrite.Close(); } void Create_GP(int depth) { for(int i = 0; i<20; i++) { Vector3 v0 = aMD.vertices[aMD.triangles[i*3]]; Vector3 v1 = aMD.vertices[aMD.triangles[i*3 +1]]; Vector3 v2 = aMD.vertices[aMD.triangles[i*3 + 2]]; Color col = getWhite(); subdivide(v0, v1, v2, depth, col,i,0); } } int ITG_idx = 0; void subdivide(Vector3 v1, Vector3 v2, Vector3 v3, int depth, Color col,int sector, int nID) { Vector3 v12, v23, v31; Vector3 v12_n, v23_n, v31_n; int i; if (depth == 0) { if (icoType == ICO_Type.HEX) { addHex(v1, v2, v3, col); } else if(icoType == ICO_Type.TRIANGLE) { addTriangle(v1, v2, v3, col); } else if(icoType == ICO_Type.ICO_TREE_GENERATOR) { addITG_Node(v1, v2, v3, sector, nID, ITG_idx); ITG_idx++; } return; } v12 = (v1 + v2) / 2.0f; v23 = (v2 + v3) / 2.0f; v31 = (v3 + v1) / 2.0f; /* extrude midpoints to lie on unit sphere */ v12_n = v12.normalized * m_fRadius; v23_n = v23.normalized * m_fRadius; v31_n = v31.normalized * m_fRadius; int shifter = nID; shifter = shifter << 2; /* recursively subdivide new triangles */ subdivide(v1, v12_n, v31_n, depth - 1, col, sector, shifter | 0); subdivide(v12_n, v2, v23_n, depth - 1, col, sector, shifter | 1); subdivide(v31_n, v23_n, v3, depth - 1, col, sector, shifter | 2); subdivide(v23_n, v31_n, v12_n, depth - 1, col, sector, shifter | 3); } void addITG_Node(Vector3 v0, Vector3 v1, Vector3 v2,int Sector, int nID, int id) { mD_Tri = MeshDraft.Triangle(v0, v1, v2); aMD_IcosaSphere.Add_ITN_Node(mD_Tri, Sector, nID, id); } void addTriangle(Vector3 v0, Vector3 v1, Vector3 v2, Color col) { mD_Tri.Clear(); mD_Tri = MeshDraft.Triangle(v0, v1, v2); mD_Tri.Paint(col); aMD_IcosaSphere.AddTriQual(mD_Tri); } void addHex(Vector3 v0, Vector3 v1, Vector3 v2, Color col) { mD_Tri.Clear(); mD_Tri = MeshDraft.Triangle(v0, v1, v2); mD_Tri.Paint(col); aMD_IcosaSphere.AddHex(mD_Tri); } public void writeMesh() { GetComponent<MeshFilter>().mesh = aMD_IcosaSphere.ToMesh(); } public ArgosMeshDraft getArgosMeshDraft() { return aMD_IcosaSphere; } Color getIDXolor(int i) { Color col; col.r = 0.2f + (float)(i) * 0.8f / 20f ; col.g = 0.5f + (float)(i) * 0.5f / 20f; col.b = 1f - (float)(i) * 0.8f / 20f; col.a = 1f; return col; } Color getWhite() // :) { Color col; col.r = 1f; col.g = 1f; col.b = 1f; col.a = 1f; return col; } Color getINColor(int i) { Color col; col.r = (float)(i) / 1024f; col.g = 1f - (float)(i) / 1024f; col.b = 0.5f - (float)(i) / 1024f; if(col.b>0) col.b = 1f- (float)(i) / 1024f; col.a = 1f; return col; } }
in ArgosMeshDraft.cs
public class ICO_Tree_Node_ID { public int sector; // 20 sectors to ICO public int nodePath; // 2 bits per depth level } public class ArgVert { public Vector3 vPos; public ICO_Tree_Node_ID itn = new ICO_Tree_Node_ID(); public float dist; public Vector3 vForce; //constrain position to sphere radius public Vector3 vVel; public float maxDistToNeighbor = 0; public float minDistToNeighbor = float.MaxValue; public int idx; public class NB { public ArgVert aV; public float distFrom; public NB() { aV = null; distFrom = float.MaxValue; } } public List<NB> avNeigbor = new List<NB>(); public ArgVert() { for (int i = 0; i < 6; i++) { avNeigbor.Add(new NB()); avNeigbor[i].aV = this; } } public float getMaxDistToNeighbor() { maxDistToNeighbor = 0; for (int i = 0; i < 6; i++) { if (avNeigbor[i].distFrom > maxDistToNeighbor) { maxDistToNeighbor = avNeigbor[i].distFrom; } } return maxDistToNeighbor; } public float getMinDistToNeighbor() { minDistToNeighbor = float.MaxValue; for (int i = 0; i < 6; i++) { if (avNeigbor[i].distFrom < minDistToNeighbor) { minDistToNeighbor = avNeigbor[i].distFrom; } } return minDistToNeighbor; } public bool isAVinNeighborList(ArgVert aV) { for (int i = 0; i < 6; i++) { if (avNeigbor[i].aV == aV) return true; } return false; } public int isLessThan(float dist) { for (int i = 0; i < 6; i++) { if (dist < avNeigbor[i].distFrom) return i; } return -1; } public bool goesHere(int i, float dist, ArgVert aV_Contender) { if (dist < avNeigbor[i].distFrom) { NB nb = new NB(); nb.aV = aV_Contender; nb.distFrom = dist; avNeigbor.Insert(i, nb); avNeigbor.RemoveAt(6); return true; } return false; } public void insNeighbor_One_Shot(float dist, ArgVert aV_Contender) { for (int i = 0; i < 6; i++) { if (goesHere(i, dist, aV_Contender)) return; } } } public class ArgosMeshDraft : MeshDraft { public List<Vector3> vTriCenter = new List<Vector3>(); public List<int> vQual = new List<int>(); public List<ArgVert> icoPointCloud = new List<ArgVert>(); public ArgosMeshDraft() : base() { } public void Add_ITN_Node(MeshDraft tri, int sector, int nodePath, int ITG_idx) { Vector3 vC = (tri.vertices[0] + tri.vertices[1] + tri.vertices[2]) / 3f; ArgVert aV = new ArgVert(); aV.vPos = vC; aV.itn.sector = sector; aV.itn.nodePath = nodePath; aV.idx = ITG_idx; icoPointCloud.Add(aV); } public void SetSortDist(Vector3 Apex) { foreach (ArgVert aV in icoPointCloud) { aV.dist = (aV.vPos - Apex).magnitude; } } public void sortPointCloud() { icoPointCloud.Sort((x, y) => x.dist.CompareTo(y.dist)); } public void AddTriQual(MeshDraft tri) { Vector3 vC = (tri.vertices[0] + tri.vertices[1] + tri.vertices[2]) / 3f; int qual = TriQual.UNDEFINED; Add(tri); for (int i = 0; i < 3; i++)//Track the quality of the triangle UVs { vTriCenter.Add(vC); vQual.Add(qual); } } public void AddHex(MeshDraft tri)//from triangle see: http://argos.vu/wp-content/uploads/2016/04/HCs-1.png { Vector3 HC = (tri.vertices[0] + tri.vertices[1] + tri.vertices[2]) / 3f; Vector3 H0 = (tri.vertices[1] + tri.vertices[0]) / 2f; Vector3 H1 = (tri.vertices[1] + HC) / 2f; Vector3 H2 = (tri.vertices[2] + tri.vertices[1]) / 2f; Vector3 H3 = (tri.vertices[2] + HC) / 2f; Vector3 H4 = (tri.vertices[0] + tri.vertices[2]) / 2f; Vector3 H5 = (tri.vertices[0] + HC) / 2f; List<Vector3> vL = new List<Vector3>(8) { HC, H0, H1, H2, H3, H4, H5, H0 }; List<Vector2> uvMapL = new List<Vector2>(8) { new Vector2(0.5f, 0.5f), new Vector2(0.5f, 1f), new Vector2(1, 0.75f), new Vector2(1, 0.25f), new Vector2(0.5f, 0), new Vector2(0, 0.25f), new Vector2(0, 0.75f), new Vector2(0.5f, 1f) }; Add(HexFan(vL, uvMapL)); } public void AddTriQual(MeshDraft tri, int qual) { Vector3 vC = (tri.vertices[0] + tri.vertices[1] + tri.vertices[2]) / 3f; Add(tri); for (int i = 0; i < 3; i++)//Track the quality of the triangle UVs { vTriCenter.Add(vC); vQual.Add(qual); } } } }