Ejemplo n.º 1
0
        /// <summary>
        /// Adds tangent and bitangent information to vertices.
        /// </summary>
        /// <param name="model">ModelData.</param>
        private void AddModelTangents(ref ModelData model)
        {
            foreach (var subMesh in model.SubMeshes)
            {
                int index = subMesh.StartIndex;
                for (int tri = 0; tri < subMesh.PrimitiveCount; tri++)
                {
                    // Get indices
                    short i1 = model.Indices[index++];
                    short i2 = model.Indices[index++];
                    short i3 = model.Indices[index++];

                    // Get vertices
                    VertexPositionNormalTextureBump vert1 = model.Vertices[i1];
                    VertexPositionNormalTextureBump vert2 = model.Vertices[i2];
                    VertexPositionNormalTextureBump vert3 = model.Vertices[i3];

                    // Make tangent and bitangent
                    MakeTangentBitangent(ref vert1, ref vert2, ref vert3);

                    // Store updated vertices
                    model.Vertices[i1] = vert1;
                    model.Vertices[i2] = vert2;
                    model.Vertices[i3] = vert3;
                }
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Adds batch data to the batch builder.
        ///  Geometry data is batched by key.
        /// </summary>
        /// <param name="key">Key to batch against.</param>
        /// <param name="batchData">Data to add.</param>
        /// <param name="matrix">Geometry transform to apply before adding.</param>
        public void AddToBuilder(uint key, BatchData batchData, Matrix matrix)
        {
            // Do nothing if sealed
            if (isSealed)
            {
                return;
            }

            BatchData builder;

            if (builderDictionary.ContainsKey(key))
            {
                // Get current batch data
                builder = builderDictionary[key];
            }
            else
            {
                // Start a new batch
                builder.Vertices = new List <VertexPositionNormalTextureBump>();
                builder.Indices  = new List <int>();
                builderDictionary.Add(key, builder);
            }

            // Transform vertices
            for (int i = 0; i < batchData.Vertices.Count; i++)
            {
                VertexPositionNormalTextureBump vertex = batchData.Vertices[i];
                vertex.Position       = Vector3.Transform(vertex.Position, matrix);
                vertex.Normal         = Vector3.TransformNormal(vertex.Normal, matrix);
                batchData.Vertices[i] = vertex;
            }

            // Add new vertices to builder
            int currentVertex = builder.Vertices.Count;

            builder.Vertices.AddRange(batchData.Vertices);

            // Update indices to new vertex base
            for (int i = 0; i < batchData.Indices.Count; i++)
            {
                batchData.Indices[i] += currentVertex;
            }

            // Add indices to builder
            builder.Indices.AddRange(batchData.Indices);

            // Update dictionary
            builderDictionary[key] = builder;
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Calculates tangent and bitangent values.
        /// Source1: Lengyel, Eric. “Computing Tangent Space Basis Vectors for an Arbitrary Mesh”. Terathon Software 3D Graphics Library, 2001. http://www.terathon.com/code/tangent.html
        /// Source2: http://forums.create.msdn.com/forums/p/30443/172057.aspx
        /// </summary>
        private void MakeTangentBitangent(
            ref VertexPositionNormalTextureBump vert1,
            ref VertexPositionNormalTextureBump vert2,
            ref VertexPositionNormalTextureBump vert3)
        {
            Vector3 v1 = vert1.Position;
            Vector3 v2 = vert2.Position;
            Vector3 v3 = vert3.Position;

            Vector2 w1 = vert1.TextureCoordinate;
            Vector2 w2 = vert2.TextureCoordinate;
            Vector2 w3 = vert3.TextureCoordinate;

            // All points in a Daggerfall plane have the same vertex normal.
            // Each vertex normal is equal to the plane normal.
            Vector3 planeNormal = vert1.Normal;

            float x1 = v2.X - v1.X;
            float x2 = v3.X - v1.X;
            float y1 = v2.Y - v1.Y;
            float y2 = v3.Y - v1.Y;
            float z1 = v2.Z - v1.Z;
            float z2 = v3.Z - v1.Z;

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

            float   r    = 1.0f / (s1 * t2 - s2 * t1);
            Vector3 sdir = new Vector3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r);
            Vector3 tdir = new Vector3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r);

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

            tangent.Normalize();

            float   tangentdir = (Vector3.Dot(Vector3.Cross(planeNormal, sdir), tdir) >= 0.0f) ? 1.0f : -1.0f;
            Vector3 binormal   = Vector3.Cross(planeNormal, tangent) * tangentdir;

            vert1.Tangent  = tangent;
            vert1.Binormal = binormal;
            vert2.Tangent  = tangent;
            vert2.Binormal = binormal;
            vert3.Tangent  = tangent;
            vert3.Binormal = binormal;
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Adds model data to the batch builder.
        /// </summary>
        /// <param name="key">Key to batch against.</param>
        /// <param name="modelData">Model data to add.</param>
        /// <param name="matrix">Transform to apply before adding model data.</param>
        /// <param name="matrix">Geometry transform to apply before adding.</param>
        public void AddToBuilder(ref ModelManager.ModelData modelData, Matrix matrix)
        {
            // Do nothing if sealed
            if (isSealed)
            {
                return;
            }

            // Iterate submeshes
            BatchData batchData;

            foreach (var sm in modelData.SubMeshes)
            {
                // Start new batch data for this submesh
                batchData.Vertices = new List <VertexPositionNormalTextureBump>();
                batchData.Indices  = new List <int>();

                int counter = 0;
                int index   = sm.StartIndex;
                for (int tri = 0; tri < sm.PrimitiveCount; tri++)
                {
                    // Get indices
                    int i1 = modelData.Indices[index++];
                    int i2 = modelData.Indices[index++];
                    int i3 = modelData.Indices[index++];

                    // Get vertices
                    VertexPositionNormalTextureBump vert1 = modelData.Vertices[i1];
                    VertexPositionNormalTextureBump vert2 = modelData.Vertices[i2];
                    VertexPositionNormalTextureBump vert3 = modelData.Vertices[i3];

                    // Add vertices
                    batchData.Vertices.Add(vert1);
                    batchData.Vertices.Add(vert2);
                    batchData.Vertices.Add(vert3);

                    // Add indices
                    batchData.Indices.Add(counter++);
                    batchData.Indices.Add(counter++);
                    batchData.Indices.Add(counter++);
                }

                // Add to builder
                AddToBuilder((uint)sm.MaterialKey, batchData, matrix);
            }
        }
        /// <summary>
        /// Creates billboard template.
        /// </summary>
        private void CreateBillboard()
        {
            // Set dimensions of billboard
            const float w = 0.5f;
            const float h = 0.5f;

            // Create vertex array
            billboardVertices    = new VertexPositionNormalTextureBump[4];
            billboardVertices[0] = new VertexPositionNormalTextureBump(
                new Vector3(-w, h, 0),
                Vector3.Up,
                new Vector2(0, 0),
                Vector3.Zero,
                Vector3.Zero);
            billboardVertices[1] = new VertexPositionNormalTextureBump(
                new Vector3(w, h, 0),
                Vector3.Up,
                new Vector2(1, 0),
                Vector3.Zero,
                Vector3.Zero);
            billboardVertices[2] = new VertexPositionNormalTextureBump(
                new Vector3(-w, -h, 0),
                Vector3.Up,
                new Vector2(0, 1),
                Vector3.Zero,
                Vector3.Zero);
            billboardVertices[3] = new VertexPositionNormalTextureBump(
                new Vector3(w, -h, 0),
                Vector3.Up,
                new Vector2(1, 1),
                Vector3.Zero,
                Vector3.Zero);

            // Create index array
            billboardIndices = new int[6]
            {
                0, 1, 2,
                1, 3, 2,
            };
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Create vertices for a terrain tile.
        /// </summary>
        /// <param name="dimension">Number of vertices wide and high.</param>
        /// <param name="scale">Size of each vertex in world units.</param>
        /// <remarks>Vertex array.</remarks>
        private VertexPositionNormalTextureBump[] CreateVertices(int dimension, float scale)
        {
            // Create vertex array
            int max = dimension + 1;

            VertexPositionNormalTextureBump[] vertices =
                new VertexPositionNormalTextureBump[max * max];

            // Set vertices
            for (int x = 0; x < max; x++)
            {
                for (int y = 0; y < max; y++)
                {
                    int pos = x + y * max;
                    vertices[pos].Position          = new Vector3(x * scale, 0f, y * scale);
                    vertices[pos].Normal            = Vector3.Up;
                    vertices[pos].TextureCoordinate = new Vector2((float)x / (float)dimension, (float)y / (float)dimension);
                }
            }

            return(vertices);
        }
        /// <summary>
        /// Adds exterior ground tiles to the batch.
        /// </summary>
        /// <param name="blockData">Block data.</param>
        private void AddRMBGroundTiles(ref DFBlock blockData)
        {
            // Make ground slightly lower to minimise depth-fighting on ground aligned polygons
            const float groundHeight = 0f;

            // Corner positions
            Vector3 topLeftPos, topRightPos, bottomLeftPos, bottomRightPos;
            Vector2 topLeftUV, topRightUV, bottomLeftUV, bottomRightUV;

            // Create vertices. These will be updated for each tile based on position and UV orientation.
            VertexPositionNormalTextureBump[] vertices = new VertexPositionNormalTextureBump[4];

            // Create indices. These are the same for every tile.
            int[] indices = new int[] { 0, 1, 2, 1, 3, 2 };

            // Loop through tiles
            int   tileCount     = 16;
            float tileDimension = 256.0f * ModelManager.GlobalScale;

            for (int y = 0; y < tileCount; y++)
            {
                for (int x = 0; x < tileCount; x++)
                {
                    // Get source tile data
                    DFBlock.RmbGroundTiles tile = blockData.RmbBlock.FldHeader.GroundData.GroundTiles[x, y];

                    // Set random terrain marker back to grass
                    int textureRecord = (tile.TextureRecord > 55) ? 2 : tile.TextureRecord;

                    // Create material
                    BaseMaterialEffect material = core.ModelManager.CreateModelMaterial(
                        (int)DFLocation.ClimateTextureSet.Exterior_Terrain,
                        textureRecord);
                    material.SamplerState0 = SamplerState.AnisotropicClamp;

                    // Create vertices for this quad
                    topLeftPos     = new Vector3(x * tileDimension, groundHeight, y * tileDimension);
                    topRightPos    = new Vector3(topLeftPos.X + tileDimension, groundHeight, topLeftPos.Z);
                    bottomLeftPos  = new Vector3(topLeftPos.X, groundHeight, topLeftPos.Z + tileDimension);
                    bottomRightPos = new Vector3(topLeftPos.X + tileDimension, groundHeight, topLeftPos.Z + tileDimension);

                    // Set UVs
                    if (tile.IsRotated && !tile.IsFlipped)
                    {
                        // Rotate only
                        topLeftUV     = new Vector2(1, 0);
                        topRightUV    = new Vector2(1, 1);
                        bottomLeftUV  = new Vector2(0, 0);
                        bottomRightUV = new Vector2(0, 1);
                    }
                    else if (tile.IsFlipped && !tile.IsRotated)
                    {
                        // Flip only
                        topLeftUV     = new Vector2(1, 1);
                        topRightUV    = new Vector2(0, 1);
                        bottomLeftUV  = new Vector2(1, 0);
                        bottomRightUV = new Vector2(0, 0);
                    }
                    else if (tile.IsRotated && tile.IsRotated)
                    {
                        // Rotate and flip
                        topLeftUV     = new Vector2(0, 1);
                        topRightUV    = new Vector2(0, 0);
                        bottomLeftUV  = new Vector2(1, 1);
                        bottomRightUV = new Vector2(1, 0);
                    }
                    else
                    {
                        // No rotate or flip
                        topLeftUV     = new Vector2(0, 0);
                        topRightUV    = new Vector2(1, 0);
                        bottomLeftUV  = new Vector2(0, 1);
                        bottomRightUV = new Vector2(1, 1);
                    }

                    // Set vertices
                    vertices[0] = new VertexPositionNormalTextureBump(topLeftPos, Vector3.Up, topLeftUV, Vector3.Zero, Vector3.Zero);
                    vertices[1] = new VertexPositionNormalTextureBump(topRightPos, Vector3.Up, topRightUV, Vector3.Zero, Vector3.Zero);
                    vertices[2] = new VertexPositionNormalTextureBump(bottomLeftPos, Vector3.Up, bottomLeftUV, Vector3.Zero, Vector3.Zero);
                    vertices[3] = new VertexPositionNormalTextureBump(bottomRightPos, Vector3.Up, bottomRightUV, Vector3.Zero, Vector3.Zero);

                    // Add to builder
                    staticGeometry.AddToBuilder(material.ID, vertices, indices, Matrix.Identity);
                }
            }
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Creates a new InstanceModel used by InstanceFactory to create new instances
        /// </summary>
        /// <param name="model">The Xna Model to be used</param>
        public InstanceModel(Model model)
        {
            // Temporary buffers for building the data.
            List <VertexPositionNormalTextureBump> vertices = new List <VertexPositionNormalTextureBump>(256);
            List <short>          indices    = new List <short>(256);
            Dictionary <int, int> indexremap = new Dictionary <int, int>(256);

            // Temporary buffers for extracting model data.
            VertexPositionNormalTextureBump[] sourcevertices = new VertexPositionNormalTextureBump[1];
            short[] sourceindices = new short[1];

            // Get the model transforms for baking down vertices into object space (XNA Models are stored in mesh space).
            Matrix[] bonearray = new Matrix[model.Bones.Count];
            model.CopyAbsoluteBoneTransformsTo(bonearray);

            for (int m = 0; m < model.Meshes.Count; m++)
            {
                ModelMesh mesh = model.Meshes[m];

                // Test for correct vertex format.
                VerifyVertexFormat(mesh);

                // Get the mesh-to-object space transform.
                Matrix meshtoobject = bonearray[mesh.ParentBone.Index];

                indexremap.Clear();

                for (int p = 0; p < mesh.MeshParts.Count; p++)
                {
                    ModelMeshPart part = mesh.MeshParts[p];

                    // Get the number of verts and indices (only VertexPositionNormalTextureBump and short are supported - these are used by SunBurn).
                    int vertcount = part.VertexBuffer.VertexCount;
                    int indcount  = part.IndexBuffer.IndexCount;

                    // Readjust the buffer sizes as necessary.
                    if (sourcevertices.Length < vertcount)
                    {
                        sourcevertices = new VertexPositionNormalTextureBump[vertcount];
                    }

                    if (sourceindices.Length < indcount)
                    {
                        sourceindices = new short[indcount];
                    }

                    // Get the mesh data.
                    part.VertexBuffer.GetData(sourcevertices, 0, vertcount);
                    part.IndexBuffer.GetData(sourceindices, 0, indcount);

                    // Loop through all of the vertices.
                    for (int i = 0; i < (part.PrimitiveCount * 3); i++)
                    {
                        int index = sourceindices[i + part.StartIndex] + part.VertexOffset;

                        // Did we already store the data in the vertex buffer?
                        if (indexremap.ContainsKey(index))
                        {
                            indices.Add((short)indexremap[index]);
                            continue;
                        }

                        // Copy the vertex and convert to object space.
                        VertexPositionNormalTextureBump vert = sourcevertices[index];

                        vert.Position = Vector3.Transform(vert.Position, meshtoobject);
                        vert.Normal   = Vector3.TransformNormal(vert.Normal, meshtoobject);
                        vert.Tangent  = Vector3.TransformNormal(vert.Tangent, meshtoobject);
                        vert.Binormal = Vector3.TransformNormal(vert.Binormal, meshtoobject);

                        vert.Normal.Normalize();
                        vert.Tangent.Normalize();
                        vert.Binormal.Normalize();

                        // Remap the source index (from the model) to the destination index (in the buffers).
                        int destindex = vertices.Count;
                        indexremap.Add(index, destindex);

                        // Store the data.
                        indices.Add((short)destindex);
                        vertices.Add(vert);
                    }
                }
            }

            // Convert the buffers to the final arrays.
            Vertices = vertices.ToArray();
            Indices  = indices.ToArray();
        }
        /// <summary>
        /// Creates a new ModelInstanceSourceData instance.
        /// </summary>
        public ModelInstanceSourceData(Model model)
        {
            // Temporary buffers for building the data.
            List<VertexPositionNormalTextureBump> vertices = new List<VertexPositionNormalTextureBump>(256);
            List<short> indices = new List<short>(256);
            Dictionary<int, int> indexremap = new Dictionary<int, int>(256);

            // Temporary buffers for extracting model data.
            VertexPositionNormalTextureBump[] sourcevertices = new VertexPositionNormalTextureBump[1];
            short[] sourceindices = new short[1];

            // Get the model transforms for baking down vertices into object space (XNA Models are stored in mesh space).
            Matrix[] bonearray = new Matrix[model.Bones.Count];
            model.CopyAbsoluteBoneTransformsTo(bonearray);

            for (int m = 0; m < model.Meshes.Count; m++)
            {
                ModelMesh mesh = model.Meshes[m];

                // Test for correct vertex format.
                VerifyVertexFormat(mesh);

                // Get the number of verts and indices (only VertexPositionNormalTextureBump and short are supported - these are used by SunBurn).
                int vertcount = mesh.VertexBuffer.SizeInBytes / VertexPositionNormalTextureBump.SizeInBytes;
                int indcount = mesh.IndexBuffer.SizeInBytes / sizeof(short);

                // Readjust the buffer sizes as necessary.
                if (sourcevertices.Length < vertcount)
                    sourcevertices = new VertexPositionNormalTextureBump[vertcount];
                if (sourceindices.Length < indcount)
                    sourceindices = new short[indcount];

                // Get the mesh data.
                mesh.VertexBuffer.GetData<VertexPositionNormalTextureBump>(sourcevertices, 0, vertcount);
                mesh.IndexBuffer.GetData<short>(sourceindices, 0, indcount);

                // Get the mesh-to-object space transform.
                Matrix meshtoobject = bonearray[mesh.ParentBone.Index];

                indexremap.Clear();

                for (int p = 0; p < mesh.MeshParts.Count; p++)
                {
                    ModelMeshPart part = mesh.MeshParts[p];

                    if (part.StreamOffset != 0)
                        throw new Exception("Stream offset not supported.");

                    // Loop through all of the vertices.
                    for (int i = 0; i < (part.PrimitiveCount * 3); i++)
                    {
                        int index = sourceindices[i + part.StartIndex] + part.BaseVertex;

                        // Did we already store the data in the vertex buffer?
                        if (indexremap.ContainsKey(index))
                        {
                            indices.Add((short)indexremap[index]);
                            continue;
                        }

                        // Copy the vertex and convert to object space.
                        VertexPositionNormalTextureBump vert = sourcevertices[index];

                        vert.Position = Vector3.Transform(vert.Position, meshtoobject);
                        vert.Normal = Vector3.TransformNormal(vert.Normal, meshtoobject);
                        vert.Tangent = Vector3.TransformNormal(vert.Tangent, meshtoobject);
                        vert.Binormal = Vector3.TransformNormal(vert.Binormal, meshtoobject);

                        vert.Normal.Normalize();
                        vert.Tangent.Normalize();
                        vert.Binormal.Normalize();

                        // Remap the source index (from the model) to the destination index (in the buffers).
                        int destindex = vertices.Count;
                        indexremap.Add(index, destindex);

                        // Store the data.
                        indices.Add((short)destindex);
                        vertices.Add(vert);
                    }
                }
            }

            // Convert the buffers to the final arrays.
            _Vertices = vertices.ToArray();
            _Indices = indices.ToArray();
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Creates static vertex and index buffers from builder.
        ///  You can keep adding to the builder and calling this method to apply changes.
        /// </summary>
        public void ApplyBuilder()
        {
            // Do nothing if sealed
            if (isSealed)
            {
                return;
            }

            // Dispose current vertex buffer
            if (vertexBuffer != null)
            {
                vertexBuffer.Dispose();
                vertexBuffer = null;
            }

            // Dispose current index buffer
            if (indexBuffer != null)
            {
                indexBuffer.Dispose();
                indexBuffer = null;
            }

            // Dispose current batch dictionary
            if (batchDictionary != null)
            {
                batchDictionary.Clear();
                batchDictionary = null;
            }

            // Create new batch dictionary
            batchDictionary = new Dictionary <uint, StaticBatch>();

            // Count total vertices and indices
            int totalVertices = 0;
            int totalIndices  = 0;

            foreach (var item in builderDictionary)
            {
                totalVertices += item.Value.Vertices.Count;
                totalIndices  += item.Value.Indices.Count;
            }

            // Create static arrays
            VertexPositionNormalTextureBump[] allVertices = new VertexPositionNormalTextureBump[totalVertices];
            int[] allIndices = new int[totalIndices];

            // Populate static arrays
            int currentVertex = 0;
            int currentIndex  = 0;

            foreach (var item in builderDictionary)
            {
                // Save current highest vertex and index
                int highestVertex = currentVertex;
                int highestIndex  = currentIndex;

                // Copy vertex data
                foreach (var vertex in item.Value.Vertices)
                {
                    allVertices[currentVertex++] = vertex;
                }

                // Copy index data
                foreach (var index in item.Value.Indices)
                {
                    allIndices[currentIndex++] = highestVertex + index;
                }

                // Add batch details
                StaticBatch batch = new StaticBatch
                {
                    StartIndex     = highestIndex,
                    PrimitiveCount = item.Value.Indices.Count / 3,
                };
                batchDictionary.Add(item.Key, batch);
            }

            // Create new static buffers
            vertexBuffer = new VertexBuffer(graphicsDevice, VertexPositionNormalTextureBump.VertexDeclaration, allVertices.Length, BufferUsage.WriteOnly);
            indexBuffer  = new IndexBuffer(graphicsDevice, IndexElementSize.ThirtyTwoBits, allIndices.Length, BufferUsage.WriteOnly);

            // Set buffer data
            vertexBuffer.SetData <VertexPositionNormalTextureBump>(allVertices);
            indexBuffer.SetData <int>(allIndices);
        }