/// <summary> /// Looks for all visual mesh tasks and writes the generated meshes to the chunk. /// </summary> /// <param name="taskStack">The task stack.</param> /// <param name="chunk">The chunk to update.</param> private void UpdateVisualMesh(RemeshTaskStack taskStack, BlockChunk chunk) { var meshFilter = chunk.GetComponent <MeshFilter>(); var meshRenderer = chunk.GetComponent <MeshRenderer>(); var visualMesh = meshFilter.sharedMesh; ApplyVertexData <VisualRemeshTask>(taskStack, visualMesh); var materials = new Material[visualMesh.subMeshCount]; int baseVertex = 0; int submeshIndex = 0; for (int i = 0; i < taskStack.TaskCount; i++) { var task = taskStack.GetTask(i); if (task is VisualRemeshTask vis) { var newMesh = vis.Finish(); visualMesh.SetTriangles(newMesh.Triangles, submeshIndex, true, baseVertex); materials[submeshIndex] = m_BlockList.GetMaterial(vis.MaterialID); submeshIndex++; baseVertex += newMesh.Vertices.Count; } } meshFilter.sharedMesh = visualMesh; meshRenderer.sharedMaterials = materials; }
/// <summary> /// Looks for all collision mesh tasks and writes the generated meshes to the chunk. /// </summary> /// <param name="taskStack">The task stack.</param> /// <param name="chunk">The chunk to update.</param> private void UpdateCollisionMesh(RemeshTaskStack taskStack, BlockChunk chunk) { var meshCollider = chunk.GetComponent <MeshCollider>(); var collisionMesh = meshCollider.sharedMesh; ApplyVertexData <CollisionRemeshTask>(taskStack, collisionMesh); int baseVertex = 0; int submeshIndex = 0; for (int i = 0; i < taskStack.TaskCount; i++) { var task = taskStack.GetTask(i); if (task is CollisionRemeshTask vis) { var newMesh = vis.Finish(); collisionMesh.SetTriangles(newMesh.Triangles, submeshIndex, true, baseVertex); submeshIndex++; baseVertex += newMesh.Vertices.Count; } } meshCollider.sharedMesh = collisionMesh; }
/// <summary> /// Updates mesh data for the given chunk. /// </summary> /// <param name="taskStack">The set of remesh tasks.</param> /// <param name="chunk">The chunk to update.</param> internal void UpdateMesh(RemeshTaskStack taskStack, BlockChunk chunk) { UpdateVisualMesh(taskStack, chunk); UpdateCollisionMesh(taskStack, chunk); m_ProcMesh.Clear(); }
/// <summary> /// Iterates over all blocks in the chunk, creating visual tasks as needed. /// </summary> /// <param name="properties">The chunk properties.</param> /// <param name="tasks">The task list to add to.</param> private void VisualBlockIterator(ChunkProperties properties, RemeshTaskStack taskStack) { var volume = m_BlockWorld.ChunkSize.Volume; var blocks = properties.Blocks; for (int i = 0; i < volume; i++) { var type = blocks[i]; if (!type.IsVisible) { continue; } var faces = type.Faces; for (int j = 0; j < 6; j++) { var material = faces[j].MaterialID; if (m_MaterialBuffer[material]) { continue; } m_MaterialBuffer[material] = true; taskStack.AddTask(new VisualRemeshTask(properties, material, PullMesher())); } } }
/// <summary> /// Iterates over all blocks in the chunk, creating visual tasks as needed. /// </summary> /// <param name="properties">The chunk properties.</param> /// <param name="tasks">The task list to add to.</param> private void VisualBlockIterator(ChunkGroup properties, RemeshTaskStack taskStack) { var volume = m_ChunkSize.Volume; var blocks = properties.Blocks; for (int i = 0; i < volume; i++) { var type = m_BlockList.GetBlockType(blocks[i]); if (!type.Visible) { continue; } // TODO Make sure block type is a cube for (int j = 0; j < type.FaceCount; j++) { var material = type.Face(j).MaterialID; if (m_MaterialBuffer[material]) { continue; } m_MaterialBuffer[material] = true; taskStack.AddTask(new VisualRemeshTask(properties, material, PullMesher())); } } }
/// <summary> /// Retrieves vertex data from the task stack and writes it to the mesh object. /// </summary> /// <param name="taskStack">The task stack to pull from.</param> /// <param name="mesh">The mesh to write to.</param> /// <typeparam name="T">The type of tasks to look for in the stack.</typeparam> private void ApplyVertexData <T>(RemeshTaskStack taskStack, Mesh mesh) { GetVertexData <T>(taskStack, out int submeshCount); mesh.Clear(); mesh.subMeshCount = submeshCount; mesh.SetVertices(m_ProcMesh.Vertices); mesh.SetNormals(m_ProcMesh.Normals); mesh.SetUVs(0, m_ProcMesh.UVs); }
/// <summary> /// Analyses the given chunk and starts a set of remesh tasks for handling that chunk. /// This method blocks until all remesh tasks have been completed. /// </summary> /// <param name="worldContainer">The world to operate on.</param> /// <param name="chunkPos">The chunk target position.</param> internal RemeshTaskStack RemeshChunk(WorldContainer worldContainer, ChunkPosition chunkPos) { var taskStack = new RemeshTaskStack(chunkPos); var chunkGroup = new ChunkGroup(worldContainer, chunkPos); foreach (var dis in m_Distributors) { dis.CreateTasks(chunkGroup, taskStack); } return(taskStack); }
/// <summary> /// Generates the collision remesh task, as needed. /// </summary> /// <param name="properties">The chunk properties.</param> /// <param name="tasks">The task list to add to.</param> private void GenerateCollision(ChunkProperties properties, RemeshTaskStack taskStack) { int volume = m_BlockWorld.ChunkSize.Volume; for (int i = 0; i < volume; i++) { var type = properties.Blocks[i]; if (type.IsSolid) { taskStack.AddTask(new CollisionRemeshTask(properties, PullMesher())); return; } } }
/// <summary> /// Generates the collision remesh task, as needed. /// </summary> /// <param name="properties">The chunk properties.</param> /// <param name="tasks">The task list to add to.</param> private void GenerateCollision(ChunkGroup properties, RemeshTaskStack taskStack) { int volume = m_ChunkSize.Volume; var blocks = properties.Blocks; for (int i = 0; i < volume; i++) { var type = m_BlockList.GetBlockType(blocks[i]); if (type.Solid) { taskStack.AddTask(new CollisionRemeshTask(properties, PullMesher())); return; } } }
/// <summary> /// Pulls vertex data from the task stack and puts it into the procMesh. /// </summary> /// <param name="taskStack">The task stack to pull from.</param> /// <param name="submeshCount">The number of submeshes being generated.</param> /// <typeparam name="T">The type of task to look for.</typeparam> private void GetVertexData <T>(RemeshTaskStack taskStack, out int submeshCount) { m_ProcMesh.Clear(); submeshCount = 0; for (int i = 0; i < taskStack.TaskCount; i++) { var task = taskStack.GetTask(i); if (task is T) { var newMesh = task.Finish(); m_ProcMesh.Vertices.AddRange(newMesh.Vertices); m_ProcMesh.Normals.AddRange(newMesh.Normals); m_ProcMesh.UVs.AddRange(newMesh.UVs); submeshCount++; } } }
/// <summary> /// Analyses the given chunk and starts a set of remesh tasks for handling that chunk. /// If the chunk was scheduled to be remeshed later, it will be immediately be remeshed. /// If the chunk is already being remeshed, this method does nothing. /// </summary> /// <param name="chunkPos">The chunk target position.</param> /// <param name="pendingTask"> /// If true, this task is allowed to task any number of frames to finish. Otherwise, the task /// is required to finish the next frame. /// </param> internal void RemeshChunk(ChunkPosition chunkPos, bool pendingTask = false) { for (int i = 0; i < m_ActiveTasks.Count; i++) { if (m_ActiveTasks[i].ChunkPosition.Equals(chunkPos)) { m_ActiveTasks[i].IsPendingTask = false; return; } } for (int i = 0; i < m_PendingRemesh.Count; i++) { if (m_PendingRemesh[i].Equals(chunkPos)) { m_PendingRemesh.RemoveAt(i); break; } } var properties = m_ChunkPropertiesPool.Pull(); var blockList = m_BlockWorld.BlockList; var world = m_BlockWorld.WorldContainer.World; ChunkAnalyzer.LoadProperties(properties, blockList, world, chunkPos); var taskStack = new RemeshTaskStack(properties); taskStack.IsPendingTask = pendingTask; m_ActiveTasks.Add(taskStack); foreach (var dis in m_Distributors) { dis.CreateTasks(properties, taskStack); } }
/// <summary> /// Generates the visual remeshing tasks, as needed. /// </summary> /// <param name="properties">The chunk properties.</param> /// <param name="tasks">The task list to add to.</param> private void GenerateVisuals(ChunkGroup properties, RemeshTaskStack taskStack) { PrepareMaterialBuffer(); VisualBlockIterator(properties, taskStack); ResetMaterialBuffer(); }
/// <inheritdoc cref="IRemeshTask"/> public void CreateTasks(ChunkGroup properties, RemeshTaskStack taskStack) { GenerateVisuals(properties, taskStack); GenerateCollision(properties, taskStack); }
/// <summary> /// Updates a chunk mesh based on the results of a finished task stack. /// </summary> /// <param name="task">The finished task stack.</param> private void BuildChunkMesh(RemeshTaskStack task) { var chunk = GetChunk(task.ChunkPosition); m_ChunkMeshBuilder.UpdateMesh(task, chunk); }