public HeightmapChunk(Rectangle range, int mipLevel, HeightmapChunk left, HeightmapChunk top) : base(null, range) { Adjacent[3] = left; Adjacent[0] = top; if (left != null) { left.Adjacent[1] = this; } if (top != null) { top.Adjacent[2] = this; } MipLevel = mipLevel; }
//how the simplification works: //we generate a "maximum second derivative" map from the heightmap. //we then create a maximum value image pyramid with the maximum value in the 4 pixels beneath //when generating the mesh, we fall into quadrants below if the second derivative is above a threshold. public void GenerateFullTree() { //how the algorithm works: //build a base structure with quad trees Chunks = new List <HeightmapChunk>(); var levels = SecondDerivativePyramid.Length; var chunkSize = 1 << levels; var cw = Size / chunkSize; for (int y = 0; y < Size; y += chunkSize) { for (int x = 0; x < Size; x += chunkSize) { var chunk = new HeightmapChunk(new Rectangle(x, y, chunkSize, chunkSize), levels, (x == 0) ? null : Chunks.Last(), (y == 0) ? null : Chunks[Chunks.Count - cw]); Chunks.Add(chunk); } } var thresholds = HighDetailThresholds; var toTraverse = new Queue <HeightmapQuadTreeNode>(Chunks); while (toTraverse.Count > 0) { var node = toTraverse.Dequeue(); var mipLevel = node.MipLevel; var sd = SecondDerivativePyramid[mipLevel - 1]; var mipWidth = Size >> (mipLevel - 1); var pos = (node.Range.X >> (mipLevel - 1)) + (node.Range.Y >> (mipLevel - 1)) * mipWidth; //check the max second derivative of the 4 potential derivatives. var threshold = HighDetailThresholds[mipLevel - 1]; if (sd[pos] >= threshold) //top left { var newNode = node.GetOrAdd(0, true); if (mipLevel > 1) { toTraverse.Enqueue(newNode); } } if (sd[pos + 1] >= threshold) //top right { var newNode = node.GetOrAdd(1, true); if (mipLevel > 1) { toTraverse.Enqueue(newNode); } } if (sd[pos + mipWidth] >= threshold) //bottom left { var newNode = node.GetOrAdd(2, true); if (mipLevel > 1) { toTraverse.Enqueue(newNode); } } if (sd[pos + mipWidth + 1] >= threshold) //top right { var newNode = node.GetOrAdd(3, true); if (mipLevel > 1) { toTraverse.Enqueue(newNode); } } } }