/// <summary> /// Calculate the sphere-space position of the patch by determining where the center vertex lies on the sphere /// </summary> private void CalculatePatchPosition(TerrainNodeSplitItem item) { // find the cube position of the center vertex double x = bounds.Left + bounds.Width / 2; double y = bounds.Bottom + bounds.Height / 2; // get the matrix used to rotate the a position to the appropriate cube face Matrix faceMatrix = CubeFaces.GetFace(bounds.Face).FaceMatrix; // create the vertex position in cube-space and rotate it to the appropriate face Position3 cubePosition = new Position3(x, y, 1); cubePosition.Transform(ref faceMatrix); // get the vertex position on the unit sphere and rotate it to the appropriate face Position3 spherePosition = Tools.CubeToSphereMapping(x, y, 1); spherePosition.Transform(ref faceMatrix); spherePosition.Normalize(); Vector2 patchPosition = new Vector2(Constants.PatchWidth / 2, Constants.PatchHeight / 2); if (item == null) { // transform the vertex based on the user defined delegate - this returns the height value of the point on the sphere createPosition(ref spherePosition, ref cubePosition, ref patchPosition, radius, out position); } else { double h = item.HeightData[(int)((patchPosition.Y + 1) * (Constants.PatchWidth + 2) + (patchPosition.X + 1))]; if (h < 0) h = 0; position = spherePosition * (radius + h); } }
/// <summary> /// Generate terrain mesh for this node /// </summary> public void GenerateMesh(TerrainNodeSplitItem item) { // the minus one here is correct: e.g. 3x3 vertices labeled 0, 1, 2: v0.x = 0, v1.x = 0.5, v2.x = 1. The increment = 1 / (3 - 1) = 0.5 double horizontalStep = bounds.Width / (Constants.PatchWidth - 1); double verticalStep = bounds.Height / (Constants.PatchHeight - 1); float horizontalTextureStep = 1.0f / (Constants.PatchWidth - 1); float verticalTextureStep = 1.0f / (Constants.PatchHeight - 1); float MinX, MinY, MinZ; float MaxX, MaxY, MaxZ; // initialize min and max vertex tracking MinX = MinY = MinZ = 999999; MaxX = MaxY = MaxZ = -999999; // get matrix used to transform vertices to the proper cube face Matrix faceMatrix = CubeFaces.GetFace(bounds.Face).FaceMatrix; // create vertex storage using user supplied delegate vertexBuffer = createTerrainNodeVertexBuffer(item.HeightData.Length); //int cubeVertexIndex = 0; //CubeVertices = new Vector2[item.HeightData.Length]; hasMeshBorder = false; int vertexIndex = 0; int Rows = Constants.PatchHeight; int Columns = Constants.PatchWidth; if (item.HeightData.Length > Constants.PatchWidth * Constants.PatchHeight) { hasMeshBorder = true; Rows += 2; Columns += 2; } patchRows = Rows; patchColumns = Columns; float v = 0; double y = bounds.Bottom; if (hasMeshBorder) { v -= verticalTextureStep; y -= verticalStep; } for (int hy = 0; hy < Rows; hy++) { float u = 0; double x = bounds.Left; if (hasMeshBorder) { u -= horizontalTextureStep; x -= horizontalStep; } for (int hx = 0; hx < Columns; hx++) { // create the vertex position and rotate it to the appropriate face Position3 cubePosition = new Position3(x, y, 1); Position3 spherePosition = Tools.CubeToSphereMapping(x, y, 1); spherePosition.Transform(ref faceMatrix); cubePosition.Transform(ref faceMatrix); // transform the vertex based on the user defined delegate double height; Position3 finalPosition; Vector2 patchPosition = new Vector2(hx, hy); if (item == null) CreatePosition(ref spherePosition, ref cubePosition, ref patchPosition, out finalPosition, out height); else { height = item.HeightData[hy * Columns + hx]; if (height < 0) height = 0; finalPosition = spherePosition * (radius + height); TranslateToPatchSpace(ref finalPosition); } VertexPositionNormalTextureHeight vertex = new VertexPositionNormalTextureHeight(); vertex.Position = (Vector3)finalPosition; vertex.Height = (float)height; vertex.Normal = (Vector3)spherePosition; vertex.TextureCoordinate = new Vector2(u, v); vertex.Tangent = Vector4.Zero; vertexBuffer.Vertices[vertexIndex++] = vertex; // track min and max coordinates, but only for the vertices that will be in the final mesh if (hx >= 1 && hx < Columns - 1 && hy >= 1 && hy < Rows - 1) { if (vertex.Position.X < MinX) MinX = vertex.Position.X; if (vertex.Position.Y < MinY) MinY = vertex.Position.Y; if (vertex.Position.Z < MinZ) MinZ = vertex.Position.Z; if (vertex.Position.X > MaxX) MaxX = vertex.Position.X; if (vertex.Position.Y > MaxY) MaxY = vertex.Position.Y; if (vertex.Position.Z > MaxZ) MaxZ = vertex.Position.Z; } x += horizontalStep; u += horizontalTextureStep; } y += verticalStep; v += verticalTextureStep; } // create min and max bounding vertices, in patch-space minVertex = new Vector3(MinX, MinY, MinZ); maxVertex = new Vector3(MaxX, MaxY, MaxZ); // calculate normals and tangents CalculateNormals(); CalculateTangents(); // save vertex buffer changes - this effectively copies the raw data to a vertex buffer on the device vertexBuffer.CommitChanges(Constants.PatchWidth, Constants.PatchHeight); }