Matrix worldTransform = Matrix.Identity; for (int i = 0; i < 500; ++i) { worldTransform.M41 = i * 2; customModel.WorldTransform = worldTransform; //modelDrawer.DrawInstancedModel(customModel); // OR //modelDrawer.DrawModel(customModel); }
My standard model drawing method is as follows:
public void DrawModel(CustomModel customModel) { Effect effect = game.Effects[customModel.Effect]; GraphicsDevice graphicsDevice = game.GraphicsDevice; Matrix[] transforms = customModel.ModelData.Transforms; effect.Begin(); effect.CurrentTechnique.Passes[0].Begin(); for (int i = 0; i < customModel.Model.Meshes.Count; ++i) { ModelMesh mesh = customModel.Model.Meshes; for (int ii = 0; ii < mesh.MeshParts.Count; ++ii) { ModelMeshPart meshPart = mesh.MeshParts[ii]; effect.Parameters["World"].SetValue(transforms[mesh.ParentBone.Index] * customModel.WorldTransform); effect.CommitChanges(); graphicsDevice.VertexDeclaration = meshPart.VertexDeclaration; graphicsDevice.Vertices[0].SetSource(mesh.VertexBuffer, meshPart.StreamOffset, meshPart.VertexStride); graphicsDevice.Indices = mesh.IndexBuffer; graphicsDevice.DrawIndexedPrimitives( PrimitiveType.TriangleList, meshPart.BaseVertex, 0, meshPart.NumVertices, meshPart.StartIndex, meshPart.PrimitiveCount ); } } effect.CurrentTechnique.Passes[0].End(); effect.End(); }
My batch drawing method is as follows:
public void DrawInstancedModel(CustomModel customModel) { if (!isInBeginEndPair) { throw new InvalidOperationException("Begin must be called successfully before a Draw can be called."); } int numModelIndices = customModel.ModelData.Indices.Length; int numModelVertices = customModel.ModelData.Vertices.Length; if (Reserve(numModelVertices, numModelIndices)) { int count = 0; int offset = 0; Matrix[] transforms = customModel.ModelData.Transforms; for (int i = 0; i < customModel.Model.Meshes.Count; ++i) { ModelMesh mesh = customModel.Model.Meshes; for (int ii = 0; ii < mesh.MeshParts.Count; ++ii) { ModelMeshPart meshPart = mesh.MeshParts[ii]; // Create and store the world transforms for each mesh part // The mesh part vertices' 'Index' property will be assigned the new transformIndex value offset += count; count = meshPart.NumVertices; for (int v = offset; v < offset + count; ++v) { customModel.ModelData.Vertices[v].Index = transformIndex; } // [World Transform] worldTransforms[transformIndex++] = transforms[mesh.ParentBone.Index] * customModel.WorldTransform; } } for (int i = 0; i < numModelIndices; ++i) { indices[numIndices++] = (ushort)(numVertices + customModel.ModelData.Indices); } customModel.ModelData.Vertices.CopyTo(vertices, numVertices); numVertices += numModelVertices; } } private bool Reserve(int numV, int numI) { if (numV > MAXVERTICES || numI > MAXINDICES) { // Whatever it is, we can't draw it return false; } if (numVertices + numV >= MAXVERTICES || numIndices + numI >= MAXINDICES || (transformIndex + 1) >= MAXMODELSPERBATCH) { // We can draw it, but we need to make room first FlushDrawing(); } return true; } private void FlushDrawing() { if (numIndices > 0) { Effect effect = game.Effects["ModelBatch"]; // Set parameters for current camera game.SetSharedParameters(camera); vertexBuffer.SetData(vertices, 0, numVertices, SetDataOptions.Discard); indexBuffer.SetData(indices, 0, numIndices, SetDataOptions.Discard); game.GraphicsDevice.Vertices[0].SetSource(vertexBuffer, 0, VertexPositionNormalTextureIndex.SizeInBytes); game.GraphicsDevice.Indices = indexBuffer; game.GraphicsDevice.VertexDeclaration = game.VertexDeclarations["VertexPositionNormalTextureIndex"]; // Set effect parameters parameter_WorldTransforms.SetValue(worldTransforms); // Make sure parameter effects take place before drawing effect.CommitChanges(); effect.Begin(); effect.CurrentTechnique.Passes[0].Begin(); game.GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, numVertices, 0, numIndices / 3); effect.CurrentTechnique.Passes[0].End(); effect.End(); } numIndices = 0; numVertices = 0; transformIndex = 0; }
Why would the one draw call per model be 8 times faster than the batch drawing method. How has my approach failed in this case?