public TerrainModel(GraphicsDevice device,
                            int terrainSize, int terrainSegments, float terrainStart,
                            int xOffset, int zOffset, Vector3 terrainScale,
                            float[,] heightMap, float[,] roadMap,
                            Effect effect, DirectionalLight directionalLight)
        {
            this.device = device;

            int terrainSizeMinusOne = terrainSize;

            terrainSize++;

            int vertexCount = terrainSize * terrainSize;

            vertices = new MultitexturedVertex[vertexCount];

            for (int z = 0; z < terrainSize; z++)
            {
                for (int x = 0; x < terrainSize; x++)
                {
                    var textureWeights = new Vector4(
                        roadMap[xOffset + x, zOffset + z],
                        MathHelper.Clamp(1 - Math.Abs(heightMap[xOffset + x, zOffset + z] - 0.2f) / 0.4f, 0, 1),
                        MathHelper.Clamp(1 - Math.Abs(heightMap[xOffset + x, zOffset + z] - 0.7f) / 0.2f, 0, 1),
                        MathHelper.Clamp(1 - Math.Abs(heightMap[xOffset + x, zOffset + z] - 1) / 0.3f, 0, 1)
                        );

                    textureWeights.Normalize();

                    vertices[z * terrainSize + x] = new MultitexturedVertex(
                        terrainScale * new Vector3(
                            (terrainStart + xOffset + x),        // X
                            heightMap[xOffset + x, zOffset + z], // Y
                            (terrainStart + zOffset + z)),       // Z
                        Vector3.Zero,                            // Normal
                        Vector3.Zero,                            // Binormal
                        Vector3.Zero,                            // Tangent
                        new Vector2(x / 8f, z / 8f),
                        textureWeights);
                }
            }

            BoundingBox = BoundingBox.CreateFromPoints(vertices.Select(vert => vert.Position));

            //MinBox = BoundingBox.CreateFromPoints(new Vector3[] { BoundingBox.Min.GetXZProjection(false), BoundingBox.Max.GetXZProjection(false) });

            #region Indicies & Vertex normals setup

            int   flexIndice = 1;
            int   rowIndex   = 2;
            int[] indices    = new int[terrainSizeMinusOne * terrainSizeMinusOne * 6];
            indices[0] = 0;
            indices[1] = terrainSize;
            indices[2] = flexIndice;

            for (int i = 5; i <= indices.Length; i += 3)
            {
                indices[i - 2] = indices[i - 4];
                indices[i - 1] = indices[i - 3];

                if (i % 2 == 0)
                {
                    flexIndice -= terrainSizeMinusOne;
                    indices[i]  = flexIndice;
                }
                else
                {
                    flexIndice += terrainSize;
                    indices[i]  = flexIndice;
                }
                if (i + 3 >= indices.Length)
                {
                    break;
                }
                else if (rowIndex * terrainSize - 1 == indices[i])
                {
                    indices[i + 1] = flexIndice - terrainSize + 1;
                    indices[i + 2] = flexIndice + 1;
                    indices[i + 3] = flexIndice - terrainSize + 2;
                    flexIndice     = indices[i + 3];
                    rowIndex++;
                    i += 3;
                }
            }

            for (int i = 0; i < indices.Length / 3; i++)
            {
                Vector3 firstvec  = vertices[indices[i * 3]].Position;
                Vector3 secondvec = vertices[indices[i * 3 + 1]].Position;
                Vector3 thirdvec  = vertices[indices[i * 3 + 2]].Position;
                Vector3 firstsub  = secondvec - firstvec;
                Vector3 secondsub = thirdvec - firstvec;

                Vector3 normal;
                if (i % 2 == 0)
                {
                    normal = Vector3.Cross(firstsub, secondsub);
                }
                else
                {
                    normal = Vector3.Cross(secondsub, firstsub);
                }

                normal.Normalize();
                vertices[indices[i * 3]].Normal     += normal;
                vertices[indices[i * 3 + 1]].Normal += normal;
                vertices[indices[i * 3 + 2]].Normal += normal;

                #region Binormal & Tangent
                // Calculate binormal and tangent to get normal map to work
                // Retrieved from http://xboxforums.create.msdn.com/forums/p/30443/172880.aspx
                Vector2 w1 = vertices[indices[i * 3]].TextureCoordinate;
                Vector2 w2 = vertices[indices[i * 3 + 1]].TextureCoordinate;
                Vector2 w3 = vertices[indices[i * 3 + 2]].TextureCoordinate;

                float s1 = w2.X - w1.X,
                      s2 = w3.X - w1.X,
                      t1 = w2.Y - w1.Y,
                      t2 = w3.Y - w1.Y;

                float   r    = 1.0f / (s1 * t2 - s2 * t1);
                Vector3 sdir = new Vector3((t2 * firstsub.X - t1 * secondsub.X) * r, (t2 * firstsub.Y - t1 * secondsub.Y) * r, (t2 * firstsub.Z - t1 * secondsub.Z) * r);
                Vector3 tdir = new Vector3((s1 * secondsub.X - s2 * firstsub.X) * r, (s1 * secondsub.Y - s2 * firstsub.Y) * r, (s1 * secondsub.Z - s2 * firstsub.Z) * r);

                // Gram-Schmidt orthogonalize
                Vector3 tangent = sdir - normal * Vector3.Dot(normal, sdir);
                tangent.Normalize();

                // Calculate handedness (here maybe you need to switch >= with <= depend on the geometry winding order)
                float   tangentdir = (Vector3.Dot(Vector3.Cross(normal, sdir), tdir) <= 0.0f) ? 1.0f : -1.0f;
                Vector3 binormal   = Vector3.Cross(normal, tangent) * tangentdir;

                // Set the values to the vertices
                vertices[indices[i * 3]].Tangent     = tangent;
                vertices[indices[i * 3 + 1]].Tangent = tangent;
                vertices[indices[i * 3 + 2]].Tangent = tangent;

                vertices[indices[i * 3]].Binormal     = binormal;
                vertices[indices[i * 3 + 1]].Binormal = binormal;
                vertices[indices[i * 3 + 2]].Binormal = binormal;
                #endregion
            }

            for (int i = 0; i < vertices.Length; i++)
            {
                vertices[i].Normal.Normalize();
            }

            #endregion

            indexBuffer = new IndexBuffer(device, typeof(int), terrainSizeMinusOne * terrainSizeMinusOne * 6, BufferUsage.None);
            indexBuffer.SetData(indices);

            vertexBuffer = new VertexBuffer(device,
                                            typeof(MultitexturedVertex), vertices.Length,
                                            BufferUsage.None);
            vertexBuffer.SetData(vertices);

            #region Effect

            this.Effect    = effect;
            this.ShadowMap = new RenderTarget2D(device, 1024, 1024, false, SurfaceFormat.Single, DepthFormat.Depth24Stencil8);

            #endregion
        }
Пример #2
0
        public TerrainModel(GraphicsDevice device, 
            int terrainSize, int terrainSegments, float terrainStart,
            int xOffset, int zOffset, Vector3 terrainScale, 
            float[,] heightMap, float[,] roadMap,
            Effect effect, DirectionalLight directionalLight)
        {
            this.device = device;

            int terrainSizeMinusOne = terrainSize;
            terrainSize++;

            int vertexCount = terrainSize * terrainSize;
            vertices = new MultitexturedVertex[vertexCount];

            for (int z = 0; z < terrainSize; z++)
            {
                for (int x = 0; x < terrainSize; x++)
                {
                    var textureWeights = new Vector4(
                        roadMap[xOffset + x, zOffset + z],
                        MathHelper.Clamp(1 - Math.Abs(heightMap[xOffset + x, zOffset + z] - 0.2f) / 0.4f, 0, 1),
                        MathHelper.Clamp(1 - Math.Abs(heightMap[xOffset + x, zOffset + z] - 0.7f) / 0.2f, 0, 1),
                        MathHelper.Clamp(1 - Math.Abs(heightMap[xOffset + x, zOffset + z] - 1) / 0.3f, 0, 1)
                    );

                    textureWeights.Normalize();

                    vertices[z * terrainSize + x] = new MultitexturedVertex(
                        terrainScale * new Vector3(
                            (terrainStart + xOffset + x), // X
                            heightMap[xOffset + x, zOffset + z], // Y
                            (terrainStart + zOffset + z)), // Z
                        Vector3.Zero, // Normal
                        Vector3.Zero, // Binormal
                        Vector3.Zero, // Tangent
                        new Vector2(x / 8f, z / 8f),
                        textureWeights);

                }
            }

            BoundingBox = BoundingBox.CreateFromPoints(vertices.Select(vert => vert.Position));

            //MinBox = BoundingBox.CreateFromPoints(new Vector3[] { BoundingBox.Min.GetXZProjection(false), BoundingBox.Max.GetXZProjection(false) });

            #region Indicies & Vertex normals setup

            int flexIndice = 1;
            int rowIndex = 2;
            int[] indices = new int[terrainSizeMinusOne * terrainSizeMinusOne * 6];
            indices[0] = 0;
            indices[1] = terrainSize;
            indices[2] = flexIndice;

            for (int i = 5; i <= indices.Length; i += 3)
            {
                indices[i - 2] = indices[i - 4];
                indices[i - 1] = indices[i - 3];

                if (i % 2 == 0)
                {
                    flexIndice -= terrainSizeMinusOne;
                    indices[i] = flexIndice;
                }
                else
                {
                    flexIndice += terrainSize;
                    indices[i] = flexIndice;
                }
                if (i + 3 >= indices.Length)
                    break;
                else if (rowIndex * terrainSize - 1 == indices[i])
                {
                    indices[i + 1] = flexIndice - terrainSize + 1;
                    indices[i + 2] = flexIndice + 1;
                    indices[i + 3] = flexIndice - terrainSize + 2;
                    flexIndice = indices[i + 3];
                    rowIndex++;
                    i += 3;
                }
            }

            for (int i = 0; i < indices.Length / 3; i++)
            {
                Vector3 firstvec = vertices[indices[i * 3]].Position;
                Vector3 secondvec = vertices[indices[i * 3 + 1]].Position;
                Vector3 thirdvec = vertices[indices[i * 3 + 2]].Position;
                Vector3 firstsub = secondvec - firstvec;
                Vector3 secondsub = thirdvec - firstvec;

                Vector3 normal;
                if(i % 2 == 0)
                {
                    normal = Vector3.Cross(firstsub, secondsub);
                }else{
                    normal = Vector3.Cross(secondsub, firstsub);
                }

                normal.Normalize();
                vertices[indices[i * 3]].Normal += normal;
                vertices[indices[i * 3 + 1]].Normal += normal;
                vertices[indices[i * 3 + 2]].Normal += normal;

                #region Binormal & Tangent
                // Calculate binormal and tangent to get normal map to work
                // Retrieved from http://xboxforums.create.msdn.com/forums/p/30443/172880.aspx
                Vector2 w1 = vertices[indices[i * 3]].TextureCoordinate;
                Vector2 w2 = vertices[indices[i * 3  + 1]].TextureCoordinate;
                Vector2 w3 = vertices[indices[i * 3 + 2]].TextureCoordinate;

                float s1 = w2.X - w1.X,
                    s2 = w3.X - w1.X,
                    t1 = w2.Y - w1.Y,
                    t2 = w3.Y - w1.Y;

                float r = 1.0f / (s1 * t2 - s2 * t1);
                Vector3 sdir = new Vector3((t2 * firstsub.X - t1 * secondsub.X) * r, (t2 * firstsub.Y - t1 * secondsub.Y) * r, (t2 * firstsub.Z - t1 * secondsub.Z) * r);
                Vector3 tdir = new Vector3((s1 * secondsub.X - s2 * firstsub.X) * r, (s1 * secondsub.Y - s2 * firstsub.Y) * r, (s1 * secondsub.Z - s2 * firstsub.Z) * r);

                // Gram-Schmidt orthogonalize
                Vector3 tangent = sdir - normal * Vector3.Dot(normal, sdir);
                tangent.Normalize();

                // Calculate handedness (here maybe you need to switch >= with <= depend on the geometry winding order)
                float tangentdir = (Vector3.Dot(Vector3.Cross(normal, sdir), tdir) <= 0.0f) ? 1.0f : -1.0f;
                Vector3 binormal = Vector3.Cross(normal, tangent) * tangentdir;

                // Set the values to the vertices
                vertices[indices[i * 3]].Tangent = tangent;
                vertices[indices[i * 3 + 1]].Tangent = tangent;
                vertices[indices[i * 3 + 2]].Tangent = tangent;

                vertices[indices[i * 3]].Binormal = binormal;
                vertices[indices[i * 3 + 1]].Binormal = binormal;
                vertices[indices[i * 3 + 2]].Binormal = binormal;
                #endregion
            }

            for (int i = 0; i < vertices.Length; i++)
            {
                vertices[i].Normal.Normalize();
            }

            #endregion

            indexBuffer = new IndexBuffer(device, typeof(int), terrainSizeMinusOne * terrainSizeMinusOne * 6, BufferUsage.None);
            indexBuffer.SetData(indices);

            vertexBuffer = new VertexBuffer(device,
                    typeof(MultitexturedVertex), vertices.Length,
                    BufferUsage.None);
            vertexBuffer.SetData(vertices);

            #region Effect

            this.Effect = effect;
            this.ShadowMap = new RenderTarget2D(device, 1024, 1024, false, SurfaceFormat.Single, DepthFormat.Depth24Stencil8);

            #endregion
        }