public override MeshDraw CreateDebugPrimitive(GraphicsDevice device) { if (cachedDebugPrimitive != null) return cachedDebugPrimitive; var verts = new VertexPositionNormalTexture[pointsList.Count]; for (var i = 0; i < pointsList.Count; i++) { verts[i].Position = pointsList[i]; verts[i].TextureCoordinate = Vector2.Zero; verts[i].Normal = Vector3.Zero; } var intIndices = indicesList.Select(x => (int)x).ToArray(); ////calculate basic normals ////todo verify, winding order might be wrong? for (var i = 0; i < indicesList.Count; i += 3) { var i1 = intIndices[i]; var i2 = intIndices[i + 1]; var i3 = intIndices[i + 2]; var a = verts[i1]; var b = verts[i2]; var c = verts[i3]; var n = Vector3.Cross((b.Position - a.Position), (c.Position - a.Position)); n.Normalize(); verts[i1].Normal = verts[i2].Normal = verts[i3].Normal = n; } var meshData = new GeometricMeshData<VertexPositionNormalTexture>(verts, intIndices, false); cachedDebugPrimitive = new GeometricPrimitive(device, meshData).ToMeshDraw(); return cachedDebugPrimitive; }
/// <summary> /// Initializes a new instance of the <see cref="Mesh" /> class. /// </summary> /// <param name="meshDraw">The mesh draw.</param> /// <param name="parameters">The parameters.</param> /// <exception cref="System.ArgumentNullException">parameters</exception> public Mesh(MeshDraw meshDraw, ParameterCollection parameters) { if (meshDraw == null) throw new ArgumentNullException("meshDraw"); if (parameters == null) throw new ArgumentNullException("parameters"); Draw = meshDraw; Parameters = parameters; }
/// <summary> /// Initializes a new instance of the <see cref="Mesh" /> class. /// </summary> /// <param name="meshDraw">The mesh draw.</param> /// <param name="parameters">The parameters.</param> /// <exception cref="System.ArgumentNullException">parameters</exception> public Mesh(MeshDraw meshDraw, ParameterCollection parameters) { if (meshDraw == null) { throw new ArgumentNullException("meshDraw"); } if (parameters == null) { throw new ArgumentNullException("parameters"); } Draw = meshDraw; Parameters = parameters; }
protected override async Task LoadContent() { await base.LoadContent(); var vertices = new Vertex[4]; vertices[0] = new Vertex { Position = new Vector3(-1, -1, 0.5f), TexCoords = new Vector2(0, 0) }; vertices[1] = new Vertex { Position = new Vector3(-1, 1, 0.5f), TexCoords = new Vector2(3, 0) }; vertices[2] = new Vertex { Position = new Vector3(1, 1, 0.5f), TexCoords = new Vector2(3, 3) }; vertices[3] = new Vertex { Position = new Vector3(1, -1, 0.5f), TexCoords = new Vector2(0, 3) }; var indices = new short[] { 0, 1, 2, 0, 2, 3 }; var vertexBuffer = Buffer.Vertex.New(GraphicsDevice, vertices, GraphicsResourceUsage.Default); var indexBuffer = Buffer.Index.New(GraphicsDevice, indices, GraphicsResourceUsage.Default); var meshDraw = new MeshDraw { DrawCount = 4, PrimitiveType = PrimitiveType.TriangleList, VertexBuffers = new[] { new VertexBufferBinding(vertexBuffer, new VertexDeclaration(VertexElement.Position<Vector3>(), VertexElement.TextureCoordinate<Vector2>()), 4) }, IndexBuffer = new IndexBufferBinding(indexBuffer, false, indices.Length), }; var mesh = new Mesh { Draw = meshDraw, }; simpleEffect = new Effect(GraphicsDevice, SpriteEffect.Bytecode); parameterCollection = new ParameterCollection(); parameterCollectionGroup = new EffectParameterCollectionGroup(GraphicsDevice, simpleEffect, new[] { parameterCollection }); parameterCollection.Set(TexturingKeys.Texture0, UVTexture); vao = VertexArrayObject.New(GraphicsDevice, mesh.Draw.IndexBuffer, mesh.Draw.VertexBuffers); myDraws = new DrawOptions[3]; myDraws[0] = new DrawOptions { Sampler = GraphicsDevice.SamplerStates.LinearClamp, Transform = Matrix.Multiply(Matrix.Scaling(0.4f), Matrix.Translation(-0.5f, 0.5f, 0f)) }; myDraws[1] = new DrawOptions { Sampler = GraphicsDevice.SamplerStates.LinearWrap, Transform = Matrix.Multiply(Matrix.Scaling(0.4f), Matrix.Translation(0.5f, 0.5f, 0f)) }; myDraws[2] = new DrawOptions { Sampler = SamplerState.New(GraphicsDevice, new SamplerStateDescription(TextureFilter.Linear, TextureAddressMode.Mirror)), Transform = Matrix.Multiply(Matrix.Scaling(0.4f), Matrix.Translation(0.5f, -0.5f, 0f)) }; //var borderDescription = new SamplerStateDescription(TextureFilter.Linear, TextureAddressMode.Border) { BorderColor = Color.Purple }; //var border = SamplerState.New(GraphicsDevice, borderDescription); //myDraws[3] = new DrawOptions { Sampler = border, Transform = Matrix.Multiply(Matrix.Scale(0.3f), Matrix.Translation(-0.5f, -0.5f, 0f)) }; }
public override MeshDraw CreateDebugPrimitive(GraphicsDevice device) { return cachedDebugPrimitive ?? (cachedDebugPrimitive = GeometricPrimitive.Cube.New(device).ToMeshDraw()); }
/// <summary> /// Transform a vertex buffer positions, normals, tangents and bitangents using the given matrix. /// </summary> /// <param name="meshDrawDatas">The mesh draw datas.</param> /// <param name="can32BitIndex">A flag stating if 32 bit index buffers.</param> public unsafe static MeshDraw MergeDrawData(IList<MeshDraw> meshDrawDatas, bool can32BitIndex) { if (meshDrawDatas.Count == 0) throw new ArgumentException("Need at least 1 MeshDrawData.", "meshDrawDatas"); if (meshDrawDatas.Count == 1) return meshDrawDatas[0]; // Check that vertex buffer declarations are matching var firstMeshDrawData = meshDrawDatas[0]; if (!firstMeshDrawData.IsSimple()) throw new InvalidOperationException("Can only merge simple MeshDrawData."); var firstVertexBuffer = firstMeshDrawData.VertexBuffers[0]; var hasIndexBuffer = IsIndexed(meshDrawDatas); int totalVertexCount = 0; int totalIndexCount = 0; //TODO: extend to non-simple vertex declarations, fill with default values it missing declarations etc. ? for (int i = 0; i < meshDrawDatas.Count; i++) { var meshDrawData = meshDrawDatas[i]; // This should not happen anymore if (i != 0) { if (!meshDrawData.IsSimple()) throw new InvalidOperationException("Can only merge simple MeshDrawData."); if (meshDrawData.VertexBuffers.Length != firstMeshDrawData.VertexBuffers.Length) throw new InvalidOperationException("Non-matching vertex buffer declarations."); if (!meshDrawData.VertexBuffers[0].Declaration.Equals(firstMeshDrawData.VertexBuffers[0].Declaration)) throw new InvalidOperationException("Non-matching vertex buffer declarations."); } if (meshDrawData.PrimitiveType != PrimitiveType.TriangleList) throw new InvalidOperationException("Can only merge TriangleList."); // Update vertex/index counts totalVertexCount += meshDrawData.VertexBuffers[0].Count; if (hasIndexBuffer) { if (meshDrawData.IndexBuffer != null) totalIndexCount += meshDrawData.IndexBuffer.Count; else totalIndexCount += meshDrawData.VertexBuffers[0].Count; } } // Allocate vertex buffer var result = new MeshDraw { PrimitiveType = PrimitiveType.TriangleList }; var destBufferData = new byte[firstVertexBuffer.Declaration.VertexStride * totalVertexCount]; result.VertexBuffers = new VertexBufferBinding[] { new VertexBufferBinding( new BufferData(BufferFlags.VertexBuffer, destBufferData).ToSerializableVersion(), firstVertexBuffer.Declaration, totalVertexCount, firstVertexBuffer.Stride)}; // Copy vertex buffers fixed (byte* destBufferDataStart = &destBufferData[0]) { var destBufferDataCurrent = destBufferDataStart; foreach (var meshDrawData in meshDrawDatas) { var sourceBuffer = meshDrawData.VertexBuffers[0].Buffer.GetSerializationData(); fixed (byte* sourceBufferDataStart = &sourceBuffer.Content[0]) { Utilities.CopyMemory((IntPtr)destBufferDataCurrent, (IntPtr)sourceBufferDataStart, sourceBuffer.Content.Length); destBufferDataCurrent += sourceBuffer.Content.Length; } } } if (hasIndexBuffer) { var use32BitIndex = can32BitIndex && totalVertexCount > ushort.MaxValue; // 65535 = 0xFFFF is kept for primitive restart in strip // Allocate index buffer destBufferData = new byte[(use32BitIndex ? sizeof(uint) : sizeof(ushort)) * totalIndexCount]; result.IndexBuffer = new IndexBufferBinding( new BufferData(BufferFlags.IndexBuffer, destBufferData).ToSerializableVersion(), use32BitIndex, totalIndexCount); // Copy index buffers fixed (byte* destBufferDataStart = &destBufferData[0]) { var destBufferDataCurrent = destBufferDataStart; var offset = 0; foreach (var meshDrawData in meshDrawDatas) { var indexBuffer = meshDrawData.IndexBuffer; byte[] sourceBufferContent = null; var is32Bit = false; if (indexBuffer != null) { sourceBufferContent = indexBuffer.Buffer.GetSerializationData().Content; is32Bit = indexBuffer.Is32Bit; } if (offset != 0 || (use32BitIndex != meshDrawData.IndexBuffer.Is32Bit)) { if (use32BitIndex) sourceBufferContent = CreateIntIndexBuffer(offset, meshDrawData.IndexBuffer.Count, sourceBufferContent, is32Bit); else sourceBufferContent = CreateShortIndexBuffer(offset, meshDrawData.IndexBuffer.Count, sourceBufferContent, is32Bit); } fixed (byte* sourceBufferDataStart = &sourceBufferContent[0]) { Utilities.CopyMemory((IntPtr)destBufferDataCurrent, (IntPtr)sourceBufferDataStart, sourceBufferContent.Length); destBufferDataCurrent += sourceBufferContent.Length; } offset += meshDrawData.VertexBuffers[0].Count; } } result.DrawCount = totalIndexCount; } else { result.DrawCount = totalVertexCount; } return result; }
public void Generate(IServiceRegistry services, Model model) { if (services == null) throw new ArgumentNullException("services"); if (model == null) throw new ArgumentNullException("model"); var graphicsDevice = services.GetSafeServiceAs<IGraphicsDeviceService>().GraphicsDevice; var data = this.CreatePrimitiveMeshData(); if (data.Vertices.Length == 0) { throw new InvalidOperationException("Invalid GeometricPrimitive [{0}]. Expecting non-zero Vertices array"); } var boundingBox = BoundingBox.Empty; for (int i = 0; i < data.Vertices.Length; i++) BoundingBox.Merge(ref boundingBox, ref data.Vertices[i].Position, out boundingBox); BoundingSphere boundingSphere; unsafe { fixed (void* verticesPtr = data.Vertices) BoundingSphere.FromPoints((IntPtr)verticesPtr, 0, data.Vertices.Length, VertexPositionNormalTexture.Size, out boundingSphere); } var originalLayout = data.Vertices[0].GetLayout(); // Generate Tangent/BiNormal vectors var resultWithTangentBiNormal = VertexHelper.GenerateTangentBinormal(originalLayout, data.Vertices, data.Indices); // Generate Multitexcoords var result = VertexHelper.GenerateMultiTextureCoordinates(resultWithTangentBiNormal); var meshDraw = new MeshDraw(); var layout = result.Layout; var vertexBuffer = result.VertexBuffer; var indices = data.Indices; if (indices.Length < 0xFFFF) { var indicesShort = new ushort[indices.Length]; for (int i = 0; i < indicesShort.Length; i++) { indicesShort[i] = (ushort)indices[i]; } meshDraw.IndexBuffer = new IndexBufferBinding(Buffer.Index.New(graphicsDevice, indicesShort).RecreateWith(indicesShort), false, indices.Length); } else { if (graphicsDevice.Features.Profile <= GraphicsProfile.Level_9_3) { throw new InvalidOperationException("Cannot generate more than 65535 indices on feature level HW <= 9.3"); } meshDraw.IndexBuffer = new IndexBufferBinding(Buffer.Index.New(graphicsDevice, indices).RecreateWith(indices), true, indices.Length); } meshDraw.VertexBuffers = new[] { new VertexBufferBinding(Buffer.New(graphicsDevice, vertexBuffer, BufferFlags.VertexBuffer).RecreateWith(vertexBuffer), layout, data.Vertices.Length) }; meshDraw.DrawCount = indices.Length; meshDraw.PrimitiveType = PrimitiveType.TriangleList; var mesh = new Mesh { Draw = meshDraw, BoundingBox = boundingBox, BoundingSphere = boundingSphere }; model.BoundingBox = boundingBox; model.BoundingSphere = boundingSphere; model.Add(mesh); if (MaterialInstance != null && MaterialInstance.Material != null) { model.Materials.Add(MaterialInstance); } }
/// <summary> /// Split the mesh if it has strictly more than 65535 vertices (max index = 65534) on a plaftorm that does not support 32 bits indices. /// </summary> /// <param name="meshDrawData">The mesh to analyze.</param> /// <param name="can32bitIndex">A flag stating if 32 bit indices are allowed.</param> /// <returns>A list of meshes.</returns> public unsafe static List<MeshDraw> SplitMesh(MeshDraw meshDrawData, bool can32bitIndex) { if (meshDrawData.IndexBuffer == null) return new List<MeshDraw> { meshDrawData }; if (!meshDrawData.IndexBuffer.Is32Bit) // already 16 bits buffer return new List<MeshDraw> { meshDrawData }; var verticesCount = meshDrawData.VertexBuffers[0].Count; if (verticesCount <= ushort.MaxValue) // can be put in a 16 bits buffer - 65535 = 0xFFFF is kept for primitive restart in strip { meshDrawData.CompactIndexBuffer(); return new List<MeshDraw> { meshDrawData }; } // now, we only have a 32 bits buffer that is justified because of a large vertex buffer if (can32bitIndex) // do nothing return new List<MeshDraw> { meshDrawData }; // TODO: handle primitives other than triangle list if (meshDrawData.PrimitiveType != PrimitiveType.TriangleList) return new List<MeshDraw> { meshDrawData }; // Split the mesh var finalList = new List<MeshDraw>(); fixed (byte* indicesByte = &meshDrawData.IndexBuffer.Buffer.GetSerializationData().Content[0]) { var indicesUint = (uint*)indicesByte; var splitInfos = new List<SplitInformation>(); var currentSplit = new SplitInformation(); currentSplit.StartTriangleIndex = 0; var currentIndexUintPtr = indicesUint; for (int triangleIndex = 0; triangleIndex < meshDrawData.IndexBuffer.Count / 3; ++triangleIndex) { var verticesToAdd = 0; var index0 = *currentIndexUintPtr++; var index1 = *currentIndexUintPtr++; var index2 = *currentIndexUintPtr++; if (!currentSplit.UsedIndices.Contains(index0)) ++verticesToAdd; if (!currentSplit.UsedIndices.Contains(index1)) ++verticesToAdd; if (!currentSplit.UsedIndices.Contains(index2)) ++verticesToAdd; if (currentSplit.UsedIndices.Count + verticesToAdd > 65535) // append in the same group { splitInfos.Add(currentSplit); currentSplit = new SplitInformation(); currentSplit.StartTriangleIndex = triangleIndex; } AddTriangle(currentSplit, index0, index1, index2, triangleIndex); } if (currentSplit.UsedIndices.Count > 0) splitInfos.Add(currentSplit); foreach (var splitInfo in splitInfos) { var triangleCount = splitInfo.LastTriangleIndex - splitInfo.StartTriangleIndex + 1; var newMeshDrawData = new MeshDraw { PrimitiveType = PrimitiveType.TriangleList, DrawCount = 3 * triangleCount, VertexBuffers = new VertexBufferBinding[meshDrawData.VertexBuffers.Length] }; // vertex buffers for (int vbIndex = 0; vbIndex < meshDrawData.VertexBuffers.Length; ++ vbIndex) { var stride = meshDrawData.VertexBuffers[vbIndex].Stride; if (stride == 0) stride = meshDrawData.VertexBuffers[vbIndex].Declaration.VertexStride; var newVertexBuffer = new byte[splitInfo.UsedIndices.Count * stride]; fixed (byte* vertexBufferPtr = &meshDrawData.VertexBuffers[vbIndex].Buffer.GetSerializationData().Content[0]) fixed (byte* newVertexBufferPtr = &newVertexBuffer[vbIndex]) { //copy vertex buffer foreach (var index in splitInfo.UsedIndices) Utilities.CopyMemory((IntPtr)(newVertexBufferPtr + stride * splitInfo.IndexRemapping[index]), (IntPtr)(vertexBufferPtr + stride * index), stride); } newMeshDrawData.VertexBuffers[vbIndex] = new VertexBufferBinding( new BufferData(BufferFlags.VertexBuffer, newVertexBuffer).ToSerializableVersion(), meshDrawData.VertexBuffers[vbIndex].Declaration, splitInfo.UsedIndices.Count); } // index buffer var newIndexBuffer = new byte[sizeof(ushort) * 3 * triangleCount]; fixed (byte* newIndexBufferPtr = &newIndexBuffer[0]) { var newIndexBufferUshortPtr = (ushort*)newIndexBufferPtr; var currentIndexPtr = &indicesUint[3 * splitInfo.StartTriangleIndex]; for (int triangleIndex = 0; triangleIndex < triangleCount; ++triangleIndex) { var index0 = *currentIndexPtr++; var index1 = *currentIndexPtr++; var index2 = *currentIndexPtr++; var newIndex0 = splitInfo.IndexRemapping[index0]; var newIndex1 = splitInfo.IndexRemapping[index1]; var newIndex2 = splitInfo.IndexRemapping[index2]; *newIndexBufferUshortPtr++ = newIndex0; *newIndexBufferUshortPtr++ = newIndex1; *newIndexBufferUshortPtr++ = newIndex2; } } newMeshDrawData.IndexBuffer = new IndexBufferBinding( new BufferData(BufferFlags.IndexBuffer, newIndexBuffer).ToSerializableVersion(), false, triangleCount*3); finalList.Add(newMeshDrawData); } } return finalList; }