public void MergeLeft(Heightmap leftTile, int transitionWidth) { if (leftTile == null) { throw new ArgumentNullException("leftTile"); } if (leftTile.Width != Width || leftTile.Depth != Depth) { throw new ArgumentException("Tiles must have equal widths and depths", "leftTile"); } if (transitionWidth >= Width) { throw new ArgumentException("Transition width must be less than tile width", "transitionWidth"); } for (int x = 0; x < transitionWidth; x++) { for (int z = 0; z < Depth; z++) { float leftEdgeHeight = leftTile.GetHeightValue(leftTile.Width - 1, z); float originalHeight = GetHeightValue(x, z); float newHeight = MathHelper.Lerp(leftEdgeHeight, originalHeight, (float)x / (transitionWidth - 1)); SetHeightValue(x, z, newHeight); } } }
// /// <summary> // /// Build a terrain patch. // /// </summary> // /// <param name="game"></param> // /// <param name="heightmap"></param> // /// <param name="worldMatrix"></param> // /// <param name="width"></param> // /// <param name="depth"></param> // /// <param name="offsetX"></param> // /// <param name="offsetZ"></param> // public static void BuildPatch(Game game, Heightmap heightmap, Matrix worldMatrix, int width, int depth, int offsetX, int offsetZ) // { // // } /// <summary> /// Build the vertex buffer as well as the bounding box. /// </summary> /// <param name="heightmap"></param> private void BuildVertexBuffer(Heightmap heightmap) { int index = 0; _boundingBox.Min.Y = float.MaxValue; _boundingBox.Max.Y = float.MinValue; Geometry = new VertexPositionNormalTexture[Width * Depth]; for (int z = _offsetZ; z < _offsetZ + Depth; ++z) { for (int x = _offsetX; x < _offsetX + Width; ++x) { // We need to connect the patches by increasing each patch width and depth by 1, // but this means the patches along some of the edges will run out of // heightmap data, so make sure we cap the index at the edge int cappedX = Math.Min(x, heightmap.Width - 1); int cappedZ = Math.Min(z, heightmap.Depth - 1); float height = heightmap.GetHeightValue(cappedX, cappedZ); if (height < _boundingBox.Min.Y) { _boundingBox.Min.Y = height; } if (height > _boundingBox.Max.Y) { _boundingBox.Max.Y = height; } var position = new Vector3(x, height, z); Vector3 normal; ComputeVertexNormal(heightmap, cappedX, cappedZ, out normal); Geometry[index] = new VertexPositionNormalTexture(position, normal, new Vector2(x, z)); ++index; } } }
/// <summary> /// Add two heightmaps together. /// </summary> /// <param name="heightmap"></param> public void AddHeightmap(Heightmap heightmap) { // Reject the heightmap if it doesn't fit. if ((_width != heightmap.Width) || (_depth != heightmap.Depth) || (_minimumHeight != heightmap.MinimumHeight) || (_maximumHeight != heightmap.MaximumHeight)) { return; } // Add the heightmaps together. for (int x = 0; x < _width; ++x) { for (int z = 0; z < _depth; ++z) { _heightValues[x + z * _width] = _heightValues[x + z * _width] + heightmap.GetHeightValue(x, z); } } }
/// <summary> /// Combine the heightmap with the passed heightmap. /// The amount variable is the ratio of the heightmap passed as a parameter. /// </summary> /// <param name="heightmap"></param> /// <param name="amount"></param> public void CombineHeightmap(Heightmap heightmap, float amount) { // Reject the heightmap if it doesn't fit. if ((_width != heightmap.Width) || (_depth != heightmap.Depth) || (_minimumHeight != heightmap.MinimumHeight) || (_maximumHeight != heightmap.MaximumHeight)) { return; } // Combine the heightmaps. // H1 = H1 * (1.0f - amount) + H2 * amount for (int x = 0; x < _width; ++x) { for (int z = 0; z < _depth; ++z) { _heightValues[x + z * _width] = _heightValues[x + z * _width] * (1.0f - amount) + heightmap.GetHeightValue(x, z) * amount; } } }
/// <summary> /// Combine the heightmap with the passed heightmap. /// The amount variable is the ratio of the heightmap passed as a parameter. /// </summary> /// <param name="heightmap"></param> /// <param name="amount"></param> public void CombineHeightmap(Heightmap heightmap, float amount) { // Reject the heightmap if it doesn't fit. if ((_width != heightmap.Width) || (_depth != heightmap.Depth) || (_minimumHeight != heightmap.MinimumHeight) || (_maximumHeight != heightmap.MaximumHeight)) { return; } // Combine the heightmaps. // H1 = H1 * (1.0f - amount) + H2 * amount for (int x = 0; x < _width; ++x) { for (int z = 0; z < _depth; ++z) { _heightValues[x + z*_width] = _heightValues[x + z*_width]*(1.0f - amount) + heightmap.GetHeightValue(x, z)*amount; } } }
/// <summary> /// Add two heightmaps together. /// </summary> /// <param name="heightmap"></param> public void AddHeightmap(Heightmap heightmap) { // Reject the heightmap if it doesn't fit. if ((_width != heightmap.Width) || (_depth != heightmap.Depth) || (_minimumHeight != heightmap.MinimumHeight) || (_maximumHeight != heightmap.MaximumHeight)) { return; } // Add the heightmaps together. for (int x = 0; x < _width; ++x) { for (int z = 0; z < _depth; ++z) { _heightValues[x + z*_width] = _heightValues[x + z*_width] + heightmap.GetHeightValue(x, z); } } }
public void MergeLeft(Heightmap leftTile, int transitionWidth) { if (leftTile == null) throw new ArgumentNullException("leftTile"); if (leftTile.Width != Width || leftTile.Depth != Depth) throw new ArgumentException("Tiles must have equal widths and depths", "leftTile"); if (transitionWidth >= Width) throw new ArgumentException("Transition width must be less than tile width", "transitionWidth"); for (int x = 0; x < transitionWidth; x++) { for (int z = 0; z < Depth; z++) { float leftEdgeHeight = leftTile.GetHeightValue(leftTile.Width - 1, z); float originalHeight = GetHeightValue(x, z); float newHeight = MathHelper.Lerp(leftEdgeHeight, originalHeight, (float) x/(transitionWidth - 1)); SetHeightValue(x, z, newHeight); } } }
/// <summary> /// Compute vertex normal at the given x,z coordinate. /// </summary> /// <param name="heightmap"></param> /// <param name="x"></param> /// <param name="z"></param> /// <param name="normal"></param> private static void ComputeVertexNormal(Heightmap heightmap, int x, int z, out Vector3 normal) { int width = heightmap.Width; int depth = heightmap.Depth; Vector3 p1; Vector3 p2; Vector3 avgNormal = Vector3.Zero; int avgCount = 0; bool spaceAbove = false; bool spaceBelow = false; bool spaceLeft = false; bool spaceRight = false; Vector3 tmpNormal; Vector3 v1; Vector3 v2; var center = new Vector3(x, heightmap.GetHeightValue(x, z), z); if (x > 0) { spaceLeft = true; } if (x < width - 1) { spaceRight = true; } if (z > 0) { spaceAbove = true; } if (z < depth - 1) { spaceBelow = true; } if (spaceAbove && spaceLeft) { p1 = new Vector3(x - 1, heightmap.GetHeightValue(x - 1, z), z); p2 = new Vector3(x - 1, heightmap.GetHeightValue(x - 1, z - 1), z - 1); v1 = p1 - center; v2 = p2 - p1; tmpNormal = Vector3.Cross(v1, v2); avgNormal += tmpNormal; ++avgCount; } if (spaceAbove && spaceRight) { p1 = new Vector3(x, heightmap.GetHeightValue(x, z - 1), z - 1); p2 = new Vector3(x + 1, heightmap.GetHeightValue(x + 1, z - 1), z - 1); v1 = p1 - center; v2 = p2 - p1; tmpNormal = Vector3.Cross(v1, v2); avgNormal += tmpNormal; ++avgCount; } if (spaceBelow && spaceRight) { p1 = new Vector3(x + 1, heightmap.GetHeightValue(x + 1, z), z); p2 = new Vector3(x + 1, heightmap.GetHeightValue(x + 1, z + 1), z + 1); v1 = p1 - center; v2 = p2 - p1; tmpNormal = Vector3.Cross(v1, v2); avgNormal += tmpNormal; ++avgCount; } if (spaceBelow && spaceLeft) { p1 = new Vector3(x, heightmap.GetHeightValue(x, z + 1), z + 1); p2 = new Vector3(x - 1, heightmap.GetHeightValue(x - 1, z + 1), z + 1); v1 = p1 - center; v2 = p2 - p1; tmpNormal = Vector3.Cross(v1, v2); avgNormal += tmpNormal; ++avgCount; } normal = avgNormal / avgCount; }
// /// <summary> // /// Build a terrain patch. // /// </summary> // /// <param name="game"></param> // /// <param name="heightmap"></param> // /// <param name="worldMatrix"></param> // /// <param name="width"></param> // /// <param name="depth"></param> // /// <param name="offsetX"></param> // /// <param name="offsetZ"></param> // public static void BuildPatch(Game game, Heightmap heightmap, Matrix worldMatrix, int width, int depth, int offsetX, int offsetZ) // { // // } /// <summary> /// Build the vertex buffer as well as the bounding box. /// </summary> /// <param name="heightmap"></param> private void BuildVertexBuffer(Heightmap heightmap) { int index = 0; _boundingBox.Min.Y = float.MaxValue; _boundingBox.Max.Y = float.MinValue; Geometry = new VertexPositionNormalTexture[Width*Depth]; for (int z = _offsetZ; z < _offsetZ + Depth; ++z) { for (int x = _offsetX; x < _offsetX + Width; ++x) { // We need to connect the patches by increasing each patch width and depth by 1, // but this means the patches along some of the edges will run out of // heightmap data, so make sure we cap the index at the edge int cappedX = Math.Min(x, heightmap.Width - 1); int cappedZ = Math.Min(z, heightmap.Depth - 1); float height = heightmap.GetHeightValue(cappedX, cappedZ); if (height < _boundingBox.Min.Y) { _boundingBox.Min.Y = height; } if (height > _boundingBox.Max.Y) { _boundingBox.Max.Y = height; } var position = new Vector3(x, height, z); Vector3 normal; ComputeVertexNormal(heightmap, cappedX, cappedZ, out normal); Geometry[index] = new VertexPositionNormalTexture(position, normal, new Vector2(x, z)); ++index; } } }
/// <summary> /// Compute vertex normal at the given x,z coordinate. /// </summary> /// <param name="heightmap"></param> /// <param name="x"></param> /// <param name="z"></param> /// <param name="normal"></param> private static void ComputeVertexNormal(Heightmap heightmap, int x, int z, out Vector3 normal) { int width = heightmap.Width; int depth = heightmap.Depth; Vector3 p1; Vector3 p2; Vector3 avgNormal = Vector3.Zero; int avgCount = 0; bool spaceAbove = false; bool spaceBelow = false; bool spaceLeft = false; bool spaceRight = false; Vector3 tmpNormal; Vector3 v1; Vector3 v2; var center = new Vector3(x, heightmap.GetHeightValue(x, z), z); if (x > 0) { spaceLeft = true; } if (x < width - 1) { spaceRight = true; } if (z > 0) { spaceAbove = true; } if (z < depth - 1) { spaceBelow = true; } if (spaceAbove && spaceLeft) { p1 = new Vector3(x - 1, heightmap.GetHeightValue(x - 1, z), z); p2 = new Vector3(x - 1, heightmap.GetHeightValue(x - 1, z - 1), z - 1); v1 = p1 - center; v2 = p2 - p1; tmpNormal = Vector3.Cross(v1, v2); avgNormal += tmpNormal; ++avgCount; } if (spaceAbove && spaceRight) { p1 = new Vector3(x, heightmap.GetHeightValue(x, z - 1), z - 1); p2 = new Vector3(x + 1, heightmap.GetHeightValue(x + 1, z - 1), z - 1); v1 = p1 - center; v2 = p2 - p1; tmpNormal = Vector3.Cross(v1, v2); avgNormal += tmpNormal; ++avgCount; } if (spaceBelow && spaceRight) { p1 = new Vector3(x + 1, heightmap.GetHeightValue(x + 1, z), z); p2 = new Vector3(x + 1, heightmap.GetHeightValue(x + 1, z + 1), z + 1); v1 = p1 - center; v2 = p2 - p1; tmpNormal = Vector3.Cross(v1, v2); avgNormal += tmpNormal; ++avgCount; } if (spaceBelow && spaceLeft) { p1 = new Vector3(x, heightmap.GetHeightValue(x, z + 1), z + 1); p2 = new Vector3(x - 1, heightmap.GetHeightValue(x - 1, z + 1), z + 1); v1 = p1 - center; v2 = p2 - p1; tmpNormal = Vector3.Cross(v1, v2); avgNormal += tmpNormal; ++avgCount; } normal = avgNormal/avgCount; }