// an array of MeshFilters, with opaque mesh stored in 0; alpha test mesh stored in 1 public void UpdateChunk(Vector2Int pos, Mesh opaque, Mesh alphaTest) { ChunkInstance chunk; if (instances.ContainsKey(pos)) { chunk = instances[pos]; } else { chunk = new ChunkInstance(); instances[pos] = chunk; var obj = Instantiate(chunkPrefab, new Vector3(pos.x << Chunk.CHUNK_X_SHIFT, 0, pos.y << Chunk.CHUNK_Z_SHIFT), Quaternion.identity, transform); chunk.opaqueMeshFilter = obj.GetComponent <MeshFilter>(); chunk.opaqueMeshCollider = obj.GetComponent <MeshCollider>(); obj.GetComponent <MeshRenderer>().sharedMaterial = opaqueMaterial; var obj2 = Instantiate(chunkPrefab, new Vector3(pos.x << Chunk.CHUNK_X_SHIFT, 0, pos.y << Chunk.CHUNK_Z_SHIFT), Quaternion.identity, transform); chunk.alphaTestMeshFilter = obj2.GetComponent <MeshFilter>(); chunk.alphaTestMeshCollider = obj2.GetComponent <MeshCollider>(); obj2.GetComponent <MeshRenderer>().sharedMaterial = alphaMaterial; } chunk.opaqueMeshFilter.mesh = opaque; chunk.alphaTestMeshFilter.mesh = alphaTest; chunk.opaqueMeshCollider.sharedMesh = opaque; chunk.alphaTestMeshCollider.sharedMesh = alphaTest; if (enableStaticBatching) { StaticBatchingUtility.Combine(gameObject); } }
//create a new chunk GameObject. needs to be passed certain values and also be made a child of this object (for neatness) ChunkInstance CreateNewChunk(Vector3 worldPos, int lodProfile) { GameObject newChunk = new GameObject(GetName(worldPos)); newChunk.transform.parent = transform; newChunk.transform.position = worldPos + transform.position; ChunkInstance c = newChunk.AddComponent <ChunkInstance>(); c.Setup(worldPos, lodProfile, useCollisions); return(c); }
public void InstantiateChunk(BlockTerrain.Chunk c) { int index = Terrain.GetChunkIndex(c.chunkx, c.chunky); ChunkInstance instance = Terrain.chunkInstances[index]; instance.UpdateAll(c); instance.UpdateMesh(0); instance.UpdateMesh(1); chunkRenderer.AddChunk(index); //chunkInstanceManager.LoadChunkInstance(instance); }
public BlockTerrain() { chunks = new Chunk[terrainSize * terrainSize]; chunkStats = new ChunkStatus(terrainSize); chunkInstances = new ChunkInstance[terrainSize * terrainSize]; for (int i = 0; i < chunkInstances.Length; i++) { chunkInstances[i] = new ChunkInstance(); } }
//if infinite world is disabled, generate the simple grid of chunks void GenerateFixedChunks() { for (int x = 0; x < fixedChunkDimensions.x; x++) { for (int y = 0; y < fixedChunkDimensions.y; y++) { for (int z = 0; z < fixedChunkDimensions.z; z++) { Vector3 worldPos = new Vector3(x, y, z) * actualDimension; db.Generate(threadsPerAxis + 1, worldPos); ChunkInstance c = CreateNewChunk(worldPos, 0); GenerateChunkMesh(c); } } } }
//method which calls the marching cubes algorithm and recieves its data to create the mesh for a given chunk void GenerateChunkMesh(ChunkInstance c) { //basic stuff: get the lod, set the material to be right one for its lod level int lodModifier = lodProfiles[c.lodIndex].lodModifier; c.SetMat(lodProfiles[c.lodIndex].mat); marchCompute.SetInt("lodModifier", lodModifier); //init buffers so data can be properly collected later triangleBuffer.SetCounterValue(0); int threads = Mathf.Max(threadsPerAxis / lodModifier, 1); marchCompute.Dispatch(0, threads, threads, threads); //get length of triangles to be made ComputeBuffer.CopyCount(triangleBuffer, triCountBuffer, 0); int[] triCountArray = { 0 }; triCountBuffer.GetData(triCountArray); int numTris = triCountArray[0]; //retrieve triangle data Triangle[] triangles = new Triangle[numTris]; triangleBuffer.GetData(triangles, 0, 0, numTris); //get the vertices and triangles for the mesh Vector3[] vertices = new Vector3[numTris * 3]; int[] meshTriangles = new int[numTris * 3]; for (int i = 0; i < numTris; i++) { for (int j = 0; j < 3; j++) { meshTriangles[i * 3 + j] = i * 3 + j; vertices[i * 3 + j] = triangles[i][j]; } } c.mesh.Clear(); c.mesh.vertices = vertices; c.mesh.triangles = meshTriangles; c.mesh.RecalculateNormals(); if (useCollisions) { c.collider.enabled = false; c.collider.enabled = true; } }
void Export(string exportPath) { BlockTerrain terrain = FindObjectOfType <TerrainManager>().Terrain; int[] chunks = FindObjectOfType <ChunkRenderer>().RenderingChunks; List <Mesh> ms = new List <Mesh>(); List <Matrix4x4> ts = new List <Matrix4x4>(); for (int i = 0; i < chunks.Length; i++) { ChunkInstance instance = terrain.chunkInstances[chunks[i]]; ms.Add(instance.Meshes[0]); ts.Add(instance.transform); ms.Add(instance.Meshes[1]); ts.Add(instance.transform); } Export(exportPath, ms.ToArray(), ts.ToArray()); }
public override void _Ready() { GD.Print("Ready to create world!"); if (densityGeneratorPath == null) { GD.PushError("VoxelTerrain must have a Density Generator."); return; } densityGenerator = GetNode <DensityGenerator>(densityGeneratorPath); if (densityGenerator == null) { GD.PushError("VoxelTerrain could not locate the supplied Density Generator."); return; } if (observerPath == null) { GD.PushError("VoxelTerrain must have an observer."); return; } observer = GetNode <Spatial>(observerPath); if (observer == null) { GD.PushError("VoxelTerrain could not locate the supplied observer."); return; } if (!(observer is Camera)) { observer = (Camera)observer.FindNode("Camera"); } if (debugLabelPath != null) { debugLabel = GetNode <Label>(debugLabelPath); } for (int y = -5; y < 5; y++) { for (int z = -5; z <= 5; z++) { for (int x = -5; x <= 5; x++) { var at = new ChunkPosition(x, y, z); var chunk = new Chunk(at); AddChunk(chunk); var instance = new ChunkInstance(chunk) { MaterialOverride = material }; chunk.InitDensity(densityGenerator.GetDensity); AddChild(instance); } } } var origoChunk = chunks[new ChunkPosition(0, 0, 0)]; origoChunk.GetLuminance().Init(); origoChunk.ForEachChunk(chunk => chunk.TriangulateChunk()); SetPhysicsProcess(true); }
//handles which chunks should be created, updated, or destroyed if infiniteWorld is enabled void GenerateVisibleChunks() { Vector3 p = camera.transform.position; Vector3 pCoord = WorldPos2Coord(p); //iterates through the currently active chunks to find which ones need to be recycled (if in the wrong LOD for it's position or too far away to be seen) //if does need to be recycled, add them to the queue to be used later foreach (ChunkInstance c in chunks) { float sqrDis = Vector3.SqrMagnitude(ChunkPos2Centre(c.coord) - p); if (sqrDis > sqrViewDis || GetLODProfile(sqrDis) != c.lodIndex) { chunksToRecycle.Enqueue(c); chunkCoords.Remove(c.coord); } } //runs through the possible chunk positions. if there is a chunk at said position, move to the next. if there isn't, add one. int maxChunksInView = Mathf.CeilToInt(viewDistance / (float)actualDimension); for (int x = -maxChunksInView; x <= maxChunksInView; x++) { for (int y = -maxChunksInView; y <= maxChunksInView; y++) { for (int z = -maxChunksInView; z <= maxChunksInView; z++) { Vector3 worldPos = pCoord + new Vector3(x, y, z) * actualDimension; if (chunkCoords.Contains(worldPos)) { continue; } //make sure that chunk is close enough and also in the direction the player is facing. otherwise it doesn't need to be generated Vector3 centre = ChunkPos2Centre(worldPos); float sqrDis = Vector3.SqrMagnitude(centre - p); if (sqrDis <= sqrViewDis) { Bounds bounds = new Bounds(centre, Vector3.one * actualDimension); if (IsVisible(bounds)) { //now run the RNG to generate random terrain for our point db.Generate(threadsPerAxis + 1, worldPos); int lodProfile = GetLODProfile(sqrDis); //if we still have chunk GameObjects that were created previously and needed to be recycled, use one. if we don't, create a new GameObject. if (chunksToRecycle.Count > 0) { ChunkInstance c = chunksToRecycle.Dequeue(); c.name = GetName(worldPos); c.transform.position = transform.position + worldPos; c.coord = worldPos; c.lodIndex = lodProfile; GenerateChunkMesh(c); chunkCoords.Add(worldPos); } else { ChunkInstance c = CreateNewChunk(worldPos, lodProfile); GenerateChunkMesh(c); chunks.Add(c); chunkCoords.Add(worldPos); } } } } } } //if any chunks that were recycled and didn't end up being used, they can be destroyed while (chunksToRecycle.Count > 0) { ChunkInstance c = chunksToRecycle.Dequeue(); chunks.Remove(c); Destroy(c.gameObject); } }
public ExecutionQueueEntity(CompiledChunk chunk, ChunkInstance instance) { Chunk = chunk; Instance = instance; }
void RenderChunk(ChunkInstance instance) { Graphics.DrawMesh(instance.Meshes[0], instance.transform, terrain, chunkLayer, Camera.main); Graphics.DrawMesh(instance.Meshes[1], instance.transform, alaphaTest, chunkLayer, Camera.main); }