static MarchingCubes computeSphereChunk(MarchingCubes mc, float[,,] noiseMap, float heightScale, int bodyRadius, Vector3 offset, int vertexIncrement, int chunkSize) { for (int z = 0; z < (chunkSize / vertexIncrement) + 1; z++) { for (int y = 0; y < (chunkSize / vertexIncrement) + 1; y++) { for (int x = 0; x < (chunkSize / vertexIncrement) + 1; x++) { float xComponent = (x * vertexIncrement + offset.x); float yComponent = (y * vertexIncrement + offset.y); float zComponent = (z * vertexIncrement + offset.z); float surface = (xComponent * xComponent) + (yComponent * yComponent) + (zComponent * zComponent) - (bodyRadius * bodyRadius) + bodyRadius; mc.set_data(surface - heightScale * bodyRadius * noiseMap[x * vertexIncrement, y * vertexIncrement, z * vertexIncrement], x, y, z); } } } return(mc); }
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); }
// Use the marching cubes algorithm to extract the isosurface private void ExtractIsosurface() { // Get the gameobject and mesh GameObject o = this.gameObject; GetMesh(ref o, ref m, true); // Clear lists vertices.Clear(); triangles.Clear(); uv.Clear(); // March through each cell in the grid for (int z = 0; z < GridSize.z; z++) { for (int y = 0; y < GridSize.y; y++) { for (int x = 0; x < GridSize.x; x++) { // Set the vertices of the cell cell.p[0] = grid[x, y, z + 1]; cell.p[1] = grid[x + 1, y, z + 1]; cell.p[2] = grid[x + 1, y, z]; cell.p[3] = grid[x, y, z]; cell.p[4] = grid[x, y + 1, z + 1]; cell.p[5] = grid[x + 1, y + 1, z + 1]; cell.p[6] = grid[x + 1, y + 1, z]; cell.p[7] = grid[x, y + 1, z]; MarchingCubes.Triangulate(ref cell, Isolevel); BuildCellMesh(ref cell); } } } // Convert the vertex, triangle and uv lists to arrays Vector3[] vertexArray = vertices.ToArray(); int[] triangleArray = triangles.ToArray(); Vector2[] uvArray = uv.ToArray(); // Set the grid mesh SetMesh(ref o, ref vertexArray, ref triangleArray, ref uvArray); }
/// <summary> /// Builds NavMesh from grid using MarchingCubes algorithm /// </summary> public void MarchCubes() { if (!gridSettings) { return; } var filter = GetComponent <MeshFilter>(); var collider = GetComponent <MeshCollider>(); filter.sharedMesh = null; collider.sharedMesh = null; if (grid == null) { GenerateGrid(); } var mesh = MarchingCubes.March(grid, gridSettings.isoLevel); filter.sharedMesh = mesh; collider.sharedMesh = mesh; }
private void TestClosed(int a, int b, int c, int d, int e, int f, int g, int h) { // ARRANGE float[,,] cells = new float[, , ] { { { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 } }, { { -1, -1, -1, -1 }, { -1, a, b, -1 }, { -1, c, d, -1 }, { -1, -1, -1, -1 } }, { { -2, -2, -2, -2 }, { -2, e, f, -2 }, { -2, g, h, -2 }, { -2, -2, -2, -2 } }, { { -2, -2, -2, -2 }, { -2, -2, -2, -2 }, { -2, -2, -2, -2 }, { -2, -2, -2, -2 } }, }; // ACT ArrayGrid grid = new ArrayGrid(cells, Vector3.Zero, Vector3.One); ListSurface s = new ListSurface(); MarchingCubes.MarchIntoSurface(grid, 0, s); bool isClosed = s.IsClosed(); // ASSERT Assert.IsTrue(isClosed); }
void CreateChunkMesh(Vector3Int Position) { foreach (Vector3Int neighbor in Utils.ChunkNeighbors) { if (!LoadedChunks.ContainsKey(Position + neighbor)) { CreateChunkData(Position + neighbor); } } ChunkData Chunk = LoadedChunks[Position]; if (!Chunk.IsDirty) { return; } MarchingCubes meshGen = new MarchingCubes(); Chunk.MeshData = meshGen.GenerateMesh(Chunk); Chunk.IsDirty = false; }
public void GridGenerateSurface_SingleValue1_OtherValueMinus1_Iso0_GeneratesCorrectTriangle() { // ARRANGE ArrayGrid grid = GenerateSingle(1, -1, 0); ListSurface expected = new ListSurface(); expected.AddVertex(new Vector3(0.5f, 0, 0)); expected.AddVertex(new Vector3(0, 0.5f, 0)); expected.AddVertex(new Vector3(0, 0, 0.5f)); expected.AddTriangle(0, 1, 2); // ACT ListSurface s = new ListSurface(); MarchingCubes.MarchIntoSurface(grid, 0, s); bool areEqual = ListSurface.AreSurfacesEquivalent(expected, s); // ASSERT Assert.IsTrue(areEqual); }
public void Generate(float isolevel, Action callback = null) { MarchingCubes.Target = isolevel; MarchingCubes.SetWindingOrder(WindingOrder.i, WindingOrder.j, WindingOrder.k); MarchingCubes.GeneratorMode = MarchingCubes.Mode.MarchingCube; // CalculateNormals(); primitive = CreateMesh(); if (mf != null) { mf.mesh = primitive; } if (mc != null) { mc.sharedMesh = primitive; } if (callback != null) { callback(); } }
void Start() { //Make 2 perlin noise objects, one is used for the surface and the other for the caves PerlinNoise m_surfacePerlin = new PerlinNoise(m_surfaceSeed); PerlinNoise m_cavePerlin = new PerlinNoise(m_caveSeed); //Set some varibles for the marching cubes plugin MarchingCubes.SetTarget(0.0f); MarchingCubes.SetWindingOrder(2, 1, 0); MarchingCubes.SetModeToCubes(); //create a array to hold the voxel chunks m_voxelChunk = new VoxelChunk[m_chunksX, m_chunksY, m_chunksZ]; //The offset is used to centre the terrain on the x and z axis. For the Y axis //we can have a certain amount of chunks above the y=0 and the rest will be below Vector3 offset = new Vector3(m_chunksX * m_voxelWidth * -0.5f, -(m_chunksY - m_chunksAbove0) * m_voxelHeight, m_chunksZ * m_voxelLength * -0.5f); for (int x = 0; x < m_chunksX; x++) { for (int y = 0; y < m_chunksY; y++) { for (int z = 0; z < m_chunksZ; z++) { //The position of the voxel chunk Vector3 pos = new Vector3(x * m_voxelWidth, y * m_voxelHeight, z * m_voxelLength); //Create the voxel object m_voxelChunk[x, y, z] = new VoxelChunk(pos + offset, m_voxelWidth, m_voxelHeight, m_voxelLength, m_surfaceLevel); //Create the voxel data m_voxelChunk[x, y, z].CreateVoxels(m_surfacePerlin, m_cavePerlin); //Smooth the voxels, is optional but I think it looks nicer m_voxelChunk[x, y, z].SmoothVoxels(); //Create the normals. This will create smoothed normal. //This is optional and if not called the unsmoothed mesh normals will be used m_voxelChunk[x, y, z].CalculateNormals(); //Creates the mesh form voxel data using the marching cubes plugin and creates the mesh collider m_voxelChunk[x, y, z].CreateMesh(m_material); } } } }
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; } }
/// <summary> /// Executes the code necessary to loading/generating chunk entity data. /// </summary> /// <param name="index"> /// The index of the job being performed. /// </param> public void Execute() { // Prep chunk generation. noiseSettings.offset = location * noiseSettings.size; noiseSettings.size += 1; // Perform chunk generation. var volumeData = VolumeGenerator.generateData(noiseSettings); var meshData = MarchingCubes.generate(volumeData, noiseSettings.size - 1, lod: 1); // Manually copy mesh data. for (int index = 0; index < meshData.Length; index++) { chunkInfo.meshData.Add(meshData[index]); } // Copy data and dispose of temporaries from callees. chunkInfo.volumeData.CopyFrom(volumeData); volumeData.Dispose(); meshData.Dispose(); }
public static void TestMarchingCubes() { MarchingCubes mc = new MarchingCubes(); LocalProfiler p = new LocalProfiler(); p.Start("GENERATE"); mc.ParallelCompute = true; mc.Generate(); p.Stop("GENERATE"); DebugUtil.Log(2, p.AllTimes()); MeshNormals.QuickCompute(mc.Mesh); DebugUtil.WriteDebugMesh(mc.Mesh, "c:\\scratch\\MARCHING_CUBES.obj"); DMeshSO meshSO = new DMeshSO(); meshSO.Create(mc.Mesh, CC.ActiveScene.DefaultMeshSOMaterial); CC.ActiveScene.AddSceneObject(meshSO, false); }
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>(); }
void Awake() { mesh = new Mesh(); mc = new MarchingCubes(); mc.m_marchingCubesShader = m_MarchingCubesShader; mc.m_clearVerticesShader = m_FillBufferShader; mc.m_calculateNormalsShader = m_calculateNormalsShader; mc.m_recalculateNormals = m_recalculateNormals; mc.Initalize(m_x_dim, m_y_dim, m_z_dim, m_size, m_LOD); m_densityMap = new float[m_x_dim * m_y_dim * m_z_dim]; //Random.InitState(20); //for(int i = 0; i < m_densityMap.Length; i++) m_densityMap[i] = Random.Range(-1f, 1f); //float radius = 7.0f; Vector3 center = new Vector3(m_x_dim / 2, m_y_dim / 2, m_z_dim / 2); for (int z = 0; z < m_z_dim; z++) { for (int y = 0; y < m_y_dim; y++) { for (int x = 0; x < m_x_dim; x++) { Vector3 point = center - new Vector3(x, y, z); m_densityMap[x + y * m_x_dim + z * m_x_dim * m_y_dim] = Mathf.Clamp((-1.0f / m_radius) * point.magnitude + 1, -1.0f, 1.0f); } } } /* * for(int z = 0; z < m_z_dim; z++) * { * for(int y = 0; y < m_y_dim; y++) * { * for(int x = 0; x < m_x_dim; x++) * { * m_densityMap[x + y * m_x_dim + z * m_x_dim * m_y_dim] = -y / (m_y_dim / 2f) + 1f; * } * } * }*/ }
public static MeshData GenerateSphereMesh(NoiseMapData mapData, SphereMeshSettings sphereSettings, int vertexIncrement) { int mcExpand = Mathf.Min(Mathf.CeilToInt(sphereSettings.noiseHeightScale * sphereSettings.radius * 3) * 2 + 2, 59); int halfMCExpand = mcExpand / 2; Vector3 addOffset = new Vector3(-halfMCExpand, -halfMCExpand, -halfMCExpand); MarchingCubes mc = new MarchingCubes(sphereSettings.chunkSize / vertexIncrement + mcExpand, sphereSettings.chunkSize / vertexIncrement + mcExpand, sphereSettings.chunkSize / vertexIncrement + mcExpand); mc.init_all(); mc = computeSphere(mc, mapData.noiseMap, sphereSettings.noiseHeightScale, sphereSettings.radius, mapData.offset, vertexIncrement, sphereSettings.chunkSize, halfMCExpand); mc.run(); mc.clean_temps(); MeshData meshData = new MeshData(); meshData.vertices = VertexToVector3Vertices(mc.vertices, mc.nverts(), mapData.offset + addOffset, vertexIncrement); meshData.normals = VertexToVector3Normals(mc.vertices, mc.nverts()); //meshData.uv = NormalsToUVs(mesh.normals); meshData.uv = VerticesToUVs(meshData.vertices); meshData.triangles = TrianglesToInt(mc.triangles, mc.ntrigs()); return(meshData); }
public MeshData GenerateMesh(bool createVoxels) { // so while SIZE is 16, which means theres 16 cells/blocks in grid // you need 17 values to be able to construct those blocks // (think of 17 points in a grid and the blocks are the 16 spaces in between) // if smoothing then need a buffer of 2 around (front and back so +4) for smoothing and normal calculation // (so mesh goes from 2-19 basically (0, 1, 20, 21) are not visible in final result) #if (SMOOTH_SHADING) if (createVoxels) { voxels = WorldGenerator.CreateVoxels(SIZE + 5, depth, voxelSize, pos); } MeshData data = MarchingCubes.CalculateMeshData(voxels, voxelSize, 2, 2); data.CalculateVertexSharing(); //Simplification simp = new Simplification(data.vertices, data.triangles); //data.normals = VoxelUtils.CalculateSmoothNormals(voxels, voxelSize, data.vertices); //data.SplitEdgesCalcSmoothness(); data.CalculateSharedNormals(); // todo figure out why this doesnt make it smoothed... #else if (createVoxels) { voxels = WorldGenerator.CreateVoxels(SIZE + 1, depth, voxelSize, worldPos); } //if (!needsMesh) { // return null; //} //MeshData data = MarchingTetrahedra.CalculateMeshData(voxels, voxelSize); MeshData data = MarchingCubes.CalculateMeshData(voxels, voxelSize); data.CalculateNormals(); #endif //data.CalculateColorsByDepth(depth); return(data); }
IEnumerator Start() { marchCube = gameObject.GetComponent <MarchingCubes>(); chunk = new Chunk[Mathf.RoundToInt(chunkPositions.x * chunkPositions.y)]; //Create the chunks int iterator = 0; for (int x = 0; x < chunkPositions.x; x++) { for (int y = 0; y < chunkPositions.y; y++) { //refreshHM = false; GameObject chunkInst = (GameObject)Instantiate(chunkObj, new Vector3((chunkSize.x - 1) * x, 0, (chunkSize.z - 1) * y), Quaternion.identity); chunkInst.transform.parent = this.transform; chunk[iterator] = chunkInst.AddComponent <Chunk>(); chunk[iterator].Assign(iterator, Mathf.RoundToInt((chunkSize.x) * x), Mathf.RoundToInt((chunkSize.z) * y)); chunk[iterator].generateCaves = generateCaves; chunk[iterator].Initialize(heightMapFractals, caveFractal, chunkSize, new Vector2(x, y)); marchCube.density = chunk[iterator].density; marchCube.Initialize(chunkSize); chunkInst.GetComponent <MeshFilter>().mesh = marchCube.mesh; chunkInst.GetComponent <MeshCollider>().sharedMesh = marchCube.mesh; chunkInst.GetComponent <MeshFilter>().mesh.RecalculateBounds(); chunkInst.GetComponent <MeshFilter>().mesh.RecalculateNormals(); chunkInst.GetComponent <MeshRenderer>().material = mat; iterator++; yield return(1); } } //Used for mesh combining to minimize draw calls //gameObject.GetComponent<CombineChildren>().Combine(); //An octree for future development //gameObject.GetComponent<Octree>().Initialize(); }
//Method to generate given creature public void Generate(Creature c) { //Initialise variables balls.Clear(); gridPoints.Clear(); gridItterations = new Vector2(); Vector3 difference = new Vector3(); //Make meta balls MakeBalls(c); //Set max and min min = new Vector3(min.x - excess, min.y - excess, min.z - excess); max = new Vector3(max.x + excess, max.y + excess, max.z + excess); //Find difference of max and min difference = max - min; startGrid = min; //Make grid GenerateGrid(difference); if (mesh == null) { //New mesh GetComponent <MeshFilter>().mesh = mesh = new Mesh(); mesh.name = "creature bod"; } else { GetComponent <MeshFilter>().mesh.Clear(); mesh = GetComponent <MeshFilter>().mesh; } //Generate mesh MarchingCubes.GenerateMesh(gridPoints, gridItterations, ref mesh); //recalculate normals mesh.RecalculateNormals(); }
protected override void OnContentRendered(EventArgs e) { // adjusts viewport grid size and step model1.GetGrid().Min = new Point3D(-5, -5); model1.GetGrid().Max = new Point3D(+5, +5); model1.GetGrid().Step = .5; // declare the function to be used to evaluate the 3D scalar field ScalarField3D func = new ScalarField3D(myScalarField); // initialize marching cube algorithm mc = new MarchingCubes(new Point3D(0, -2.5, 0), 50, .1f, 25, .1f, 25, .1f, func); mc.IsoLevel = trackBar1.Value; mc.DoWork(); // iso surface generation Mesh isoSurf = mc.Result; // adds the surface to the entities collection with Magenta color model1.Entities.Add(isoSurf, System.Drawing.Color.Magenta); // updates the iso level label isoLevelLabel.Content = "Iso level = " + mc.IsoLevel; // sets trimetric view model1.SetView(viewType.Trimetric); // fits the model in the viewport model1.ZoomFit(); // refresh the viewport model1.Invalidate(); base.OnContentRendered(e); }
public static void Generate(Thread thread, ChunkProcessor.Process process) { process.flag = ChunkProcessor.Flag.Processing; Marching mcubes = new MarchingCubes(); mcubes.Surface = 0; float[] voxels = new float[(int)(Chunk.RESOLUTION * Chunk.RESOLUTION * Chunk.RESOLUTION)]; GeometricalSchemaTemplate temp = new GeometricalSchemaTemplate(); temp.Init(); for (int x = 0; x < Chunk.RESOLUTION; x++) { for (int y = 0; y < Chunk.RESOLUTION; y++) { for (int z = 0; z < Chunk.RESOLUTION; z++) { temp.Feed(x, y, z, process.chunk.data.position.x, process.chunk.data.position.y, process.chunk.data.position.z); voxels[x + y * Chunk.RESOLUTION + z * Chunk.RESOLUTION * Chunk.RESOLUTION] = temp.Voxel(); } } } List <Vector3> verts = new List <Vector3>(); List <int> indices = new List <int>(); mcubes.Generate(voxels, Chunk.RESOLUTION, Chunk.RESOLUTION, Chunk.RESOLUTION, verts, indices); process.chunk.data.vertices = verts.ToArray(); process.chunk.data.triangles = indices.ToArray(); process.flag = ChunkProcessor.Flag.Ready; process.success = true; thread.Abort(); }
public void UpdateMesh() { if (!generator) { return; } if (generator.EnableJob) { MarchingCubes.GenerateMarchingCubesWithJob(voxels, generator.CellSize, generator.ChunkScale, generator.EnableTriangleIndexing, vertices, triangles, colors); } else { MarchingCubes.GenerateMarchingCubes(voxels, generator.CellSize, generator.ChunkScale, generator.EnableTriangleIndexing, vertices, triangles, colors); } mesh.Clear(); mesh.SetVertices(vertices); mesh.SetTriangles(triangles, 0); mesh.SetColors(colors); mesh.RecalculateNormals(); meshCollider.sharedMesh = mesh; dirty = false; }
private Group TestEdgeToVector(float[,,] cell) { LinkedList <bool> batch = new LinkedList <bool>(); MarchingCubes marchingCubes = new MarchingCubes(); marchingCubes.SetVolume(cell); MarchingCubes.Positon pos = new MarchingCubes.Positon(); pos.x = 1; pos.y = 0; pos.z = 0; float expected = Mathf.Lerp(1f, 2f, Mathf.Abs(1.1f) / Mathf.Abs(-1f - 1.1f)); expected = Mathf.Round(expected * 100000) / 100000; float actual = marchingCubes.EdgeToVector(3, pos)[0]; actual = Mathf.Round(actual * 100000) / 100000; Assert <float>("Edge To Vector Test & LerpVectors 1", ref batch, expected, actual); return(new Group("EdgeToVector", batch)); }
public static void test_marching_cubes() { MarchingCubes c = new MarchingCubes(); LocalProfiler profiler = new LocalProfiler(); profiler.Start("Generate"); c.ParallelCompute = true; c.Generate(); profiler.Stop("Generate"); System.Console.WriteLine("Tris: {0} Times: {1}", c.Mesh.TriangleCount, profiler.AllTimes()); Reducer r = new Reducer(c.Mesh); r.ReduceToEdgeLength(c.CubeSize * 0.25); System.Console.WriteLine("after reduce: {0}", c.Mesh.TriangleCount); MeshNormals.QuickCompute(c.Mesh); TestUtil.WriteTestOutputMesh(c.Mesh, "marching_cubes.obj"); }
private void TestMC() { eyeshot.GetGrid().Visible = true; eyeshot.GetGrid().Min = new Point3D(-5, -5); eyeshot.GetGrid().Max = new Point3D(+5, +5); eyeshot.GetGrid().Step = .5; ScalarField3D func = new ScalarField3D(ScalarFieldFunc); double resolution = 0.5; int span = 100; MarchingCubes mc = new MarchingCubes(new Point3D(-5, -5, -5), span, resolution, span, resolution, span, resolution, func); mc.IsoLevel = 4; eyeshot.DoWork(mc); Mesh res = mc.Result; res.FlipNormal(); Mesh sphere = Mesh.CreateSphere(Math.Sqrt(mc.IsoLevel), 16, 32); // eyeshot.Entities.Add(sphere, 0, Color.FromArgb(170, Color.Blue)); eyeshot.Entities.Add(res, 0, Color.FromArgb(170, Color.Red)); eyeshot.Invalidate(); eyeshot.ZoomFit(); }
private void Generate() { var seed = System.DateTime.Now.Millisecond; var perlin = new GeneratorValue(seed, 1, 0.5f, 0.025f, 2, 4); float[] density = new float[width * height * depth]; for (int k = 0; k < depth; k++) { for (int j = 0; j < height; j++) { for (int i = 0; i < width; i++) { density[i + j * width + k * width * height] = perlin.GetNoise3D(new Vector3(i, j, k)); } } } var cubeMarcher = new MarchingCubes(0.1f); var verts = new List <Vector3>(); var indicies = new List <int>(); cubeMarcher.GenerateMesh(density, width, height, depth, verts, indicies); Debug.Log(verts.Count); Debug.Log(indicies.Count); var mesh = new Mesh(); mesh.SetVertices(verts); mesh.SetIndices(indicies.ToArray(), MeshTopology.Triangles, 0); mesh.RecalculateBounds(); mesh.RecalculateNormals(); meshFilter.mesh = mesh; }
Mesh MeshDensityArray() { Marching marching = new MarchingCubes(); marching.Surface = 0.0f; int sl = chunkSettings.ChunkSL + 1; int width = sl; int height = sl; int length = sl; List <Vector3> verts = new List <Vector3>(); List <int> indices = new List <int>(); //The mesh produced is not optimal. There is one vert for each index. //Would need to weld vertices for better quality mesh. marching.Generate(renderBuffer, width, height, length, verts, indices); List <Color32> colors = new List <Color32>(); foreach (Vector3 vertex in verts) { colors.Add(Random.ColorHSV()); } Mesh mesh = new Mesh(); mesh.vertices = verts.ToArray(); mesh.triangles = indices.ToArray(); mesh.colors32 = colors.ToArray(); mesh.RecalculateNormals(); return(mesh); }
void CreateSmoothTerrain(MyMesh TerrainMesh, MarchingCubes marchingCubes, Blocks MyBlocks) { Debug.Log ("Creating Smooth Terrain"); Vector3 BlockScale = MyBlocks.Scale; // Marching cubes is one too small! // for some reason the size has to be like this Vector3 WorldSize_ = MyBlocks.Size; int expand = 0;// WorldCore->MarchingExpand; WorldSize_.x += expand; WorldSize_.y += expand; WorldSize_.z += expand; // = 18 now out of 16 0 to 15 // I need to perform this calculation PER CUBE and not per grid // So perform calculation depending on surrounding cubes, but not whole thing //MarchingCubesData.Clear(); //for (int i = 0; i < (WorldSize_.x)*(WorldSize_.y)*(WorldSize_.z); i++) // MarchingCubesData.Add(0.0f); //marchingCubes.ClearData(MarchingCubesData); marchingCubes = new MarchingCubes(new Vector3(WorldSize_.x, WorldSize_.x, WorldSize_.x), Mathf.RoundToInt(WorldSize_.x)); marchingCubes.PolygonizeData(MyBlocks, WorldSize_); TerrainMesh.ClearMesh (); for (int i = 0; i < marchingCubes.trilist.Count; i++) { // for every triangle in list marchingCubes.trilist[i].calcnormal(true); TerrainMesh.Verticies.Add (marchingCubes.trilist[i].position[0]); TerrainMesh.Verticies.Add (marchingCubes.trilist[i].position[1]); TerrainMesh.Verticies.Add (marchingCubes.trilist[i].position[2]); TerrainMesh.Colors.Add (marchingCubes.trilist[i].colors[0]); TerrainMesh.Colors.Add (marchingCubes.trilist[i].colors[1]); TerrainMesh.Colors.Add (marchingCubes.trilist[i].colors[2]); TerrainMesh.Indicies.Add (TerrainMesh.Verticies.Count-3); TerrainMesh.Indicies.Add (TerrainMesh.Verticies.Count-2); TerrainMesh.Indicies.Add (TerrainMesh.Verticies.Count-1); } Debug.Log ("Created Smooth Terrain"); }
protected virtual void update_level_set() { double unsigned_offset = Math.Abs(offset_distance); if (cached_sdf == null || unsigned_offset > cached_sdf_max_offset || grid_cell_size != cached_sdf.CellSize) { DMesh3 meshIn = MeshSource.GetDMeshUnsafe(); int exact_cells = (int)(unsigned_offset / grid_cell_size) + 1; // only use spatial DS if we are computing enough cells DMeshAABBTree3 use_spatial = GenerateClosedMeshOp.MeshSDFShouldUseSpatial( input_spatial, exact_cells, grid_cell_size, input_mesh_edge_stats.z); MeshSignedDistanceGrid sdf = new MeshSignedDistanceGrid(meshIn, grid_cell_size, use_spatial) { ExactBandWidth = exact_cells }; if (use_spatial != null) { sdf.NarrowBandMaxDistance = unsigned_offset + grid_cell_size; sdf.ComputeMode = MeshSignedDistanceGrid.ComputeModes.NarrowBand_SpatialFloodFill; } sdf.CancelF = is_invalidated; sdf.Compute(); if (is_invalidated()) { return; } cached_sdf = sdf; cached_sdf_max_offset = unsigned_offset; cached_sdf_bounds = meshIn.CachedBounds; } var iso = new DenseGridTrilinearImplicit(cached_sdf.Grid, cached_sdf.GridOrigin, cached_sdf.CellSize); MarchingCubes c = new MarchingCubes(); c.Implicit = iso; c.IsoValue = offset_distance; c.Bounds = cached_sdf_bounds; c.CubeSize = mesh_cell_size; c.Bounds.Expand(offset_distance + 3 * c.CubeSize); c.RootMode = MarchingCubes.RootfindingModes.LerpSteps; c.RootModeSteps = 5; c.CancelF = is_invalidated; c.Generate(); if (is_invalidated()) { return; } Reducer r = new Reducer(c.Mesh); r.FastCollapsePass(c.CubeSize * 0.5, 3, true); if (is_invalidated()) { return; } if (min_component_volume > 0) { MeshEditor.RemoveSmallComponents(c.Mesh, min_component_volume, min_component_volume); } if (is_invalidated()) { return; } ResultMesh = c.Mesh; }
public void genMesh(VoxelUpdateInfo info) { if (control == null) { return; } size = info.size; Queue <int[]> triangleSet = new Queue <int[]>(); vertices = new Dictionary <int, object>(); vertexSubstances = new Dictionary <int, byte>(); Voxel[, ,] voxels = createVoxelArray(info); MarchingCubes.setup(info.size / VOXEL_DIMENSION, control.isoLevel, ref vertices, ref vertexSubstances, ref voxels, position - new Vector3(0.5f, 0.5f, 0.5f) * size / VOXEL_DIMENSION, null); int totalTris = 0; for (byte x = (byte)(1 - xExtend), x1 = (byte)(x + 1); x1 < xDim; x = x1++) { for (byte y = (byte)(1 - yExtend), y1 = (byte)(y + 1); y1 < yDim; y = y1++) { for (byte z = (byte)(1 - zExtend), z1 = (byte)(z + 1); z1 < zDim; z = z1++) { lock (control) { VoxelHolder block = info.getSub(VOXEL_COUNT_POWER, VOXEL_DIMENSION + x, VOXEL_DIMENSION + y, VOXEL_DIMENSION + z); voxels[x1, y1, z1] = block.toVoxel(); int[] tris = MarchingCubes.lookupTriangles(x, y, z, x1, y1, z1); if (tris == null) { continue; } triangleSet.Enqueue(tris); totalTris += tris.Length; } } } } if (vertices.Count < 1) { applied = true; return; } List <int> triangles = new List <int>(); List <Vector3> finalVertices = new List <Vector3>(vertices.Count); //List<byte> finalMats = new List<byte>(vertices.Count); while (triangleSet.Count > 0) { int[] triangleList = triangleSet.Dequeue(); for (int i = 0; i < triangleList.Length; ++i) { if (vertices[triangleList[i]].GetType() == typeof(Vector3)) { finalVertices.Add((Vector3)vertices[triangleList[i]]); //finalMats.Add(vertexSubstances[triangleList[i]]); vertices[triangleList[i]] = finalVertices.Count - 1; } triangles.Add((int)vertices[triangleList[i]]); } } VERTS = finalVertices.ToArray(); TRIS = triangles.ToArray(); //MATS = finalMats.ToArray(); calcNorms(); alignEdge(info, 0, 1, 1); alignEdge(info, 2, 1, 1); alignEdge(info, 1, 0, 1); alignEdge(info, 1, 2, 1); alignEdge(info, 1, 1, 0); alignEdge(info, 1, 1, 2); lock (control) { control.enqueueJob(new ApplyMeshJob(this, info.detailLevel, info.x, info.y, info.z)); } }
/// <summary> /// Sample analytic winding number into grid in narrow-band around target isovalue, /// and then extract using marching cubes. /// /// TODO: don't need to discard current grid when isovalue changes, just need to /// re-run the front propagation part of mwn.Compute()! /// If this is done, then use this instead of update_winding_fast() for open meshes /// </summary> protected virtual void update_winding() { DMesh3 meshIn = MeshSource.GetDMeshUnsafe(); if (spatialPro == null || spatial_timestamp != meshIn.ShapeTimestamp) { spatialPro = new DMeshAABBTreePro(meshIn, true); spatialPro.FastWindingNumber(Vector3d.Zero); spatial_timestamp = meshIn.ShapeTimestamp; } if (is_invalidated()) { return; } if (cached_mwn_grid == null || grid_cell_size != cached_mwn_grid.CellSize || (float)winding_iso != cached_mwn_grid.IsoValue) { Func <Vector3d, double> fastWN = (q) => { return(spatialPro.FastWindingNumber(q)); }; var mwn = new MeshScalarSamplingGrid(meshIn, grid_cell_size, fastWN) { IsoValue = (float)winding_iso }; mwn.CancelF = is_invalidated; mwn.Compute(); if (is_invalidated()) { return; } cached_mwn_grid = mwn; cached_mwn_bounds = meshIn.CachedBounds; } MarchingCubes c = new MarchingCubes(); c.Implicit = new SampledGridImplicit(cached_mwn_grid); c.IsoValue = 0.0; c.Bounds = cached_mwn_bounds; c.CubeSize = mesh_cell_size; c.Bounds.Expand(3 * c.CubeSize); c.RootMode = MarchingCubes.RootfindingModes.Bisection; c.RootModeSteps = 10; c.CancelF = is_invalidated; c.Generate(); if (is_invalidated()) { return; } Reducer r = new Reducer(c.Mesh); r.FastCollapsePass(c.CubeSize * 0.5, 3, true); if (is_invalidated()) { return; } if (min_component_volume > 0) { MeshEditor.RemoveSmallComponents(c.Mesh, min_component_volume, min_component_volume); } if (is_invalidated()) { return; } // reproject - if we want to do this, we need to create spatial and meshIn above! gParallel.ForEach(c.Mesh.VertexIndices(), (vid) => { if (is_invalidated()) { return; } Vector3d v = c.Mesh.GetVertex(vid); int tid = spatialPro.FindNearestTriangle(v, grid_cell_size * MathUtil.SqrtTwo); if (tid != DMesh3.InvalidID) { var query = MeshQueries.TriangleDistance(meshIn, tid, v); if (v.Distance(query.TriangleClosest) < grid_cell_size) { c.Mesh.SetVertex(vid, query.TriangleClosest); } } }); if (is_invalidated()) { return; } ResultMesh = c.Mesh; }
public void addEdge(VoxelUpdateInfo info, byte x, byte y, byte z) { if (vertices == null) { return; } bool recalculate = false; Voxel[, ,] voxels = new Voxel[VERTEX_DIMENSION, VERTEX_DIMENSION, VERTEX_DIMENSION]; if (x == 0 /* && xExtend == 0*/) { recalculate = true; xExtend = 1; for (byte yi = (byte)(1 - yExtend); yi < yDim; ++yi) { for (byte zi = (byte)(1 - zExtend); zi < zDim; ++zi) { voxels[0, yi, zi] = info.getSub(VOXEL_COUNT_POWER, VOXEL_DIMENSION - xExtend, VOXEL_DIMENSION - 1 + yi, VOXEL_DIMENSION - 1 + zi).toVoxel(); voxels[1, yi, zi] = info.getSub(VOXEL_COUNT_POWER, VOXEL_DIMENSION, VOXEL_DIMENSION - 1 + yi, VOXEL_DIMENSION - 1 + zi).toVoxel(); } } } else if (x == 2 /* && xDim < VERTEX_DIMENSION*/) { recalculate = true; xDim = VERTEX_DIMENSION; for (byte yi = (byte)(1 - yExtend); yi < yDim; ++yi) { for (byte zi = (byte)(1 - zExtend); zi < zDim; ++zi) { voxels[VOXEL_DIMENSION + 1, yi, zi] = info.getSub(VOXEL_COUNT_POWER, VOXEL_DIMENSION * 2, VOXEL_DIMENSION - 1 + yi, VOXEL_DIMENSION - 1 + zi).toVoxel(); voxels[VOXEL_DIMENSION, yi, zi] = info.getSub(VOXEL_COUNT_POWER, VOXEL_DIMENSION * 2 - 1, VOXEL_DIMENSION - 1 + yi, VOXEL_DIMENSION - 1 + zi).toVoxel(); } } } else if (y == 0 /* && yExtend == 0*/) { recalculate = true; yExtend = 1; for (byte xi = (byte)(1 - xExtend); xi < xDim; ++xi) { for (byte zi = (byte)(1 - zExtend); zi < zDim; ++zi) { voxels[xi, 0, zi] = info.getSub(VOXEL_COUNT_POWER, VOXEL_DIMENSION - 1 + xi, VOXEL_DIMENSION - yExtend, VOXEL_DIMENSION - 1 + zi).toVoxel(); voxels[xi, 1, zi] = info.getSub(VOXEL_COUNT_POWER, VOXEL_DIMENSION - 1 + xi, VOXEL_DIMENSION, VOXEL_DIMENSION - 1 + zi).toVoxel(); } } } else if (y == 2 /* && yDim < VERTEX_DIMENSION*/) { recalculate = true; yDim = VERTEX_DIMENSION; for (byte xi = (byte)(1 - xExtend); xi < xDim; ++xi) { for (byte zi = (byte)(1 - zExtend); zi < zDim; ++zi) { voxels[xi, VOXEL_DIMENSION + 1, zi] = info.getSub(VOXEL_COUNT_POWER, VOXEL_DIMENSION - 1 + xi, VOXEL_DIMENSION * 2, VOXEL_DIMENSION - 1 + zi).toVoxel(); voxels[xi, VOXEL_DIMENSION, zi] = info.getSub(VOXEL_COUNT_POWER, VOXEL_DIMENSION - 1 + xi, VOXEL_DIMENSION * 2 - 1, VOXEL_DIMENSION - 1 + zi).toVoxel(); } } } else if (z == 0 /* && zExtend == 0*/) { recalculate = true; zExtend = 1; for (byte xi = (byte)(1 - xExtend); xi < xDim; ++xi) { for (byte yi = (byte)(1 - yExtend); yi < yDim; ++yi) { voxels[xi, yi, 0] = info.getSub(VOXEL_COUNT_POWER, VOXEL_DIMENSION - 1 + xi, VOXEL_DIMENSION - 1 + yi, VOXEL_DIMENSION - zExtend).toVoxel(); voxels[xi, yi, 1] = info.getSub(VOXEL_COUNT_POWER, VOXEL_DIMENSION - 1 + xi, VOXEL_DIMENSION - 1 + yi, VOXEL_DIMENSION).toVoxel(); } } } else if (z == 2 /* && zDim < VERTEX_DIMENSION*/) { recalculate = true; zDim = VERTEX_DIMENSION; for (byte xi = (byte)(1 - xExtend); xi < xDim; ++xi) { for (byte yi = (byte)(1 - yExtend); yi < yDim; ++yi) { voxels[xi, yi, VOXEL_DIMENSION + 1] = info.getSub(VOXEL_COUNT_POWER, VOXEL_DIMENSION - 1 + xi, VOXEL_DIMENSION - 1 + yi, VOXEL_DIMENSION * 2).toVoxel(); voxels[xi, yi, VOXEL_DIMENSION] = info.getSub(VOXEL_COUNT_POWER, VOXEL_DIMENSION - 1 + xi, VOXEL_DIMENSION - 1 + yi, VOXEL_DIMENSION * 2 - 1).toVoxel(); } } } if (recalculate) { Queue <int[]> triangleSet = new Queue <int[]>(); MarchingCubes.setup(info.size / VOXEL_DIMENSION, control.isoLevel, ref vertices, ref vertexSubstances, ref voxels, position - new Vector3(0.5f, 0.5f, 0.5f) * size / VOXEL_DIMENSION, VERTS); byte xStart = (byte)(1 - xExtend + (VOXEL_DIMENSION + xExtend - 1) * (x / 2)); byte xEnd = (byte)(2 + (xDim - 2) * ((x + 1) / 2)); byte yStart = (byte)(1 - yExtend + (VOXEL_DIMENSION + yExtend - 1) * (y / 2)); byte yEnd = (byte)(2 + (yDim - 2) * ((y + 1) / 2)); byte zStart = (byte)(1 - zExtend + (VOXEL_DIMENSION + zExtend - 1) * (z / 2)); byte zEnd = (byte)(2 + (zDim - 2) * ((z + 1) / 2)); for (byte xi = xStart, x1 = (byte)(xi + 1); x1 < xEnd; xi = x1++) { for (byte yi = yStart, y1 = (byte)(yi + 1); y1 < yEnd; yi = y1++) { for (byte zi = zStart, z1 = (byte)(zi + 1); z1 < zEnd; zi = z1++) { int[] tris = MarchingCubes.lookupTriangles(xi, yi, zi, x1, y1, z1); if (tris == null) { continue; } triangleSet.Enqueue(tris); } } } if (vertices.Count < 1) { return; } List <int> newTriangles = new List <int>(TRIS); List <Vector3> newVertices = new List <Vector3>(VERTS); int tri = 0; while (triangleSet.Count > 0) { int[] triangleList = triangleSet.Dequeue(); for (int i = 0; i < triangleList.Length; ++i) { if (vertices[triangleList[i]].GetType() == typeof(Vector3)) { newVertices.Add((Vector3)vertices[triangleList[i]]); vertices[triangleList[i]] = newVertices.Count - 1; } newTriangles.Add((int)vertices[triangleList[i]]); } tri += triangleList.Length; } Vector3[] finalNorms = new Vector3[newVertices.Count]; Array.Copy(NORMS, finalNorms, NORMS.Length); int oldNormCount = NORMS.Length; VERTS = newVertices.ToArray(); TRIS = newTriangles.ToArray(); calcNorms(); Array.Copy(NORMS, oldNormCount, finalNorms, oldNormCount, finalNorms.Length - oldNormCount); NORMS = finalNorms; } alignEdge(info, x, y, z); control.enqueueJob(new ApplyMeshJob(this, info.detailLevel, info.x, info.y, info.z)); }