This is my first time posting here and in all honesty I’m relatively new to programming. Aside from that, I have done the run of the mill search the forums, searched google, searched stackoverflow, searched a lot. Gone through tutorials left and right and I’ve been able to come up with some code, with some modification from what’s been posted on the net for procedurally creating an isosphere by subdividing faces etc etc. Got the Collision working just fine and such. I’m stuck at trying to get the UV set up properly. It’s just not clicking, and I’m sure it’s just something simple. Not really wanting to ask for help but I’m just stumped. I usually try to figure things out myself because…well, the information is there. Somewhere, I just can’t find it. Anyways, enough of my rambling. I’m gonna post the code here in it’s entirety and maybe someone smrt enough could let me know what I’m doing wrong. Hell, even some optimizations would be awesome.
Also…thanks for reading and possibly helping. FYI, I don’t get any error’s in Unity but when I run it, the sphere generates with collision and all that but the texture (png format) doesn’t display correctly, the entire thing just shows up grey-ish. It’s supposed to be the moon. (Just temporary until I can figure this out) The file is formated correctly since if I just create a sphere from the GameObject menu it displays like it’s supposed to be. So my UV coding is all screwed up.
This portion of the code is figure out the middle point so it knows where to do it’s thing for the vertices and triangles and all that jazz.
I think the getMiddleUVPoint is where my problem is.
public int getMiddleUVPoint(int v1, int v2, ref List<Vector2> uv, ref Dictionary<long, int> uvcache, float radius){
//first check if it already exists
bool firstUVIsSmaller = v1 < v2;
long smallerUVIndex = firstUVIsSmaller ? v1 : v2;
long greaterUVIndex = firstUVIsSmaller ? v2 : v1;
long UVkey = (smallerUVIndex << 32) + greaterUVIndex;
int UVret;
if (uvcache.TryGetValue (UVkey, out UVret)){
return UVret;
}
//not in uvcache, then calculate
Vector2 UVpoint1 = uv[v1];
Vector2 UVpoint2 = uv[v2];
Vector2 UVmiddle = new Vector2((UVpoint1.x + UVpoint2.x) / 2f,
(UVpoint1.y + UVpoint2.y) / 2f);
//add UV
int UVi = uv.Count;
uv.Add (UVmiddle.normalized * radius);
//store it
uvcache.Add (UVkey, UVi);
return UVi;
/*
Vector2 tempVector = new Vector2();
tempVector = ((v2-v1) * 0.5) + v1;
return tempVector;
*/
}
// return index of point in the middle of p1 and p2
public int getMiddlePoint(int p1, int p2, ref List<Vector3> vertices, ref Dictionary<long, int> cache, float radius){
// first check if we have it already
//Debug.Log ("getMiddlePoint is called");
bool firstIsSmaller = p1 < p2;
long smallerIndex = firstIsSmaller ? p1 : p2;
long greaterIndex = firstIsSmaller ? p2 : p1;
long key = (smallerIndex << 32) + greaterIndex;
int ret;
if (cache.TryGetValue(key, out ret)){
return ret;
}
// not in cache, calculate it
//Debug.Log ("Calculating middle vertice");
Vector3 point1 = vertices[p1];
Vector3 point2 = vertices[p2];
Vector3 middle = new Vector3((point1.x + point2.x) / 2f,
(point1.y + point2.y) / 2f,
(point1.z + point2.z) / 2f);
// add vertex makes sure point is on unit sphere
int i = vertices.Count;
vertices.Add( middle.normalized * radius );
// store it, return index
cache.Add(key, i);
return i;
}
Self explanatory
public struct TriangleIndices{
public int v1;
public int v2;
public int v3;
public TriangleIndices(int v1, int v2, int v3){
this.v1 = v1;
this.v2 = v2;
this.v3 = v3;
}
}
Start code…doesn’t have anything really
public void Start(){
//Debug.Log ("Start() initialized");
Create ();
}
These are put in the beginning just so I can change them on the fly…
public int rLevel = 3;
public float rad = 200f;
This is the meat of the code, it’s not entirely well organized and I will fix that once I get past this extremely annoying part.
public void Create(){
//Debug.Log ("Creating ISOSPHERE");
GameObject gameObject;
Material mat;
gameObject = new GameObject();
gameObject.AddComponent ("MeshRenderer");
MeshFilter filter = gameObject.AddComponent<MeshFilter>();
MeshCollider col = gameObject.AddComponent<MeshCollider>();
Mesh mesh = filter.mesh;
mesh.Clear();
List<Vector3> vertList = new List<Vector3>();
Dictionary<long, int> middlePointIndexCache = new Dictionary<long, int>();
//int index = 0;
int recursionLevel = rLevel;
float radius = rad;
// create 12 vertices of a icosahedron
float t = (1f + Mathf.Sqrt(5f)) / 2f;
//Debug.Log ("Creating vertList");
vertList.Add(new Vector3(-1f, t, 0f).normalized * radius);
vertList.Add(new Vector3( 1f, t, 0f).normalized * radius);
vertList.Add(new Vector3(-1f, -t, 0f).normalized * radius);
vertList.Add(new Vector3( 1f, -t, 0f).normalized * radius);
vertList.Add(new Vector3( 0f, -1f, t).normalized * radius);
vertList.Add(new Vector3( 0f, 1f, t).normalized * radius);
vertList.Add(new Vector3( 0f, -1f, -t).normalized * radius);
vertList.Add(new Vector3( 0f, 1f, -t).normalized * radius);
vertList.Add(new Vector3( t, 0f, -1f).normalized * radius);
vertList.Add(new Vector3( t, 0f, 1f).normalized * radius);
vertList.Add(new Vector3(-t, 0f, -1f).normalized * radius);
vertList.Add(new Vector3(-t, 0f, 1f).normalized * radius);
//Debug.Log ("vertList complete");
// create 20 triangles of the icosahedron
List<TriangleIndices> faces = new List<TriangleIndices>();
//Debug.Log ("Creating triangle faces");
// 5 faces around point 0
faces.Add(new TriangleIndices(0, 11, 5));
faces.Add(new TriangleIndices(0, 5, 1));
faces.Add(new TriangleIndices(0, 1, 7));
faces.Add(new TriangleIndices(0, 7, 10));
faces.Add(new TriangleIndices(0, 10, 11));
// 5 adjacent faces
faces.Add(new TriangleIndices(1, 5, 9));
faces.Add(new TriangleIndices(5, 11, 4));
faces.Add(new TriangleIndices(11, 10, 2));
faces.Add(new TriangleIndices(10, 7, 6));
faces.Add(new TriangleIndices(7, 1, 8));
// 5 faces around point 3
faces.Add(new TriangleIndices(3, 9, 4));
faces.Add(new TriangleIndices(3, 4, 2));
faces.Add(new TriangleIndices(3, 2, 6));
faces.Add(new TriangleIndices(3, 6, 8));
faces.Add(new TriangleIndices(3, 8, 9));
// 5 adjacent faces
faces.Add(new TriangleIndices(4, 9, 5));
faces.Add(new TriangleIndices(2, 4, 11));
faces.Add(new TriangleIndices(6, 2, 10));
faces.Add(new TriangleIndices(8, 6, 7));
faces.Add(new TriangleIndices(9, 8, 1));
//Debug.Log ("Triangle faces complete");
// refine triangles
//Debug.Log ("Refining triangles");
for (int i = 0; i < recursionLevel; i++){
List<TriangleIndices> faces2 = new List<TriangleIndices>();
foreach (var tri in faces){
// replace triangle by 4 triangles
//Debug.Log ("Replacing triangle by 4 triangles");
int a = getMiddlePoint(tri.v1, tri.v2, ref vertList, ref middlePointIndexCache, radius);
int b = getMiddlePoint(tri.v2, tri.v3, ref vertList, ref middlePointIndexCache, radius);
int c = getMiddlePoint(tri.v3, tri.v1, ref vertList, ref middlePointIndexCache, radius);
faces2.Add(new TriangleIndices(tri.v1, a, c));
faces2.Add(new TriangleIndices(tri.v2, b, a));
faces2.Add(new TriangleIndices(tri.v3, c, b));
faces2.Add(new TriangleIndices(a, b, c));
}
faces = faces2;
}
List<int> triList = new List<int>();
//Debug.Log ("Creating triList");
for( int i = 0; i < faces.Count; i++ ){
triList.Add( faces[i].v1 );
triList.Add( faces[i].v2 );
triList.Add( faces[i].v3 );
}
//Creating the UV list
float w = 5.5f;
float h = 3f;
//Creating the 22 Points for UV
List<Vector2> UVPoints = new List<Vector2>();
Dictionary<long, int> middleUVPointIndexCache = new Dictionary<long, int>();
UVPoints.Add(new Vector2(0.5f / w, 0));
UVPoints.Add(new Vector2(1.5f / w, 0));
UVPoints.Add(new Vector2(2.5f / w, 0));
UVPoints.Add(new Vector2(3.5f / w, 0));
UVPoints.Add(new Vector2(4.5f / w, 0));
UVPoints.Add(new Vector2(0 , 1 / h));
UVPoints.Add(new Vector2(1f / w, 1 / h));
UVPoints.Add(new Vector2(2f / w, 1 / h));
UVPoints.Add(new Vector2(3f / w, 1 / h));
UVPoints.Add(new Vector2(4f / w, 1 / h));
UVPoints.Add(new Vector2(5f / w, 1 / h));
UVPoints.Add(new Vector2(0.5f / w, 2 / h));
UVPoints.Add(new Vector2(1.5f / w, 2 / h));
UVPoints.Add(new Vector2(2.5f / w, 2 / h));
UVPoints.Add(new Vector2(3.5f / w, 2 / h));
UVPoints.Add(new Vector2(4.5f / w, 2 / h));
UVPoints.Add(new Vector2(1, 2 / h));
UVPoints.Add(new Vector2(1f / w, 1));
UVPoints.Add(new Vector2(2f / w, 1));
UVPoints.Add(new Vector2(3f / w, 1));
UVPoints.Add(new Vector2(4f / w, 1));
UVPoints.Add(new Vector2(5f / w, 1));
//Creating the UV faces with the UV points
List<TriangleIndices> UVfaces = new List<TriangleIndices>();
//first row
UVfaces.Add(new TriangleIndices(0, 5, 6));
UVfaces.Add(new TriangleIndices(1, 6, 7));
UVfaces.Add(new TriangleIndices(2, 7, 8));
UVfaces.Add(new TriangleIndices(3, 8, 9));
UVfaces.Add(new TriangleIndices(4, 9, 10));
//second row
UVfaces.Add(new TriangleIndices( 7, 6, 12));
UVfaces.Add(new TriangleIndices( 6, 5, 11));
UVfaces.Add(new TriangleIndices(10, 9, 15));
UVfaces.Add(new TriangleIndices( 9, 8, 14));
UVfaces.Add(new TriangleIndices( 8, 7, 13));
//fourth row
UVfaces.Add(new TriangleIndices(17, 12, 11));
UVfaces.Add(new TriangleIndices(21, 16, 15));
UVfaces.Add(new TriangleIndices(20, 15, 14));
UVfaces.Add(new TriangleIndices(19, 14, 13));
UVfaces.Add(new TriangleIndices(18, 13, 12));
//third row
UVfaces.Add(new TriangleIndices(11, 12, 6));
UVfaces.Add(new TriangleIndices(15, 16, 10));
UVfaces.Add(new TriangleIndices(14, 15, 9));
UVfaces.Add(new TriangleIndices(13, 14, 8));
UVfaces.Add(new TriangleIndices(12, 13, 7));
for (int UVi = 0; UVi < recursionLevel; UVi++){
List<TriangleIndices> UVfaces2 = new List<TriangleIndices>();
foreach (var tri in UVfaces){
// replace triangle by 4 triangles
//Debug.Log ("Replacing triangle by 4 triangles");
int a = getMiddleUVPoint(tri.v1, tri.v2, ref UVPoints, ref middleUVPointIndexCache, radius);
int b = getMiddleUVPoint(tri.v2, tri.v3, ref UVPoints, ref middleUVPointIndexCache, radius);
int c = getMiddleUVPoint(tri.v3, tri.v1, ref UVPoints, ref middleUVPointIndexCache, radius);
UVfaces2.Add(new TriangleIndices(tri.v1, a, c));
UVfaces2.Add(new TriangleIndices(tri.v2, b, a));
UVfaces2.Add(new TriangleIndices(tri.v3, c, b));
UVfaces2.Add(new TriangleIndices(a, b, c));
}
UVfaces = UVfaces2;
}
/*
int nVertices = mesh.vertices.Length;
Vector2[] UVs = new Vector2[nVertices];
//Debug.Log ("Creating UVs");
for(int i= 0; i < nVertices; i++){
UVs[i] = mesh.vertices[i];
}
*/
Vector3[] normales = new Vector3[vertList.Count];
//Debug.Log ("Creating normales");
for(int i = 0; i < normales.Length; i++){
normales[i] = vertList[i].normalized;
}
mat = Resources.Load("Material/Moon") as Material;
if(mat == null)
Debug.Log ("No material found");
mesh.vertices = vertList.ToArray();
mesh.triangles = triList.ToArray();
//mesh.uv = UVs;
mesh.normals = normales;
col.sharedMesh = null;
col.sharedMesh = mesh;
mesh.RecalculateBounds();
mesh.RecalculateNormals ();
gameObject.renderer.material = mat;
mesh.Optimize();
//Debug.Log ("Completed ISOSPHERE");
}
The whole nVertices and UV portion that’s commented out doesn’t give me any errors and the material/texture displays exactly the same as the stuff I put in there. Basically what I found is that I have to subdivide the UVs since thats what happens to the verts/faces/triangles. The UV is pretty much the only part I’m currently stuck at. Any help would greatly be appreciated and yes. Again, I did search…with the magical search function on here and Google. A couple of helpful pages popped up…which is how I got this far. I realize that the posted code is out of order but I wanted to break it up some. The public int and float for recursion and radius are at the beginning followed by the static triangleindices, then the getMiddlePoint stuff, followed by start() and then the create().