/// <summary> /// Create a new empty CachedMeshHolder /// </summary> private CachedMeshHolder CreateNewBlock(QuadTreeNode <NodeData> node) { GameObject block = GameObject.Instantiate(BlockPrefab); block.name = "Block_" + node.Depth; block.transform.SetParent(gameObject.transform); block.transform.localPosition = node.Position - node.Size * new Vector3(0.5f, 0, 0.5f); block.transform.localScale = new Vector3(node.Size, 1, node.Size); Mesh blockMesh = meshGenerator.BuildPatch(node.Position, node.Size, ResolutionMultiplier, HeightMap, HeightMultiplier); //blockMesh.RecalculateNormals(); // TO DO: place these heavy calculations somewhere else blockMesh.RecalculateBounds(); // TO DO: place these heavy calculations somewhere else block.GetComponent <MeshFilter>().mesh = blockMesh; //block.GetComponent<MeshFilter>().mesh.bounds = new Bounds(Vector3.zero, new Vector3(1, 0.5f, 1) * node.Size * 0.4f); block.GetComponent <MeshCollider>().sharedMesh = blockMesh; block.GetComponent <MeshRenderer>().material = TerrainMaterial; CachedMeshHolder holder = new CachedMeshHolder() { gameObject = block, filter = gameObject.GetComponent <MeshFilter>(), collider = gameObject.GetComponent <MeshCollider>(), renderer = gameObject.GetComponent <MeshRenderer>() }; return(holder); }
/// <summary> /// Either creates or shows the already existing mesh corresponding to this node /// </summary> private void ShowNode(QuadTreeNode <NodeData> node, HashSet <QuadTreeNode <NodeData> > newActiveNodes) { if (RenderTerrain) { // If there isn't already a mesh linked to this node if (RenderTerrain && !nodeMeshMap.ContainsKey(node)) { // Create an empty mesh holder object CachedMeshHolder container = CreateNewBlock(node); // Set chunk data...? // ... // Call highest detail action...? // ... // Add the newly created mesh to the lists activeMeshes.Add(container); nodeMeshMap[node] = container; } // Show the mesh nodeMeshMap[node].gameObject.SetActive(true); } // If the newActiveNodes don't already contain this node, add it if (!newActiveNodes.Contains(node)) { newActiveNodes.Add(node); } }
/// <summary> /// Pop an unused container from the queue, or generate new containers if required /// </summary> /// <returns></returns> private CachedMeshHolder PopMeshContainer() { while (meshPool.Count < 3) { GameObject g = new GameObject("Chunk"); g.transform.SetParent(go.transform); g.transform.localPosition = Vector3.zero; MeshFilter meshFilter = g.AddComponent <MeshFilter>(); Mesh m = new Mesh(); m.name = "Cached Chunk Mesh"; meshFilter.sharedMesh = m; MeshRenderer meshRenderer = g.AddComponent <MeshRenderer>(); meshRenderer.sharedMaterial = this.material; g.SetActive(false); MeshCollider collider = g.AddComponent <MeshCollider>(); collider.enabled = false; CachedMeshHolder holder = new CachedMeshHolder(); holder.gameObject = g; holder.filter = meshFilter; holder.collider = collider; meshPool.Enqueue(holder); } CachedMeshHolder container = meshPool.Dequeue(); return(container); }
private void ShowNode(QuadNode <ChunkData> node, HashSet <QuadNode <ChunkData> > activeList) { if (!chunkMeshMap.ContainsKey(node)) { //Buffer CachedMeshHolder container = PopMeshContainer(); MeshFilter filter = container.filter; //Populate mesh filter.sharedMesh = meshService.Make(node.range.a, node.range.b, node.range.d, node.range.c, this.radius).mesh; //filter.sharedMesh = SubPlane.Make(node.range.a, node.range.b, node.range.d, node.range.c, resolution); //Set chunk data if it was never computed before if (node.value.bounds == null) { node.value.bounds = new Sphere(Vector3.zero, 1); node.value.bounds.center = filter.sharedMesh.bounds.center; /*node.value.bounds.radius = Mathf.Max ( * filter.sharedMesh.bounds.extents.x, * filter.sharedMesh.bounds.extents.y, * filter.sharedMesh.bounds.extents.z * );*/ node.value.bounds.radius = Mathf.Sqrt( filter.sharedMesh.bounds.extents.x * filter.sharedMesh.bounds.extents.x + filter.sharedMesh.bounds.extents.y * filter.sharedMesh.bounds.extents.y + filter.sharedMesh.bounds.extents.z * filter.sharedMesh.bounds.extents.z ); } //Show node filter.gameObject.SetActive(true); //Call highest detail action if (node.depth == this.maxDepth) { //Call listeners if exists foreach (System.Action <QuadNode <ChunkData> > fn in this.listeners) { fn.Invoke(node); } //Call detailing service if available if (detailService != null) { detailService.ShowChunkDetails(node, filter.sharedMesh); } } //Add me if I don't already exist this.activeMeshes.Add(container); this.chunkMeshMap[node] = container; } if (!activeList.Contains(node)) { activeList.Add(node); } }
private void ShowNodeSplit(QuadNode <ChunkData> parent, MeshData[] meshes, HashSet <QuadNode <ChunkData> > activeList) { for (int i = 0; i < 4; i++) { QuadNode <ChunkData> child = parent[(Quadrant)i]; if (!chunkMeshMap.ContainsKey(child)) { //Buffer CachedMeshHolder container = PopMeshContainer(); MeshFilter filter = container.filter; filter.sharedMesh = meshes[i].mesh; container.collider.sharedMesh = filter.sharedMesh; container.collider.enabled = true; container.renderer.sharedMaterial = textureService.GetMaterialFor(this, child, filter.sharedMesh); if (child.value.bounds == null) { child.value.bounds = new Sphere(Vector3.zero, 1); child.value.bounds.center = filter.sharedMesh.bounds.center; child.value.bounds.radius = Mathf.Sqrt( filter.sharedMesh.bounds.extents.x * filter.sharedMesh.bounds.extents.x + filter.sharedMesh.bounds.extents.y * filter.sharedMesh.bounds.extents.y + filter.sharedMesh.bounds.extents.z * filter.sharedMesh.bounds.extents.z ); } //Show node filter.gameObject.SetActive(true); //Call highest detail action if (child.depth == this.maxDepth) { //Call listeners if exists foreach (System.Action <QuadNode <ChunkData> > fn in this.listeners) { fn.Invoke(child); } //Call detailing service if available if (detailService != null) { detailService.ShowChunkDetails(child, filter.sharedMesh); } } //Add me if I don't already exist this.activeMeshes.Add(container); this.chunkMeshMap[child] = container; } if (!activeList.Contains(child)) { activeList.Add(child); } } }
/// <summary> /// Pop an unused container from the queue, or generate new containers if required /// </summary> /// <returns></returns> private CachedMeshHolder PopMeshContainer() { PoolablePool meshPool = PoolManager.Current.CustomPool(PlanetFacePoolTag, 3, 3); while (meshPool.Count < 3) { GameObject g = new GameObject("Chunk"); g.transform.SetParent(go.transform); g.transform.localPosition = Vector3.zero; g.transform.localScale = Vector3.one; MeshFilter meshFilter = g.AddComponent <MeshFilter>(); Mesh m = new Mesh(); m.name = "Cached Chunk Mesh"; meshFilter.sharedMesh = m; MeshRenderer meshRenderer = g.AddComponent <MeshRenderer>(); meshRenderer.sharedMaterial = null; g.SetActive(false); MeshCollider collider = g.AddComponent <MeshCollider>(); //collider.enabled = false; CachedMeshHolder holder = new CachedMeshHolder(); holder.gameObject = g; holder.filter = meshFilter; holder.collider = collider; holder.renderer = meshRenderer; meshPool.Push(holder); } CachedMeshHolder container = (CachedMeshHolder)meshPool.Pop(); if (container.gameObject.transform.parent != go.transform) { container.gameObject.transform.SetParent(go.transform); container.gameObject.transform.localPosition = Vector3.zero; container.gameObject.transform.localScale = Vector3.one; } return(container); }
/// <summary> /// Basically ShowNode(...) but it runs 4 times, once for each child of the passed node /// </summary> private void ShowNodeSplit(QuadTreeNode <NodeData> node, HashSet <QuadTreeNode <NodeData> > newActiveNodes) { for (int i = 0; i < 4; i++) { QuadTreeNode <NodeData> subNode = node.SubNodes[i]; if (RenderTerrain) { // If there is no mesh corresponding to this node if (RenderTerrain && !nodeMeshMap.ContainsKey(subNode)) { // Create an empty mesh holder object CachedMeshHolder container = CreateNewBlock(subNode); // Set chunk data...? // ... // Call highest detail action...? // ... // Add the newly created mesh to the lists activeMeshes.Add(container); nodeMeshMap[subNode] = container; } // Show the subNode mesh nodeMeshMap[subNode].gameObject.SetActive(true); } // If the newActiveNodes don't already contain this node, add it if (!newActiveNodes.Contains(subNode)) { newActiveNodes.Add(subNode); } } // Discard the parent mesh DiscardNode(node); }
/// <summary> /// Merges 4 nodes into their parent /// </summary> private void ShowNodeMerge(QuadTreeNode <NodeData> node, HashSet <QuadTreeNode <NodeData> > newActiveList) { if (RenderTerrain) { // If there is no mesh corresponding to this node if (!nodeMeshMap.ContainsKey(node)) { // Create an empty mesh holder object CachedMeshHolder container = CreateNewBlock(node); // Set chunk data...? // ... // Call highest detail action...? // ... // Add the newly created mesh to the lists activeMeshes.Add(container); nodeMeshMap[node] = container; } // Show the node mesh nodeMeshMap[node].gameObject.SetActive(true); } // Discard children nodes foreach (var subNode in node.SubNodes) { DiscardNode(subNode); } // If the newActiveNodes don't already contain this node, add it if (!newActiveList.Contains(node)) { newActiveList.Add(node); } }