/// <summary> /// Add this node to the terrain's batch. /// </summary> /// <param name="fullyContained">Whether this node is known to be fully contained within the clipping frustums, in which case it and its children do not need to check clipping against it.</param> /// <param name="viewPoint">The position that this node is being viewed from.</param> /// <param name="distance">Equal to the distance from the <paramref name="viewPoint"/> to the nearest point on this node. This is needed by parent nodes for sorting, so it is calculated there and then passed down.</param> public void Batch(bool fullyContained, ref Vector3d viewPoint, double distance) { if (!CheckClip(ref fullyContained)) { return; } double lodBlend = LodBlend(distance); if (lodBlend >= 1 && !IsLeaf) { TerrainTreeNode a = ChildTopLeft, b = ChildTopRight, c = ChildBottomLeft, d = ChildBottomRight; double ad = ChildTopLeft.DistanceTo(ref viewPoint); double bd = ChildTopRight.DistanceTo(ref viewPoint); double cd = ChildBottomLeft.DistanceTo(ref viewPoint); double dd = ChildBottomRight.DistanceTo(ref viewPoint); SortByDepth(ref ad, ref bd, ref cd, ref dd, ref a, ref b, ref c, ref d); a.Batch(fullyContained, ref viewPoint, ad); b.Batch(fullyContained, ref viewPoint, bd); c.Batch(fullyContained, ref viewPoint, cd); d.Batch(fullyContained, ref viewPoint, dd); return; } Terrain.AddInstanceArray(TexelCorner.X, TexelCorner.Y, Lod + lodBlend, TexelSize); }
internal PlanarTerrainBlock(PlanarTerrain terrain, Vector2i blockIndex) { this.terrain = terrain; this.blockIndex = blockIndex; int size = terrain.BlockSize; //heightTexture = new Texture2D(device, size, size, true, Format.Single, DepthFormat.None, 0, RenderTargetUsage.PlatformContents); //heightBackBuffer = new Texture2D(device, size, size, true, Format.Single, DepthFormat.None, 0, RenderTargetUsage.PlatformContents); treeRoot = new TerrainTreeNode(this, new Vector2i(0, 0), size, terrain.DeepestLod); DirtyTreeArea = new Box2i(0, 0, size, size); }
/// <summary> /// Generate the tree node. /// </summary> /// <param name="terrainBlock">The terrain this is a node within.</param> /// <param name="corner">The integer coordinates of the top-left corner of the tree node.</param> /// <param name="size">The size in cells of this tree node.</param> /// <param name="lod">The level of detail of this node. This decreases for each step down into the terrain until it reaches zero.</param> public TerrainTreeNode(PlanarTerrainBlock terrainBlock, Vector2i corner, int size, int lod) { if (size < TerrainBlockSize) { throw new Exception("Invalid terrain size - must be a power of 2 greater than " + TerrainBlockSize + "."); } this.terrainBlock = terrainBlock; pLod = lod; pTexelCorner = new Vector2d(corner.X, corner.Y) / Terrain.BlockSize; pTexelSize = size / (double)Terrain.BlockSize; pBox.Min = new Vector3d(corner.X, 0, corner.Y); pBox.Max = new Vector3d(corner.X + size, 0, corner.Y + size); pVertexCorner = new Vector2i(corner.X / TerrainBlockSize, corner.Y / TerrainBlockSize); if (size > TerrainBlockSize) { var hsize = size / 2; pChildTopLeft = new TerrainTreeNode(terrainBlock, corner, hsize, lod - 1); pChildTopRight = new TerrainTreeNode(terrainBlock, new Vector2i(corner.X + hsize, corner.Y), hsize, lod - 1); pChildBottomLeft = new TerrainTreeNode(terrainBlock, new Vector2i(corner.X, corner.Y + hsize), hsize, lod - 1); pChildBottomRight = new TerrainTreeNode(terrainBlock, new Vector2i(corner.X + hsize, corner.Y + hsize), hsize, lod - 1); } }
/// <summary> /// Return how much to blend between this LOD level and the next less detailed one. /// If this returns 1, then the node should be divided if possible. /// </summary> /// <param name="node"></param> /// <param name="distance"></param> /// <returns></returns> public virtual double NodeLodBlend(TerrainTreeNode node, double distance) { throw new NotImplementedException(); }
/// <summary> /// Return whether the node is contained in this module's clipping range. /// If this returns <see cref="Containment.Contains"/>, then any node with a smaller /// box must also be contained. /// </summary> /// <param name="node"></param> /// <returns></returns> public virtual Containment NodeClip(TerrainTreeNode node) { throw new NotImplementedException(); }
/// <summary>Sort the parameters so that smaller values are first. <paramref name="ad"/> is paired to <paramref name="a"/> and so on.</summary> static void SortByDepth(ref double ad, ref double bd, ref double cd, ref double dd, ref TerrainTreeNode a, ref TerrainTreeNode b, ref TerrainTreeNode c, ref TerrainTreeNode d) { if (bd < ad && bd < cd && bd < dd) { Extensions.Swap(ref ad, ref bd); Extensions.Swap(ref a, ref b); } else if (cd < ad && cd < bd && cd < dd) { Extensions.Swap(ref ad, ref cd); Extensions.Swap(ref a, ref c); } else if (dd < ad && dd < bd && dd < cd) { Extensions.Swap(ref ad, ref dd); Extensions.Swap(ref a, ref d); } if (cd < bd && cd < dd) { Extensions.Swap(ref bd, ref cd); Extensions.Swap(ref b, ref c); } else if (dd < bd && dd < cd) { Extensions.Swap(ref bd, ref dd); Extensions.Swap(ref b, ref d); } if (cd < dd) { Extensions.Swap(ref cd, ref dd); Extensions.Swap(ref c, ref d); } }