void GenerateMap() { map = new int[width, height, depth]; switch (fillType) { case FillType.Random: RandomFillMap(); break; case FillType.Pink: PerlinFillMap(); break; case FillType.Ridge: RidgeFillMap(); break; case FillType.Billow: BillowFillMap(); break; } for (int i = 0; i < smoothIterations; i++) { SmoothMap(); } //TODO not working RemoveWallsFromMap(); float[,,] floatMap = new float[width, height, depth]; for (int x = 0; x < width - 1; x++) { for (int y = 0; y < height - 1; y++) { for (int z = 0; z < depth - 1; z++) { floatMap[x, y, z] = (float)map[x, y, z]; } } } MarchingCubes.SetModeToCubes(); Mesh mesh = MarchingCubes.CreateMesh(floatMap); //Move all vertices so that origin is centered Vector3[] vertices = mesh.vertices; /* for(int i = 0; i < vertices.Count(); i++) { * vertices[i] = vertices[i] + (-mesh.bounds.center); * }*/ mesh.name = "world"; myMesh = mesh; GetComponent <MeshFilter>().mesh = mesh; mesh.RecalculateNormals(); GetComponent <MeshCollider>().sharedMesh = mesh; }
public Mesh CreateMesh() { //float startTime = Time.realtimeSinceStartup; Mesh mesh = MarchingCubes.CreateMesh(GridData); if (mesh == null) { return(null); } int size = mesh.vertices.Length; if (GridNormals != null) { Vector3[] normals = new Vector3[size]; Vector3[] verts = mesh.vertices; //Each verts in the mesh generated is its position in the voxel array //and you can use this to find what the normal at this position. //The verts are not at whole numbers though so you need to use trilinear interpolation //to find the normal for that position for (int i = 0; i < size; i++) { normals[i] = TriLinearInterpNormal(verts[i]); } mesh.normals = normals; } else { mesh.RecalculateNormals(); } Color[] control = new Color[size]; Vector3[] meshNormals = mesh.normals; for (int i = 0; i < size; i++) { //This creates a control map used to texture the mesh based on the slope //of the vert. Its very basic and if you modify how this works yoou will //you will probably need to modify the shader as well. float dpUp = Vector3.Dot(meshNormals[i], Vector3.up); float R = Mathf.Pow(Mathf.Abs(dpUp), 2.0f); float G = Mathf.Max(0.0f, dpUp); // (Mathf.Max(0.0f, dpUp) < 0.8f) ? 0.0f : 1.0f; //Whats left end up being the rock face on the vertical areas control[i] = new Color(R, G, 0, 0); } //May as well store in colors mesh.colors = control; return(mesh); //Debug.Log("Create mesh time = " + (Time.realtimeSinceStartup-startTime).ToString() ); }
private void MeshThread(MapData mapData, Action <MeshData> callback) { MeshData mesh = MarchingCubes.CreateMesh(mapData); lock (meshThreadInfoQueue) { meshThreadInfoQueue.Enqueue(new MapThreadInfo <MeshData>(callback, mesh)); } }
public void Build() { marchingCubes.CreateMesh(field); vertBuffer.Clear(); for (int i = 0; i < marchingCubes.mb.vertices.Count; i++) { TVector3 vert = marchingCubes.mb.vertices[i]; vertBuffer.Add(new Vector3(vert.X, vert.Y, vert.Z)); } m.Clear(); m.SetVertices(vertBuffer); m.SetTriangles(marchingCubes.mb.triangles, 0); m.RecalculateNormals(); mf.sharedMesh = m; mc.sharedMesh = m; }
public void UpdateMesh() { if (isDirty) { Mesh mesh = MarchingCubes.CreateMesh(voxels); MarchingCubes.SetTarget(target); //The diffuse shader wants uvs so just fill with a empty array, there not actually used mesh.uv = new Vector2[mesh.vertices.Length]; mesh.RecalculateNormals(); DestroyImmediate(m_mesh.GetComponent <MeshFilter>().sharedMesh, true); m_mesh.GetComponent <MeshFilter>().mesh = mesh; m_mesh.transform.localPosition = transform.position + new Vector3(-32 / 2, -32 / 2, -32 / 2); isDirty = false; } }
/// <summary> /// Creates the surface objects. /// </summary> /// <param name='voxels'> /// Voxels, i.e. the scalar field used to compute the surface. /// </param> /// <param name='threshold'> /// The threshold on which the isosurface is based. /// </param> /// <param name='delta'> /// Delta parameter from the grid, basically the size of each cell. /// </param> /// <param name='origin'> /// Origin of the grid. /// </param> /// <param name='colors'> /// Colors. Kept from previous implementation, but doesn't do anything here. I'm only /// keeping it because I'm not sure what it was used for. --- Alexandre /// </param> /// <param name='tag'> /// Tag for the objects to be created. /// </param> /// <param name='electro'> /// True if this is an electrostatic field isosurface. /// </param> public static void CreateSurfaceObjects(float[,,] voxels, float threshold, Vector3 delta, Vector3 origin, Color[] colors, string tag = "SurfaceManager", bool electro = false) { ELECTRO = electro; Debug.Log(ELECTRO.ToString()); if (ELECTRO) { ReadDX readDX = UI.GUIMoleculeController.readdx; origin = readDX.GetOrigin(); delta = readDX.GetDelta(); } InitGenMesh(voxels, threshold, delta, origin, tag); SetDims(); float bMCTime = Time.realtimeSinceStartup; MeshData mData = MarchingCubes.CreateMesh(VOXELS, 0, XDIM, 0, YDIM, 0, ZDIM); Debug.Log("Entire surface contains " + mData.vertices.Length.ToString() + " vertices."); float elapsed = 10f * (Time.realtimeSinceStartup - bMCTime); Debug.Log("GenerateMesh::MarchingCubes time: " + elapsed.ToString()); OffsetVertices(mData); float bSmooth = Time.realtimeSinceStartup; AdjacencySets adjacencySets = new AdjacencySets(mData.triangles.Length); adjacencySets.AddAllTriangles(mData.triangles); SmoothFilter.AdjSetsSmoother(mData, adjacencySets); elapsed = Time.realtimeSinceStartup - bSmooth; Debug.Log("Smoothing time: " + elapsed.ToString()); ProperlyCalculateNormals(mData); // Necessary for electrostatic fields isosurfaces Debug.Log(threshold.ToString()); if (threshold < 0) { FlipTriangles(mData); } Splitting splitting = new Splitting(); List <Mesh> meshes = splitting.Split(mData); CreateSurfaceObjects(meshes); }
void Update() { var offset = noiseMove * Time.time; var dx = Vector3.right * (noiseScale / division); var dy = Vector3.up * (noiseScale / division); var dz = Vector3.forward * (noiseScale / division); for (var iz = 0; iz < division; iz++) { for (var iy = 0; iy < division; iy++) { for (var ix = 0; ix < division; ix++) { var pos = dx * ix + dy * iy + dz * iz + offset; voxels [ix, iy, iz] = Perlin.Fbm(pos, octave) * noise + 1.0f * iz / division; } } } for (var iz = 1; iz < division - 1; iz++) { for (var iy = 1; iy < division - 1; iy++) { for (var ix = 1; ix < division - 1; ix++) { var gx = voxels[ix + 1, iy, iz] - voxels[ix - 1, iy, iz]; var gy = voxels[ix, iy + 1, iz] - voxels[ix, iy - 1, iz]; var gz = voxels[ix, iy, iz + 1] - voxels[ix, iy, iz - 1]; gradient[ix, iy, iz] = new Vector3(gx, gy, gz); } } } var oldMesh = meshFilter.sharedMesh; MarchingCubes.SetTarget(target); var mesh = MarchingCubes.CreateMesh(voxels, gradient); meshFilter.sharedMesh = mesh; if (oldMesh != null) { Destroy(oldMesh); } }
void Start() { currentTarget = target; m_perlin = new PerlinNoise(2); //Target 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 were 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 MarchingCubes.SetTarget(target); //Winding order of triangles use 2,1,0 or 0,1,2 MarchingCubes.SetWindingOrder(0, 1, 2); //Set the mode used to create the mesh //Cubes is faster and creates less verts, tetrahedrons is slower and creates more verts but better represents the mesh surface //MarchingCubes.SetModeToCubes(); MarchingCubes.SetModeToCubes(); //The size of voxel array. Be carefull not to make it to large as a mesh in unity can only be made up of 65000 verts int width = 32; int height = 32; int length = 32; voxels = new float[width, height, length]; //Fill voxels with values. Im using perlin noise but any method to create voxels will work CalcVoxels(width, height, length); Mesh mesh = MarchingCubes.CreateMesh(voxels); //The diffuse shader wants uvs so just fill with a empty array, there not actually used mesh.uv = new Vector2[mesh.vertices.Length]; mesh.RecalculateNormals(); m_mesh = new GameObject("Mesh"); m_mesh.AddComponent <MeshFilter>(); m_mesh.AddComponent <MeshRenderer>(); m_mesh.GetComponent <Renderer>().material = m_material; m_mesh.GetComponent <MeshFilter>().mesh = mesh; //Center mesh m_mesh.transform.localPosition = new Vector3(-32 / 2, -32 / 2, -32 / 2); }
void Update() { time += Time.deltaTime; center1 = new Vector3(Mathf.Cos(Time.time * 3.14f) * 16 + 16, 32, Mathf.Sin(Time.time * 3.14f) * 16 + 16); if (time > 1 / 30f) { time -= 1 / 30f; currentTarget = target; MarchingCubes.SetTarget(target); CalcVoxels(32, 32, 32); Mesh mesh = MarchingCubes.CreateMesh(voxels); //The diffuse shader wants uvs so just fill with a empty array, there not actually used mesh.uv = new Vector2[mesh.vertices.Length]; mesh.RecalculateNormals(); DestroyImmediate(m_mesh.GetComponent <MeshFilter>().sharedMesh, true); m_mesh.GetComponent <MeshFilter>().mesh = mesh; } }
public void Build() { float[,,] voxels = new float[size + 1, size + 1, size + 1]; int height; float hFactor; for (int z = 0; z < size + 1; z++) { for (int y = 0; y < size + 1; y++) { height = yi + y; hFactor = (float)(maxHeight - 2 * height) / (float)maxHeight; for (int x = 0; x < size + 1; x++) { voxels[x, y, z] = -hFactor + m_perlin.FractalNoise3D((float)(xi + x), (float)(yi + y), (float)(zi + z), 3, freq, 1.0f); } } } mesh = MarchingCubes.CreateMesh(voxels); //UV MAPPING Vector3[] vertices = mesh.vertices; Vector2[] uvs = new Vector2[mesh.vertices.Length]; for (int i = 0; i < uvs.Length; i++) { uvs[i] = new Vector2(vertices[i].x, vertices[i].z); } mesh.uv = uvs; //NORMALS mesh.RecalculateNormals(); //TANGENTS TangentSolver.Solve(mesh); mesh.Optimize(); AssetDatabase.CreateAsset(mesh, "Assets/Resources/meshes/mesh" + xi + yi + zi + ".asset"); //GAMEOBJECT SETUP m_mesh.GetComponent <MeshFilter>().mesh = mesh; m_mesh.transform.localPosition = gPos; m_mesh.AddComponent <MeshCollider>(); }
//creates the mesh from the voxel data and assigns it to the mesh filter and mesh collider public override void Render() { //if(Time.time<10) //{ MeshBuilder mb = MarchingCubes.CreateMesh(voxVals, voxSubs); //build all the skirts using marching squares with the edge values if (scale != 1) { for (int i = 0; i < 6; i++) { float[,] slice = new float[chunkSize + 1, chunkSize + 1]; Sub[,] subs = new Sub[chunkSize, chunkSize]; for (int x = 0; x < chunkSize + 1; x++) { for (int y = 0; y < chunkSize + 1; y++) { switch (i) { case 0: slice[x, y] = voxVals[x, y, 0]; if (x < chunkSize && y < chunkSize) { subs[x, y] = voxSubs[x, y, 0]; } break; case 1: slice[x, y] = voxVals[chunkSize - x, y, chunkSize]; if (x < chunkSize && y < chunkSize) { subs[x, y] = voxSubs[chunkSize - 1 - x, y, chunkSize - 1]; } break; case 2: slice[x, y] = voxVals[0, y, chunkSize - x]; if (x < chunkSize && y < chunkSize) { subs[x, y] = voxSubs[0, y, chunkSize - 1 - x]; } break; case 3: slice[x, y] = voxVals[chunkSize, y, x]; if (x < chunkSize && y < chunkSize) { subs[x, y] = voxSubs[chunkSize - 1, y, x]; } break; case 4: slice[x, y] = voxVals[x, chunkSize, y]; if (x < chunkSize && y < chunkSize) { subs[x, y] = voxSubs[x, chunkSize - 1, y]; } break; case 5: slice[x, y] = voxVals[x, 0, chunkSize - y]; if (x < chunkSize && y < chunkSize) { subs[x, y] = voxSubs[x, 0, chunkSize - 1 - y]; } break; default: break; } } } switch (i) { case 0: mb.addMesh(MarchingSquares.buildMesh(slice, subs), Vector3.zero, Quaternion.identity); break; case 1: mb.addMesh(MarchingSquares.buildMesh(slice, subs), new Vector3(chunkSize, 0, chunkSize), Quaternion.Euler(0, 180, 0)); break; case 2: mb.addMesh(MarchingSquares.buildMesh(slice, subs), new Vector3(0, 0, chunkSize), Quaternion.Euler(0, 90, 0)); break; case 3: mb.addMesh(MarchingSquares.buildMesh(slice, subs), new Vector3(chunkSize, 0, 0), Quaternion.Euler(0, -90, 0)); break; case 4: mb.addMesh(MarchingSquares.buildMesh(slice, subs), new Vector3(0, chunkSize, 0), Quaternion.Euler(90, 0, 0)); break; case 5: mb.addMesh(MarchingSquares.buildMesh(slice, subs), new Vector3(0, 0, chunkSize), Quaternion.Euler(-90, 0, 0)); break; default: break; } } } Mesh mesh = mb.getMesh(); //Mesh mesh = MarchingCubes.CreateMesh(voxVals, voxType); //Mesh mesh = MarchingCubes2.CreateMesh(voxVals); //mesh.RecalculateNormals();//not sure what this does at the moment filter.mesh = mesh; //only add colliders for level 0 terrain objects (scale 1) if (scale == 1) { //coll = gameObject.AddComponent<MeshCollider>(); coll.sharedMesh = mesh; } //transform.position.localScale = new Vector3(scale, scale, scale); //} }
//args0 - filepath //args1 - resolution //args2 - xaxis //args3 - yaxis //args4 - zaxis //args5 - isoLevel public static void Main(string[] args) { DebugLog.resetLog(); DebugLog.setDebug(true); int resolution; float isoLevel; #region cmd args handling if (args.Length > 6 || args.Length < 1) { Console.Out.WriteLine(numArgs); Console.In.ReadLine(); return; } if (args.Length == 1 && (args[0].ToLower() == "--help" || args[0].ToLower() == "help" || args[0].ToLower() == "?" || args[0].ToLower() == "h")) { Console.Out.WriteLine(help); Console.In.ReadLine(); return; } if (!File.Exists(args[0])) { DebugLog.logConsole("Could not find file. Are you sure you are passing in the right string?"); throw new Exception("Could not find file. Are you sure you are passing in the right string?"); } try { resolution = Int32.Parse(args[1]); } catch { DebugLog.logConsole("Resolution not a number"); throw new Exception("Resolution not a number"); } try { isoLevel = float.Parse(args[5]); } catch { DebugLog.logConsole("IsoLevel is not a float"); throw new Exception("IsoLevel is not a float"); } if (resolution < 1) { DebugLog.logConsole("Resolution cannot be less than 1"); throw new Exception("Resolution cannot be less than 1"); } #endregion SingularMesh mcAlg = new SingularMesh(); string dir = Directory.GetParent(Directory.GetParent(Directory.GetParent(args[0]).FullName).FullName).Name; List <float> minMaxArray = generateMinMaxArray(new string[] { args[2], args[3], args[4] }, dir); VoxelArray array = mcAlg.createPointCloud(args[0], resolution, args[2], args[3], args[4], minMaxArray.ToArray()); //VoxelArray.WriteFloatArray(mcAlg.outputPath + ".FARA", array); MarchingCubes test = new MarchingCubes(); test.SetTarget(isoLevel); IM intermediate = test.CreateMesh(array.toFloatArray()); if (intermediate.verts.Count > 64999) { IM[] divs = intermediate.divideIntoSmall(); for (int i = 0; i < divs.Length; i++) { divs[i].WriteIntermediateToFile(mcAlg.outputPath + "_" + i + ".IMF"); } } else { intermediate.WriteIntermediateToFile(mcAlg.outputPath + ".IMF"); } }
public void CreateMesh(Material mat) { //float startTime = Time.realtimeSinceStartup; Mesh mesh = MarchingCubes.CreateMesh(m_voxels, 2, 2); if (mesh == null) { return; } int size = mesh.vertices.Length; if (m_normals != null) { Vector3[] normals = new Vector3[size]; Vector3[] verts = mesh.vertices; //Each verts in the mesh generated is its position in the voxel array //and i use this to find what the normal at this position. //The verts are not at whole numbers so i use trilinear interpolation //to find the normal for that position for (int i = 0; i < size; i++) { normals[i] = TriLinearInterpNormal(verts[i]); } mesh.normals = normals; } else { mesh.RecalculateNormals(); } Color[] control = new Color[size]; Vector3[] meshNormals = mesh.normals; for (int i = 0; i < size; i++) { //This creates a control map used to texture the mesh based on the slope //of the vert. float dpUp = Vector3.Dot(meshNormals[i], Vector3.up); //Red channel is the sand on flat areas float R = (Mathf.Max(0.0f, dpUp) < 0.8f) ? 0.0f : 1.0f; //Green channel is the gravel on the sloped areas float G = Mathf.Pow(Mathf.Abs(dpUp), 2.0f); //Whats left end up being the rock face on the vertical areas control[i] = new Color(R, G, 0, 0); } //May as well store in colors mesh.colors = control; m_mesh = new GameObject("Voxel Mesh " + m_pos.x.ToString() + " " + m_pos.y.ToString() + " " + m_pos.z.ToString()); m_mesh.AddComponent <MeshFilter>(); m_mesh.AddComponent <MeshRenderer>(); m_mesh.renderer.material = mat; m_mesh.GetComponent <MeshFilter>().mesh = mesh; m_mesh.transform.localPosition = m_pos; MeshCollider collider = m_mesh.AddComponent <MeshCollider>(); collider.sharedMesh = mesh; //Debug.Log("Create mesh time = " + (Time.realtimeSinceStartup-startTime).ToString() ); }
public void createMesh(ConcurrentStack <string> stack, int resolution, string[] axis, float[] minMaxArray, float isoLevel) { DebugLog.logConsole("Mesh creation thread started"); totalMeshes = stack.Count; while (!stack.IsEmpty) { //If we fail popping, we may be attempting to access //at the same time as someone else. This means the stack //might have emptied since we last checked so we check again if (!stack.TryPop(out string file)) { continue; } //If we got this far, then we have a file DebugLog.logConsole(file + " has been selected"); SingularMesh alg = alg = new SingularMesh(); VoxelArray array = null; try { array = alg.createPointCloud(file, resolution, axis[0], axis[1], axis[2], minMaxArray); } catch (Exception) { DebugLog.logConsole("Threading failed at array creation for " + file); } MarchingCubes test = new MarchingCubes(); test.SetTarget(isoLevel); IM intermediate = null; try { intermediate = test.CreateMesh(array.toFloatArray()); } catch (Exception) { DebugLog.logConsole("Threading failed at intermediate creation for " + file); } try { if (intermediate.verts.Count > 64999) { DebugLog.logConsole("Dividing " + file); IM[] divs = intermediate.divideIntoSmall(); for (int i = 0; i < divs.Length; i++) { divs[i].WriteIntermediateToFile(alg.outputPath + "_" + i + ".IMF"); } } else { intermediate.WriteIntermediateToFile(alg.outputPath + ".IMF"); } DebugLog.logConsole(alg.outputPath + ".IMF"); } catch (Exception e) { DebugLog.logConsole(e.Message + "\n" + e.StackTrace + "\n" + file + "\n--------------------------------------------"); } array = null; alg = null; intermediate = null; try { double perc = ((double)(totalMeshes - stack.Count) / (double)totalMeshes) * 100; PercentageClass.UpdatePercentage("Creating Mesh", perc); DebugLog.logConsole("Mesh Creation: " + perc.ToString("#.##") + "% total"); } catch (Exception) { DebugLog.logConsole("Threading failed at percentage writing for " + file); } } }
// Use this for initialization void Awake() { //Random.seed = 2; //Target 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 were 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 MarchingCubes.SetTarget(-0.8825f); //Winding order of triangles use 2,1,0 or 0,1,2 MarchingCubes.SetWindingOrder(2, 1, 0); //Set the mode used to create the mesh //Cubes is faster and creates less verts, tetrahedrons is slower and creates more verts but better represents the mesh surface MarchingCubes.SetModeToCubes(); //MarchingCubes.SetModeToTetrahedrons(); //the index of the closest voronoi seed int[, ,] voxelVoronoi = new int[_width + 1, _height + 1, _length + 1]; //smoothmin distances float[, ,] voxelSmoothMin = new float[_width + 1, _height + 1, _length + 1]; //final values float[, ,] voxels = new float[_width + 1, _height + 1, _length + 1]; int x, y, z; float start = Time.realtimeSinceStartup; Vector3[] seeds = new Vector3[numSeeds]; for (int i = 0; i < seeds.Length; i++) { seeds[i] = new Vector3(Random.value * (_width + 1), Random.value * (_height + 1), Random.value * (_length + 1)); } //populate the voronoi/smoothmin arrays for (x = 0; x < _width + 1; x++) { for (y = 0; y < _height + 1; y++) { for (z = 0; z < _length + 1; z++) { Vector3 testPoint = new Vector3(x, y, z); int closestSeedIndex = 0; float distance = distanceOfMirrors(testPoint, seeds[0]); for (int i = 1; i < seeds.Length; i++) { float queryDistance = distanceOfMirrors(testPoint, seeds[i]); if (queryDistance < distance) { distance = queryDistance; closestSeedIndex = i; } } voxelVoronoi[x, y, z] = closestSeedIndex; voxelSmoothMin[x, y, z] = sminDistance(testPoint, seeds, k); } } } int yesCount = 0; int noCount = 0; //Create a mesh for each seed for (int i = 0; i < seeds.Length; i++) { //Fill voxels with values. Im using perlin noise but any method to create voxels will work for (x = 0; x < _width + 1; x++) { for (y = 0; y < _height + 1; y++) { for (z = 0; z < _length + 1; z++) { if (voxelVoronoi[x, y, z] != i) //we are not in the correct voronoi cell { voxels[x, y, z] = 1; //outside noCount++; } else { Vector3 queryPoint = new Vector3(x, y, z); float distance = distanceOfMirrors(queryPoint, seeds[i]); distance = voxelSmoothMin[x, y, z] / distance; voxels[x, y, z] = 1 - (distance * 2); //transform from 0..1 to 1..-1 yesCount++; } } } } Mesh mesh = MarchingCubes.CreateMesh(voxels, _scale); //The diffuse shader wants uvs so just fill with a empty array, there not actually used mesh.RecalculateNormals(); m_mesh = Instantiate(meshPrefab); m_mesh.GetComponent <MeshFilter>().mesh = mesh; //Center mesh //m_mesh.transform.localPosition = scale * new Vector3(-width / 2, -height / 2, -length / 2); //meshcolliders need to be added as components to properly initialize //so I can't put it in the prefab m_mesh.AddComponent <MeshCollider>(); ProceduralDuplication.AddToDuplicate(m_mesh); } Debug.Log("Time take = " + (Time.realtimeSinceStartup - start) * 1000.0f); }