/// <summary>
        /// Constructor to set up terrain patch
        /// </summary>

        public TerrainPatch(GraphicsDevice graphicsDevice, Vector2 offset)
        {
            neighbors = new TerrainPatch[4];

            meshes      = new TerrainMesh[mipLevels];
            mapOffset   = offset;
            worldOffset = new Vector3(mapOffset.X * patchSize, 0f, -mapOffset.Y * patchSize);

            for (int i = 0; i < mipLevels; i++)
            {
                meshes[i] = new TerrainMesh(graphicsDevice, this, i);
            }
        }
Example #2
0
        /// <summary>
        /// Find the normals for each mesh vertex
        /// </summary>

        private void CalculateNormals(ushort[] indices, float heightScale)
        {
            int fullMeshSize = TerrainPatch.patchSize + 1;

            // store temporary normals
            Vector3[] vertexNormals = new Vector3[vertices.Length];

            for (int i = 0; i < vertices.Length; i++)
            {
                vertexNormals[i] = new Vector3(0.5f, 0.5f, 1f);
            }

            for (int i = 0; i < indices.Length / 3; i++)
            {
                int index0 = indices[i * 3];
                int index1 = indices[i * 3 + 1];
                int index2 = indices[i * 3 + 2];

                vertexNormals[index0] += Vector3.Up;
                vertexNormals[index1] += Vector3.Up;
                vertexNormals[index2] += Vector3.Up;

                //continue;

                Vector3 vertexPos0 = new Vector3
                                     (
                    vertices[index0].VertexID % fullMeshSize,
                    vertices[index0].VertexHeight * heightScale,
                    -(int)(vertices[index0].VertexID / fullMeshSize)
                                     );
                Vector3 vertexPos1 = new Vector3
                                     (
                    vertices[index1].VertexID % fullMeshSize,
                    vertices[index1].VertexHeight * heightScale,
                    -(int)(vertices[index1].VertexID / fullMeshSize)
                                     );
                Vector3 vertexPos2 = new Vector3
                                     (
                    vertices[index2].VertexID % fullMeshSize,
                    vertices[index2].VertexHeight * heightScale,
                    -(int)(vertices[index2].VertexID / fullMeshSize)
                                     );

                Vector3 side1  = vertexPos0 - vertexPos2;
                Vector3 side2  = vertexPos0 - vertexPos1;
                Vector3 normal = Vector3.Cross(side1, side2);

                vertexNormals[index0] += normal;
                vertexNormals[index1] += normal;
                vertexNormals[index2] += normal;
            }

            float epsilon = 0.0000001f;

            // Correct normalization
            for (int i = 0; i < vertices.Length; i++)
            {
                vertexNormals[i].Normalize();
                //continue;

                // Fix side edges and we're done for this vertex
                if (i % meshSize == meshSize - 1 && terrainPatch.mapOffset.X < Terrain.gridSize.X - 1)
                {
                    int         adjacent     = i - (meshSize - 1);
                    TerrainMesh adjacentMesh = terrainPatch.neighbors[3].Meshes[mipLevel];
                    vertices[i].NormalX = adjacentMesh.vertices[adjacent].NormalX;
                    vertices[i].NormalY = adjacentMesh.vertices[adjacent].NormalY;

                    continue;
                }

                // Fix top and bottom edges and we're done for this vertex
                if (i / meshSize == meshSize - 1 && terrainPatch.mapOffset.Y < Terrain.gridSize.Y - 1)
                {
                    int         adjacent     = i - (meshSize * (meshSize - 1));
                    TerrainMesh adjacentMesh = terrainPatch.neighbors[1].Meshes[mipLevel];
                    vertices[i].NormalX = adjacentMesh.vertices[adjacent].NormalX;
                    vertices[i].NormalY = adjacentMesh.vertices[adjacent].NormalY;

                    continue;
                }

                // Encode normal into 2 components

                Vector2 projectedNormal;
                float   absZ = Math.Abs(vertexNormals[i].Z) + 1.0f;
                projectedNormal.X = vertexNormals[i].X / absZ;
                projectedNormal.Y = vertexNormals[i].Y / absZ;

                // Convert unit circle to square
                // We add epsilon to avoid division by zero

                float   d = Math.Abs(projectedNormal.X) + Math.Abs(projectedNormal.Y) + epsilon;
                float   r = Vector2.Distance(projectedNormal, Vector2.Zero);
                Vector2 q = projectedNormal * r / d;

                // Mirror triangles to outer edge if z is negative

                float   negativeZ = Math.Max(-Math.Sign(vertexNormals[i].Z), 0f);
                Vector2 qSign     = new Vector2(Math.Sign(q.X), Math.Sign(q.Y));
                qSign.X = Math.Sign(qSign.X + 0.5f);
                qSign.Y = Math.Sign(qSign.Y + 0.5f);

                // Reflection: qr = q - 2 * n * (dot (q, n) - d) / dot (n, n)

                q -= negativeZ * (float)(Vector2.Dot(q, qSign) - 1.0) * qSign;
                vertices[i].NormalX = (short)(q.X * 32767);
                vertices[i].NormalY = (short)(q.Y * 32767);
            }
            // Finish reading normals
        }