public static InstancedModelData CreateInstancedModelData(Model model, int[] meshDrawOrders) { DynamicArray <InstancedVertex> dynamicArray = new DynamicArray <InstancedVertex>(); DynamicArray <ushort> dynamicArray2 = new DynamicArray <ushort>(); for (int i = 0; i < meshDrawOrders.Length; i++) { ModelMesh modelMesh = model.Meshes[meshDrawOrders[i]]; foreach (ModelMeshPart meshPart in modelMesh.MeshParts) { _ = dynamicArray.Count; VertexBuffer vertexBuffer = meshPart.VertexBuffer; IndexBuffer indexBuffer = meshPart.IndexBuffer; ReadOnlyList <VertexElement> vertexElements = vertexBuffer.VertexDeclaration.VertexElements; ushort[] indexData = BlockMesh.GetIndexData <ushort>(indexBuffer); Dictionary <ushort, ushort> dictionary = new Dictionary <ushort, ushort>(); if (vertexElements.Count != 3 || vertexElements[0].Offset != 0 || !(vertexElements[0].Semantic == VertexElementSemantic.Position.GetSemanticString()) || vertexElements[1].Offset != 12 || !(vertexElements[1].Semantic == VertexElementSemantic.Normal.GetSemanticString()) || vertexElements[2].Offset != 24 || !(vertexElements[2].Semantic == VertexElementSemantic.TextureCoordinate.GetSemanticString())) { throw new InvalidOperationException("Unsupported vertex format."); } SourceModelVertex[] vertexData = BlockMesh.GetVertexData <SourceModelVertex>(vertexBuffer); for (int j = meshPart.StartIndex; j < meshPart.StartIndex + meshPart.IndicesCount; j++) { ushort num = indexData[j]; if (!dictionary.ContainsKey(num)) { dictionary.Add(num, (ushort)dynamicArray.Count); InstancedVertex item = default(InstancedVertex); SourceModelVertex sourceModelVertex = vertexData[num]; item.X = sourceModelVertex.X; item.Y = sourceModelVertex.Y; item.Z = sourceModelVertex.Z; item.Nx = sourceModelVertex.Nx; item.Ny = sourceModelVertex.Ny; item.Nz = sourceModelVertex.Nz; item.Tx = sourceModelVertex.Tx; item.Ty = sourceModelVertex.Ty; item.Instance = modelMesh.ParentBone.Index; dynamicArray.Add(item); } } for (int k = 0; k < meshPart.IndicesCount / 3; k++) { dynamicArray2.Add(dictionary[indexData[meshPart.StartIndex + 3 * k]]); dynamicArray2.Add(dictionary[indexData[meshPart.StartIndex + 3 * k + 1]]); dynamicArray2.Add(dictionary[indexData[meshPart.StartIndex + 3 * k + 2]]); } } } InstancedModelData instancedModelData = new InstancedModelData(); instancedModelData.VertexBuffer = new VertexBuffer(InstancedModelData.VertexDeclaration, dynamicArray.Count); instancedModelData.IndexBuffer = new IndexBuffer(IndexFormat.SixteenBits, dynamicArray2.Count); instancedModelData.VertexBuffer.SetData(dynamicArray.Array, 0, dynamicArray.Count); instancedModelData.IndexBuffer.SetData(dynamicArray2.Array, 0, dynamicArray2.Count); return(instancedModelData); }
/// <summary> /// Adds a display object to the batch. /// </summary> /// <param name="displayObject">Display object to add.</param> /// <param name="drawer">Drawer of the batch.</param> public bool Add(ModelDisplayObject displayObject, InstancedModelDrawer drawer) { //In theory, don't need to test for dupliate entries since batch.Add //should only be called through a InstancedModelDrawer's add (which checks beforehand). if (displayObjects.Count == MaximumObjectsPerBatch || ((indices.Length / 3 + displayObject.GetTriangleCountEstimate()) > MaximumPrimitiveCountPerBatch && displayObjects.Count > 0)) { return(false); } displayObjects.Add(displayObject); int instanceIndex = displayObjects.Count - 1; var textureIndex = displayObject.TextureIndex; displayObject.GetVertexData(vertexList, indexList, this, (ushort)vertices.Length, indices.Length, instanceIndex); //Add the data to the batch. var newVertices = new VertexPositionNormalTexture[vertices.Length + vertexList.Count]; vertices.CopyTo(newVertices, 0); vertexList.CopyTo(newVertices, vertices.Length); vertices = newVertices; var newIndices = new ushort[indices.Length + indexList.Count]; indices.CopyTo(newIndices, 0); indexList.CopyTo(newIndices, indices.Length); indices = newIndices; var newInstancingVertices = new InstancedVertex[instancedVertices.Length + vertexList.Count]; instancedVertices.CopyTo(newInstancingVertices, 0); for (int i = instancedVertices.Length; i < newInstancingVertices.Length; i++) { newInstancingVertices[i] = new InstancedVertex { InstanceIndex = instanceIndex, TextureIndex = textureIndex } } ; instancedVertices = newInstancingVertices; vertexBuffer = new VertexBuffer(graphicsDevice, VertexPositionNormalTexture.VertexDeclaration, vertices.Length, BufferUsage.WriteOnly); vertexBuffer.SetData(vertices); instancingBuffer = new VertexBuffer(graphicsDevice, InstancedVertex.VertexDeclaration, instancedVertices.Length, BufferUsage.WriteOnly); instancingBuffer.SetData(instancedVertices); bindings = new VertexBufferBinding[] { vertexBuffer, instancingBuffer }; indexBuffer = new IndexBuffer(graphicsDevice, IndexElementSize.SixteenBits, indices.Length, BufferUsage.WriteOnly); indexBuffer.SetData(indices); vertexList.Clear(); indexList.Clear(); return(true); }
/// <summary> /// Adds a display object to the batch. /// </summary> /// <param name="displayObject">Display object to add.</param> /// <param name="drawer">Drawer of the batch.</param> public unsafe bool Add(ModelDisplayObject displayObject, InstancedModelDrawer drawer) { //In theory, don't need to test for duplicate entries since batch.Add //should only be called through a InstancedModelDrawer's add (which checks beforehand). if (displayObjects.Count == MaximumObjectsPerBatch || ((indexCount / 3 + displayObject.GetTriangleCountEstimate()) > MaximumPrimitiveCountPerBatch && displayObjects.Count > 0)) { return(false); } displayObjects.Add(displayObject); int instanceIndex = displayObjects.Count - 1; var textureIndex = displayObject.TextureIndex; //OUegheogh, this could just directly write into the batch's vertex/index cache rather than going through a list and recopy. displayObject.GetVertexData(vertexList, indexList, this, (ushort)vertexCount, indexCount, instanceIndex); vertexList.CopyTo(vertices, vertexCount); indexList.CopyTo(indices, indexCount); var newIndexCount = indexCount + indexList.Count; var newVertexCount = vertexCount + vertexList.Count; for (int i = vertexCount; i < newVertexCount; i++) { instancedVertices[i] = new InstancedVertex { InstanceIndex = instanceIndex, TextureIndex = textureIndex } } ; vertexBuffer.SetData(sizeof(VertexPositionNormalTexture) * vertexCount, vertices, vertexCount, vertexList.Count, sizeof(VertexPositionNormalTexture)); instancedBuffer.SetData(sizeof(InstancedVertex) * vertexCount, instancedVertices, vertexCount, vertexList.Count, sizeof(InstancedVertex)); indexBuffer.SetData(sizeof(ushort) * indexCount, indices, indexCount, indexList.Count); vertexCount = newVertexCount; indexCount = newIndexCount; vertexList.Clear(); indexList.Clear(); return(true); }
/// <summary> /// Adds a display object to the batch. /// </summary> /// <param name="displayObject">Display object to add.</param> /// <param name="drawer">Drawer of the batch.</param> public bool Add(ModelDisplayObject displayObject, InstancedModelDrawer drawer) { //In theory, don't need to test for dupliate entries since batch.Add //should only be called through a InstancedModelDrawer's add (which checks beforehand). if (displayObjects.Count == MaximumObjectsPerBatch || ((indices.Length / 3 + displayObject.GetTriangleCountEstimate()) > MaximumPrimitiveCountPerBatch && displayObjects.Count > 0)) return false; displayObjects.Add(displayObject); int instanceIndex = displayObjects.Count - 1; var textureIndex = displayObject.TextureIndex; displayObject.GetVertexData(vertexList, indexList, this, (ushort)vertices.Length, indices.Length, instanceIndex); //Add the data to the batch. var newVertices = new VertexPositionNormalTexture[vertices.Length + vertexList.Count]; vertices.CopyTo(newVertices, 0); vertexList.CopyTo(newVertices, vertices.Length); vertices = newVertices; var newIndices = new ushort[indices.Length + indexList.Count]; indices.CopyTo(newIndices, 0); indexList.CopyTo(newIndices, indices.Length); indices = newIndices; var newInstancingVertices = new InstancedVertex[instancedVertices.Length + vertexList.Count]; instancedVertices.CopyTo(newInstancingVertices, 0); for (int i = instancedVertices.Length; i < newInstancingVertices.Length; i++) newInstancingVertices[i] = new InstancedVertex { InstanceIndex = instanceIndex, TextureIndex = textureIndex }; instancedVertices = newInstancingVertices; vertexBuffer = new VertexBuffer(graphicsDevice, VertexPositionNormalTexture.VertexDeclaration, vertices.Length, BufferUsage.WriteOnly); vertexBuffer.SetData(vertices); instancingBuffer = new VertexBuffer(graphicsDevice, InstancedVertex.VertexDeclaration, instancedVertices.Length, BufferUsage.WriteOnly); instancingBuffer.SetData(instancedVertices); bindings = new VertexBufferBinding[] { vertexBuffer, instancingBuffer }; indexBuffer = new IndexBuffer(graphicsDevice, IndexElementSize.SixteenBits, indices.Length, BufferUsage.WriteOnly); indexBuffer.SetData(indices); vertexList.Clear(); indexList.Clear(); return true; }
/// <summary> /// Removes a display object from the batch. /// </summary> /// <param name="displayObject">Display object to remove.</param> /// <param name="drawer">Instanced model drawer doing the removal.</param> public void Remove(ModelDisplayObject displayObject, InstancedModelDrawer drawer) { //Modify vertex buffer var newVertices = new VertexPositionNormalTexture[vertices.Length - displayObject.BatchInformation.VertexCount]; //Copy the first part back (before the display object) Array.Copy(vertices, 0, newVertices, 0, displayObject.BatchInformation.BaseVertexBufferIndex); //Copy the second part back (after the display object) Array.Copy(vertices, displayObject.BatchInformation.BaseVertexBufferIndex + displayObject.BatchInformation.VertexCount, newVertices, displayObject.BatchInformation.BaseVertexBufferIndex, vertices.Length - (displayObject.BatchInformation.BaseVertexBufferIndex + displayObject.BatchInformation.VertexCount)); vertices = newVertices; //Modify index buffer var newIndices = new ushort[indices.Length - displayObject.BatchInformation.IndexCount]; //Copy the first part back (before the display object) Array.Copy(indices, 0, newIndices, 0, displayObject.BatchInformation.BaseIndexBufferIndex); //Copy the second part back (after the display object) Array.Copy(indices, displayObject.BatchInformation.BaseIndexBufferIndex + displayObject.BatchInformation.IndexCount, newIndices, displayObject.BatchInformation.BaseIndexBufferIndex, indices.Length - (displayObject.BatchInformation.BaseIndexBufferIndex + displayObject.BatchInformation.IndexCount)); indices = newIndices; //The index buffer's data is now wrong though. We deleted a bunch of vertices. //So go through the index buffer starting at the point of deletion and decrease the values appropriately. for (int i = displayObject.BatchInformation.BaseIndexBufferIndex; i < indices.Length; i++) indices[i] -= (ushort)displayObject.BatchInformation.VertexCount; //Modify instancing indices var newInstancedVertices = new InstancedVertex[instancedVertices.Length - displayObject.BatchInformation.VertexCount]; //Copy the first part back (before the display object) Array.Copy(instancedVertices, 0, newInstancedVertices, 0, displayObject.BatchInformation.BaseVertexBufferIndex); //Copy the second part back (after the display object) Array.Copy(instancedVertices, displayObject.BatchInformation.BaseVertexBufferIndex + displayObject.BatchInformation.VertexCount, newInstancedVertices, displayObject.BatchInformation.BaseVertexBufferIndex, instancedVertices.Length - (displayObject.BatchInformation.BaseVertexBufferIndex + displayObject.BatchInformation.VertexCount)); instancedVertices = newInstancedVertices; //Like with the index buffer, go through the buffer starting at the point of deletion and decrease the values appropriately. for (int i = displayObject.BatchInformation.BaseVertexBufferIndex; i < instancedVertices.Length; i++) instancedVertices[i].InstanceIndex--; displayObjects.Remove(displayObject); //Move the subsequent display objects list indices and base vertices/indices. for (int i = displayObject.BatchInformation.BatchListIndex; i < DisplayObjects.Count; i++) { DisplayObjects[i].BatchInformation.BatchListIndex--; DisplayObjects[i].BatchInformation.BaseVertexBufferIndex -= displayObject.BatchInformation.VertexCount; DisplayObjects[i].BatchInformation.BaseIndexBufferIndex -= displayObject.BatchInformation.IndexCount; } // Tell ModelDisplayObject that it got removed (batch, indices). displayObject.ClearBatchReferences(); //If there weren't any vertices, this batch is about to die. if (displayObjects.Count > 0) { vertexBuffer = new VertexBuffer(graphicsDevice, VertexPositionNormalTexture.VertexDeclaration, vertices.Length, BufferUsage.WriteOnly); vertexBuffer.SetData(vertices); instancingBuffer = new VertexBuffer(graphicsDevice, InstancedVertex.VertexDeclaration, instancedVertices.Length, BufferUsage.WriteOnly); instancingBuffer.SetData(instancedVertices); indexBuffer = new IndexBuffer(graphicsDevice, IndexElementSize.SixteenBits, indices.Length, BufferUsage.WriteOnly); indexBuffer.SetData(indices); bindings = new VertexBufferBinding[] { vertexBuffer, instancingBuffer }; } }
/// <summary> /// Removes a display object from the batch. /// </summary> /// <param name="displayObject">Display object to remove.</param> /// <param name="drawer">Instanced model drawer doing the removal.</param> public void Remove(ModelDisplayObject displayObject, InstancedModelDrawer drawer) { //Modify vertex buffer var newVertices = new VertexPositionNormalTexture[vertices.Length - displayObject.BatchInformation.VertexCount]; //Copy the first part back (before the display object) Array.Copy(vertices, 0, newVertices, 0, displayObject.BatchInformation.BaseVertexBufferIndex); //Copy the second part back (after the display object) Array.Copy(vertices, displayObject.BatchInformation.BaseVertexBufferIndex + displayObject.BatchInformation.VertexCount, newVertices, displayObject.BatchInformation.BaseVertexBufferIndex, vertices.Length - (displayObject.BatchInformation.BaseVertexBufferIndex + displayObject.BatchInformation.VertexCount)); vertices = newVertices; //Modify index buffer var newIndices = new ushort[indices.Length - displayObject.BatchInformation.IndexCount]; //Copy the first part back (before the display object) Array.Copy(indices, 0, newIndices, 0, displayObject.BatchInformation.BaseIndexBufferIndex); //Copy the second part back (after the display object) Array.Copy(indices, displayObject.BatchInformation.BaseIndexBufferIndex + displayObject.BatchInformation.IndexCount, newIndices, displayObject.BatchInformation.BaseIndexBufferIndex, indices.Length - (displayObject.BatchInformation.BaseIndexBufferIndex + displayObject.BatchInformation.IndexCount)); indices = newIndices; //The index buffer's data is now wrong though. We deleted a bunch of vertices. //So go through the index buffer starting at the point of deletion and decrease the values appropriately. for (int i = displayObject.BatchInformation.BaseIndexBufferIndex; i < indices.Length; i++) { indices[i] -= (ushort)displayObject.BatchInformation.VertexCount; } //Modify instancing indices var newInstancedVertices = new InstancedVertex[instancedVertices.Length - displayObject.BatchInformation.VertexCount]; //Copy the first part back (before the display object) Array.Copy(instancedVertices, 0, newInstancedVertices, 0, displayObject.BatchInformation.BaseVertexBufferIndex); //Copy the second part back (after the display object) Array.Copy(instancedVertices, displayObject.BatchInformation.BaseVertexBufferIndex + displayObject.BatchInformation.VertexCount, newInstancedVertices, displayObject.BatchInformation.BaseVertexBufferIndex, instancedVertices.Length - (displayObject.BatchInformation.BaseVertexBufferIndex + displayObject.BatchInformation.VertexCount)); instancedVertices = newInstancedVertices; //Like with the index buffer, go through the buffer starting at the point of deletion and decrease the values appropriately. for (int i = displayObject.BatchInformation.BaseVertexBufferIndex; i < instancedVertices.Length; i++) { instancedVertices[i].InstanceIndex--; } displayObjects.Remove(displayObject); //Move the subsequent display objects list indices and base vertices/indices. for (int i = displayObject.BatchInformation.BatchListIndex; i < DisplayObjects.Count; i++) { DisplayObjects[i].BatchInformation.BatchListIndex--; DisplayObjects[i].BatchInformation.BaseVertexBufferIndex -= displayObject.BatchInformation.VertexCount; DisplayObjects[i].BatchInformation.BaseIndexBufferIndex -= displayObject.BatchInformation.IndexCount; } // Tell ModelDisplayObject that it got removed (batch, indices). displayObject.ClearBatchReferences(); //If there weren't any vertices, this batch is about to die. if (displayObjects.Count > 0) { vertexBuffer = new VertexBuffer(graphicsDevice, VertexPositionNormalTexture.VertexDeclaration, vertices.Length, BufferUsage.WriteOnly); vertexBuffer.SetData(vertices); instancingBuffer = new VertexBuffer(graphicsDevice, InstancedVertex.VertexDeclaration, instancedVertices.Length, BufferUsage.WriteOnly); instancingBuffer.SetData(instancedVertices); indexBuffer = new IndexBuffer(graphicsDevice, IndexElementSize.SixteenBits, indices.Length, BufferUsage.WriteOnly); indexBuffer.SetData(indices); bindings = new VertexBufferBinding[] { vertexBuffer, instancingBuffer }; } }