/// <summary> /// Outside code should only call this on the root. This method will recursively construct an entire quadtree starting /// from the root node. It will continue to expand a branch of the tree until any new nodes would have to /// have a resolution greater than that of the heightmap itself. /// </summary> public void RecursivelyBuildTree() { // Get this chunk's index. index = quadTree.GetNextChunkIndex(); // First compute the net world transform for this node. worldTransform = Matrix.CreateScale(scaleFactor, 1.0f, scaleFactor) * Matrix.CreateTranslation(centerWorldPosition); // Calculate the texture coordinate range for this chunk. textureCoordinates = new TerrainChunkTextureCoordinates(); float terrainDimension = 2 * quadTree.Parameters.TerrainScale; textureCoordinates.UStart = ((centerWorldPosition.X - scaleFactor / 2.0f + terrainDimension / 2.0f) / terrainDimension - 0.25f) * 2f; textureCoordinates.UEnd = ((centerWorldPosition.X + scaleFactor / 2.0f + terrainDimension / 2.0f) / terrainDimension - 0.25f) * 2f; textureCoordinates.VStart = ((centerWorldPosition.Z - scaleFactor / 2.0f + terrainDimension / 2.0f) / terrainDimension - 0.25f) * 2f; textureCoordinates.VEnd = ((centerWorldPosition.Z + scaleFactor / 2.0f + terrainDimension / 2.0f) / terrainDimension - 0.25f) * 2f; // Construct the bounding box to be used for frustum culling boundingBox = new BoundingBox(new Vector3(centerWorldPosition.X - scaleFactor / 2.0f, 0.0f, centerWorldPosition.Z - scaleFactor / 2.0f), new Vector3(centerWorldPosition.X + scaleFactor / 2.0f, quadTree.Parameters.MaxHeight, centerWorldPosition.Z + scaleFactor / 2.0f)); // If this node has a lower resolution than the heightmap itself, we expand it into four children. // Otherwise, this branch of the tree ends. children = new List<TerrainChunk>(); if (quadTree.HeightMap.Width / quadTree.Parameters.TerrainScale >= quadTree.CommonGrid.Dimension / scaleFactor) { // This isn't a leaf chunk, so we compute/look up its geometric error. if (quadTree.Parameters.DoPreprocessing) { // Compute it manually geometricError = ComputeRawGeometricError(); quadTree.ChunkGeometricErrors[index] = geometricError; } else { // Look it up from the precomputed table geometricError = quadTree.ChunkGeometricErrors[index]; } // Expand into four children TerrainChunk child1 = new TerrainChunk(quadTree, this, centerWorldPosition + new Vector3(scaleFactor / 4.0f, 0.0f, scaleFactor / 4.0f), scaleFactor / 2.0f); TerrainChunk child2 = new TerrainChunk(quadTree, this, centerWorldPosition + new Vector3(scaleFactor / 4.0f, 0.0f, -scaleFactor / 4.0f), scaleFactor / 2.0f); TerrainChunk child3 = new TerrainChunk(quadTree, this, centerWorldPosition + new Vector3(-scaleFactor / 4.0f, 0.0f, scaleFactor / 4.0f), scaleFactor / 2.0f); TerrainChunk child4 = new TerrainChunk(quadTree, this, centerWorldPosition + new Vector3(-scaleFactor / 4.0f, 0.0f, -scaleFactor / 4.0f), scaleFactor / 2.0f); children.Add(child1); children.Add(child2); children.Add(child3); children.Add(child4); child1.RecursivelyBuildTree(); child2.RecursivelyBuildTree(); child3.RecursivelyBuildTree(); child4.RecursivelyBuildTree(); } // Finally, as the recursion unwinds, we accumulate the geometric error from children. if (children.Count > 0) { geometricError += (float)Math.Max(children[0].GeometricError, Math.Max(children[1].GeometricError, Math.Max(children[2].GeometricError, children[3].GeometricError))); } minimumDistanceToSplit = geometricError / quadTree.Parameters.MaxScreenSpaceError * quadTree.Parameters.PerspectiveScalingFactor; }
/// <summary> /// Outside code should only call this on the root. This method will recursively construct an entire quadtree starting /// from the root node. It will continue to expand a branch of the tree until any new nodes would have to /// have a resolution greater than that of the heightmap itself. /// </summary> public void RecursivelyBuildTree() { // Get this chunk's index. index = quadTree.GetNextChunkIndex(); // First compute the net world transform for this node. worldTransform = Matrix.CreateScale(scaleFactor, 1.0f, scaleFactor) * Matrix.CreateTranslation(centerWorldPosition); // Calculate the texture coordinate range for this chunk. textureCoordinates = new TerrainChunkTextureCoordinates(); float terrainDimension = 2 * quadTree.Parameters.TerrainScale; textureCoordinates.UStart = ((centerWorldPosition.X - scaleFactor / 2.0f + terrainDimension / 2.0f) / terrainDimension - 0.25f) * 2f; textureCoordinates.UEnd = ((centerWorldPosition.X + scaleFactor / 2.0f + terrainDimension / 2.0f) / terrainDimension - 0.25f) * 2f; textureCoordinates.VStart = ((centerWorldPosition.Z - scaleFactor / 2.0f + terrainDimension / 2.0f) / terrainDimension - 0.25f) * 2f; textureCoordinates.VEnd = ((centerWorldPosition.Z + scaleFactor / 2.0f + terrainDimension / 2.0f) / terrainDimension - 0.25f) * 2f; // Construct the bounding box to be used for frustum culling boundingBox = new BoundingBox(new Vector3(centerWorldPosition.X - scaleFactor / 2.0f, 0.0f, centerWorldPosition.Z - scaleFactor / 2.0f), new Vector3(centerWorldPosition.X + scaleFactor / 2.0f, quadTree.Parameters.MaxHeight, centerWorldPosition.Z + scaleFactor / 2.0f)); // If this node has a lower resolution than the heightmap itself, we expand it into four children. // Otherwise, this branch of the tree ends. children = new List <TerrainChunk>(); if (quadTree.HeightMap.Width / quadTree.Parameters.TerrainScale >= quadTree.CommonGrid.Dimension / scaleFactor) { // This isn't a leaf chunk, so we compute/look up its geometric error. if (quadTree.Parameters.DoPreprocessing) { // Compute it manually geometricError = ComputeRawGeometricError(); quadTree.ChunkGeometricErrors[index] = geometricError; } else { // Look it up from the precomputed table geometricError = quadTree.ChunkGeometricErrors[index]; } // Expand into four children TerrainChunk child1 = new TerrainChunk(quadTree, this, centerWorldPosition + new Vector3(scaleFactor / 4.0f, 0.0f, scaleFactor / 4.0f), scaleFactor / 2.0f); TerrainChunk child2 = new TerrainChunk(quadTree, this, centerWorldPosition + new Vector3(scaleFactor / 4.0f, 0.0f, -scaleFactor / 4.0f), scaleFactor / 2.0f); TerrainChunk child3 = new TerrainChunk(quadTree, this, centerWorldPosition + new Vector3(-scaleFactor / 4.0f, 0.0f, scaleFactor / 4.0f), scaleFactor / 2.0f); TerrainChunk child4 = new TerrainChunk(quadTree, this, centerWorldPosition + new Vector3(-scaleFactor / 4.0f, 0.0f, -scaleFactor / 4.0f), scaleFactor / 2.0f); children.Add(child1); children.Add(child2); children.Add(child3); children.Add(child4); child1.RecursivelyBuildTree(); child2.RecursivelyBuildTree(); child3.RecursivelyBuildTree(); child4.RecursivelyBuildTree(); } // Finally, as the recursion unwinds, we accumulate the geometric error from children. if (children.Count > 0) { geometricError += (float)Math.Max(children[0].GeometricError, Math.Max(children[1].GeometricError, Math.Max(children[2].GeometricError, children[3].GeometricError))); } minimumDistanceToSplit = geometricError / quadTree.Parameters.MaxScreenSpaceError * quadTree.Parameters.PerspectiveScalingFactor; }