public static GameObject BlockToGameObject(RenderBuffers buffers, IVoxelBlock block, Material material, Action <PointerEventData, GameObject> clickCallback) { GameObject go = new GameObject(String.Format("Block({0}, {1})", block.Offset.x, block.Offset.y)); go.AddComponent <ProceduralRenderer>(); go.AddComponent <BoxCollider>(); go.AddComponent <BlockInfo>(); go.AddComponent <EventTrigger>(); ProceduralRenderer renderer = go.GetComponent <ProceduralRenderer>(); renderer.buffers = buffers; renderer.bounds.min = new Vector3(0.0f, 0.0f, 0.0f); renderer.bounds.size = new Vector3(block.Width, block.Height, block.Length); go.GetComponent <BlockInfo>().Block = block; go.transform.localPosition = new Vector3((block.Offset.x - 0.5f) * block.Width, -block.Height / 2, (block.Offset.y - 0.5f) * block.Length); go.transform.localScale = new Vector3(1.0f, 1.0f, 1.0f); go.GetComponent <BoxCollider>().center = new Vector3(block.Width / 2, block.Height / 2, block.Length / 2); go.GetComponent <BoxCollider>().size = new Vector3(block.Width, block.Height, block.Length); EventTrigger trigger = go.GetComponent <EventTrigger>(); EventTrigger.Entry entry = new EventTrigger.Entry(); entry.eventID = EventTriggerType.PointerClick; entry.callback.AddListener((data) => { clickCallback((PointerEventData)data, go); }); trigger.triggers.Add(entry); go.AddComponent <LineRenderer>(); LineRenderer boundingBoxRenderer = go.GetComponent <LineRenderer>(); Vector3[] points = getBoundingBoxPoints(block); boundingBoxRenderer.positionCount = points.Length; boundingBoxRenderer.useWorldSpace = false; boundingBoxRenderer.SetPositions(points); return(go); }
public IEnumerator <object> genericTest(Tests type, string name, int cpuLimit, int pmbLimit, Func <Vector3Int, int, int, int, float> voxelGenerator) { int CPU_LIMIT = cpuLimit; int PMB_LIMIT = pmbLimit; UnityEngine.Debug.Log("Starting Test " + name); perfData[(int)type] = new PerfData { testName = name, sizes = new TestSize[testSizes.Length], }; int limitCounter = 0; for (int i = 0; i < testSizes.Length; i++) { Vector3Int size = (Vector3Int)testSizes[i]; UnityEngine.Debug.Log("size: " + size); perfData[(int)type].sizes[i] = new TestSize { sizeName = string.Format("({0}, {1}, {2})", size.x, size.y, size.z), cpuTime = new int[ROUNDS], pmbTime = new int[ROUNDS], cpuTriangles = 0, pmbTriangles = 0, }; float[] voxel; string path = Path.Combine(performanceDataDir, string.Format("{0}{1}.dat", name, perfData[(int)type].sizes[i].sizeName)); if (File.Exists(path)) { UnityEngine.Debug.Log("loading voxelData from file:"); Stream voxelStream = File.OpenRead(path); BinaryFormatter deserializer = new BinaryFormatter(); voxel = (float[])deserializer.Deserialize(voxelStream); voxelStream.Close(); } else { UnityEngine.Debug.Log("recreating voxelData:"); voxel = new float[size.x * size.y * size.z]; for (int x = 0; x < size.x; x++) { for (int y = 0; y < size.y; y++) { for (int z = 0; z < size.z; z++) { voxel[z * size.x * size.y + y * size.x + x] = voxelGenerator(size, x, y, z); } } } Stream SaveFileStream = File.Create(path); BinaryFormatter serializer = new BinaryFormatter(); serializer.Serialize(SaveFileStream, voxel); SaveFileStream.Close(); } UnityEngine.Debug.Log("executing Test:"); for (int round = 0; round < ROUNDS; round++) { Stopwatch watch = Stopwatch.StartNew(); if (limitCounter < CPU_LIMIT) { List <Vector3> verts = new List <Vector3>(); List <int> indices = new List <int>(); List <Vector3> normals = new List <Vector3>(); marching.Generate(voxel, size.x, size.y, size.z, verts, indices, normals); watch.Stop(); UnityEngine.Debug.LogFormat("\tCPU took {0}ms", watch.ElapsedMilliseconds); perfData[(int)type].sizes[i].cpuTime[round] = (int)watch.ElapsedMilliseconds; perfData[(int)type].sizes[i].cpuTriangles = indices.Count / 3; } else { UnityEngine.Debug.Log("\tCPU skipped"); perfData[(int)type].sizes[i].cpuTime[round] = -1; } if (limitCounter < PMB_LIMIT) { VoxelBlock <Voxel> block = InitBlock(size); UnityEngine.Debug.Log(voxel.Length + " " + voxel[0] + " " + voxel[1] + " " + voxel[2] + " " + voxel[3] + " " + voxel[4] + " " + voxel[5] + " " + voxel[6] + " " + voxel[7]); helper.scheduleOnMainThread(() => { watch = Stopwatch.StartNew(); pmb.ReInit(block); RenderBuffers buffers = pmb.calculate(voxel, size.x, size.y, size.z, 0.5f); int[] args = new int[4]; buffers.argsBuffer.GetData(args); watch.Stop(); UnityEngine.Debug.LogFormat("\tPMB took {0}ms", watch.ElapsedMilliseconds); perfData[(int)type].sizes[i].pmbTime[round] = (int)watch.ElapsedMilliseconds; perfData[(int)type].sizes[i].pmbTriangles = args[0] / 3; buffers.vertexBuffer.Dispose(); buffers.indexBuffer.Dispose(); buffers.normalBuffer.Dispose(); buffers.argsBuffer.Dispose(); UnityEngine.Debug.Log("PMB triags inside thread: " + perfData[(int)type].sizes[i].pmbTriangles); }).wait(); UnityEngine.Debug.Log("PMB triags after thread: " + perfData[(int)type].sizes[i].pmbTriangles); } else { UnityEngine.Debug.Log("\tPMB skipped"); perfData[(int)type].sizes[i].pmbTime[round] = -1; watch.Stop(); } yield return(null); } limitCounter++; } }
public override bool Calculate() { bool isPMB = false; if (!input.connected()) { return(false); } VoxelBlock <Voxel> block = input.GetValue <VoxelBlock <Voxel> >(); if (surfaceConnection.connected()) { surface = surfaceConnection.GetValue <float>(); } Marching marching = null; switch (mode) { case VerteGenerationMode.Tetrahedron: marching = new MarchingTertrahedron(); break; case VerteGenerationMode.Cubes: marching = new MarchingCubes(); break; case VerteGenerationMode.Voxel: marching = new VoxelGeneration(); break; case VerteGenerationMode.PMB: isPMB = true; break; } //The size of voxel array. Vector3Int count = block.VoxelCount; int width = count.x; int height = count.y; int length = count.z; float[] voxels = new float[width * height * length]; for (int y = 0; y < height; y++) { Voxel[,] voxelLayer = block.Layers[y].Layer; for (int x = 0; x < width; x++) { for (int z = 0; z < length; z++) { int idx = x + y * width + z * width * height; voxels[idx] = voxelLayer[x, z].GetValue(); } } } if (isPMB) { var pmbTask = MainThreadHelper.instance().scheduleOnMainThread(() => { pmb.ReInit(block); Stopwatch pmbWatch = Stopwatch.StartNew(); buffers = pmb.calculate(voxels, width, height, length, surface); pmbWatch.Stop(); UnityEngine.Debug.LogFormat("PMB took {0}ms\n\t{1} voxels\n\t{2} triangles", pmbWatch.ElapsedMilliseconds, voxels.Count(), buffers.indexBuffer.count / 3); }); pmbTask.wait(); if (!pmbTask.completed) { return(false); } Block = block; return(true); } //Surface is the value that represents the surface of mesh //For example the perlin noise has a range of -1 to 1 so the mid point is where we want the surface to cut through. //The target value does not have to be the mid point it can be any value with in the range. // //This should be accesible by an input marching.Surface = surface; List <Vector3> verts = new List <Vector3>(); List <int> indices = new List <int>(); List <Vector3> normals = new List <Vector3>(); Stopwatch sw = Stopwatch.StartNew(); marching.Generate(voxels, width, height, length, verts, indices, normals); sw.Stop(); UnityEngine.Debug.LogFormat("Marching took {0}ms\n\t{1} vertices; {2} triangles", sw.ElapsedMilliseconds, verts.Count(), indices.Count() / 3); sw.Restart(); weldVertices(verts, indices, normals); sw.Stop(); UnityEngine.Debug.LogFormat("Vertex welding took {0}ms\n\t {1} vertices left", sw.ElapsedMilliseconds, verts.Count()); var task = MainThreadHelper.instance().scheduleOnMainThread(() => { buffers = new RenderBuffers { vertexBuffer = new ComputeBuffer(verts.Count, sizeof(float) * 3), indexBuffer = new ComputeBuffer(indices.Count, sizeof(int)), normalBuffer = new ComputeBuffer(normals.Count, sizeof(float) * 3), argsBuffer = new ComputeBuffer(4, sizeof(int), ComputeBufferType.IndirectArguments), }; buffers.vertexBuffer.SetData(verts); buffers.indexBuffer.SetData(indices); buffers.normalBuffer.SetData(normals); buffers.argsBuffer.SetData(new int[] { indices.Count, 1, 0, 0 }); }); task.wait(); if (!task.completed) { return(false); } Block = block; return(true); }