using System.Collections.Generic; using UnityEngine; public class mengersponge : MonoBehaviour { private class Cube { //cube is defined by center point (left lower point) and three directions private Vector3 center; private Vector3 xdir; private Vector3 ydir; private Vector3 zdir; private Vector3[] vertices; private Vector3[] normals; private int[] triangles; public void generate(Vector3 c, Vector3 x, Vector3 y, Vector3 z) { center = c; xdir = x; ydir = y; zdir = z; vertices = gen_vertices(); normals = gen_normals(); triangles = gen_triangles(); } public static Cube[] compute_children (Cube[] fathercubes) { //count total children (waste of computing power...) int kiddoes = 0; foreach (Cube v in fathercubes) { //compute children Cube[] chld = v.gen_children(); kiddoes += chld.Length; } Cube[] children = new Cube[kiddoes]; //merge childrenarr int childno = 0; for (int i = 0; i < fathercubes.Length; i++) { Cube[] chld = fathercubes[i].gen_children(); foreach (Cube v in chld) { children[childno] = v; childno++; } } return children; } public Cube[] gen_children () { bool[,,] want = new bool[3,3,3]; //subdivision tensor: true means we generate it for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { for (int z = 0; z < 3; z++) { want[x,y,z] = true; } } } want[1,1,1] = false; want[0,1,1] = false; want[1,1,0] = false; want[1,0,1] = false; want[2,1,1] = false; want[1,1,2] = false; want[1,2,1] = false; //division: division.length tells me how to subdivide each line, division[2] true tells me i return this cube, false not return this cube int cubesnumber = 0; for (int i = 0; i < want.GetLength(0); i++) { for (int j = 0; j < want.GetLength(1); j++) { for (int k = 0; k < want.GetLength(2); k++) { if (want[i,j,k]) cubesnumber++; } } } Cube[] children = new Cube[cubesnumber]; int indx =0; float test = want.GetLength(0); float xlength = (1f/ want.GetLength(0)); float ylength = (1f/ want.GetLength(1)); float zlength = (1f/ want.GetLength(2)); for (int i = 0; i < want.GetLength(0); i++) { for (int j = 0; j < want.GetLength(1); j++) { for (int k = 0; k < want.GetLength(2); k++) { if (want[i,j,k]) { children[indx] = new Cube(); Vector3 child_center = center + xlength*i*xdir+ylength*j*ydir+zlength*k*zdir; Vector3 child_xdir = xlength*xdir; Vector3 child_ydir = ylength*ydir; Vector3 child_zdir = zlength*zdir; children[indx].generate(child_center,child_xdir,child_ydir,child_zdir); indx++; } } } } return children; } public Mesh GetMesh() { Mesh mesh = new Mesh(); mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; mesh.vertices = vertices; mesh.triangles = triangles; mesh.normals = normals; //random colors Color[] colors = new Color[mesh.vertices.Length]; Vector2[] uv = new Vector2[mesh.vertices.Length]; for (int i = 0; i < mesh.vertices.Length; i++) { float red = Vector3.Angle(vertices[i],Vector3.right)/180; float green = Vector3.Angle(vertices[i],Vector3.up)/180; float blue = Vector3.Angle(vertices[i],Vector3.forward)/180; colors[i] = new Color(red,green,blue,1); uv[i] = new Vector2(0.5f, 0.5f); /* colors[i] = new Color( Random.Range(0f, 1f), Random.Range(0f, 1f), Random.Range(0f, 1f) //0f,1f,0f );*/ } mesh.colors = colors; mesh.uv = uv; mesh.RecalculateNormals(); mesh.RecalculateBounds(); return mesh; } private Vector3[] gen_normals () { //computes the normals to each vertex of the cube, //this is not the real normal, just a rough approximation Vector3 midpoint = (center+xdir+zdir)/2f; Vector3[] normals = new Vector3[8]; //new Vector3 (0, 0, 0), normals[0] = center-midpoint; //new Vector3 (1, 0, 0), normals[1] = center+xdir-midpoint; //new Vector3 (1, 1, 0), normals[2] = center+xdir+ydir-midpoint; //new Vector3 (0, 1, 0), normals[3] = center+ydir-midpoint; //new Vector3 (0, 1, 1), normals[4] = center+ydir+zdir-midpoint; //new Vector3 (1, 1, 1), normals[5] = center+xdir+ydir+zdir-midpoint; //new Vector3 (1, 0, 1), normals[6] = center+xdir+zdir-midpoint; //new Vector3 (0, 0, 1), normals[7] = center+zdir-midpoint; return normals; } private Vector3[] gen_vertices () { //computes the vertices of the cube Vector3[] vertices = new Vector3[8]; //new Vector3 (0, 0, 0), vertices[0] = center; //new Vector3 (1, 0, 0), vertices[1] = center+xdir; //new Vector3 (1, 1, 0), vertices[2] = center+xdir+ydir; //new Vector3 (0, 1, 0), vertices[3] = center+ydir; //new Vector3 (0, 1, 1), vertices[4] = center+ydir+zdir; //new Vector3 (1, 1, 1), vertices[5] = center+xdir+ydir+zdir; //new Vector3 (1, 0, 1), vertices[6] = center+xdir+zdir; //new Vector3 (0, 0, 1), vertices[7] = center+zdir; return vertices; } private int[] gen_triangles () { //computes the triangles of the cube int[] triangles = { 0, 2, 1, //face front 0, 3, 2, 2, 3, 4, //face top 2, 4, 5, 1, 2, 5, //face right 1, 5, 6, 0, 7, 4, //face left 0, 4, 3, 5, 4, 7, //face back 5, 7, 6, 0, 6, 7, //face bottom 0, 1, 6 }; return triangles; } } private MeshFilter filter; private MeshCollider collider; public int sponge_iterations = 2; public int max_sponge_iterations = 4; List cubes = new List(); // Use this for initialization void Start () { filter = GetComponent(); collider = GetComponent(); generate_cubes(); //generates cubes up to degree sponge_iterations filter.mesh =getCubemeshs(sponge_iterations); collider.sharedMesh = filter.mesh; } // Update is called once per frame void FixedUpdate () { OVRInput.Update(); if (OVRInput.GetDown(OVRInput.Button.One)) { sponge_iterations++; if (sponge_iterations > max_sponge_iterations) sponge_iterations = max_sponge_iterations; generate_cubes(); //generates cubes up to degree sponge_iterations filter.mesh =getCubemeshs(sponge_iterations); collider.sharedMesh = filter.mesh; } if (OVRInput.GetDown(OVRInput.Button.Two)) { sponge_iterations--; if (sponge_iterations < 0) sponge_iterations = 0; generate_cubes(); //generates cubes up to degree sponge_iterations filter.mesh =getCubemeshs(sponge_iterations); collider.sharedMesh = filter.mesh; } } Mesh mergeMeshs (Mesh[] meshes) { Mesh newmesh = new Mesh(); newmesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; int no_vertices = 0; int no_triangles = 0; for (int i = 0; i < meshes.Length; i++) { no_vertices += meshes[i].vertices.Length; no_triangles += meshes[i].triangles.Length; } Vector3[] vertices = new Vector3[no_vertices]; Color[] colors = new Color[no_vertices]; Vector3[] normals = new Vector3[no_vertices]; Vector2[] uv = new Vector2[no_vertices]; int[] triangles = new int[no_triangles]; int vertpos = 0; int tripos = 0; int currentmesh_firstvertexind = 0; //tells me at what index the current mesh begins (w.r.t vertices) -- important for triangles for (int i = 0; i < meshes.Length; i++) { for (int j = 0; j < meshes[i].vertices.Length; j++) { vertices[vertpos] = meshes[i].vertices[j]; colors[vertpos] = meshes[i].colors[j]; normals[vertpos] = meshes[i].normals[j]; uv[vertpos] = meshes[i].uv[j]; vertpos++; } for (int j = 0; j < meshes[i].triangles.Length; j++) { triangles[tripos] = meshes[i].triangles[j]+currentmesh_firstvertexind; tripos++; } currentmesh_firstvertexind = vertpos; } newmesh.vertices = vertices; newmesh.colors = colors; newmesh.normals = normals; newmesh.uv = uv; newmesh.triangles = triangles; return newmesh; } void generate_cubes () { //makes sure that up to order sponge_iterations cubes are created //not more than max_sponge_iterations are created. if (sponge_iterations > max_sponge_iterations) sponge_iterations = max_sponge_iterations; int iterations = sponge_iterations; if (cubes.Count < 1) { //first cube needs to be generated Cube[] c = new Cube[1]; c[0] = new Cube(); c[0].generate(new Vector3 (0, 0, 0),new Vector3 (10, 0, 0),new Vector3 (0, 10, 0),new Vector3 (0, 0, 10)); cubes.Add(c); } for (int i =cubes.Count-1; i < iterations; i++) { //compute remaining generations Cube[] c = Cube.compute_children(cubes[i]); cubes.Add(c); } } Mesh getCubemeshs (int iteration_degree) { Cube[] c = cubes[iteration_degree];//take the cubes from the iteration_degree's degree Mesh[] cubemeshes = new Mesh[c.Length]; for (int i = 0; i