Exemple #1
0
 /// <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;
 }
        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;
        }
Exemple #3
0
 /// <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();

            pipelineState = new MutablePipelineState(GraphicsDevice);

            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),
            };

            mesh = new Mesh
            {
                Draw = meshDraw,
            };

            simpleEffect = new EffectInstance(new Effect(GraphicsDevice, SpriteEffect.Bytecode));
            simpleEffect.Parameters.Set(TexturingKeys.Texture0, UVTexture);
            simpleEffect.UpdateEffect(GraphicsDevice);

            // TODO GRAPHICS REFACTOR
            //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)) };
        }
Exemple #5
0
        /// <inheritdoc/>
        public override void Draw(RenderDrawContext context, RenderView renderView, RenderViewStage renderViewStage, int startIndex, int endIndex)
        {
            var commandList = context.CommandList;

            foreach (var renderFeature in RenderFeatures)
            {
                renderFeature.Draw(context, renderView, renderViewStage, startIndex, endIndex);
            }

            // TODO: stackalloc?
            var descriptorSetsLocal = descriptorSets.Value;

            if (descriptorSetsLocal == null || descriptorSetsLocal.Length < EffectDescriptorSetSlotCount)
            {
                descriptorSetsLocal = descriptorSets.Value = new DescriptorSet[EffectDescriptorSetSlotCount];
            }

            MeshDraw currentDrawData = null;

            for (int index = startIndex; index < endIndex; index++)
            {
                var renderNodeReference = renderViewStage.SortedRenderNodes[index].RenderNode;
                var renderNode          = GetRenderNode(renderNodeReference);

                var renderMesh = (RenderMesh)renderNode.RenderObject;
                var drawData   = renderMesh.ActiveMeshDraw;

                // Get effect
                // TODO: Use real effect slot
                var renderEffect = renderNode.RenderEffect;
                if (renderEffect.Effect == null)
                {
                    continue;
                }

                // Bind VB
                if (currentDrawData != drawData)
                {
                    for (int i = 0; i < drawData.VertexBuffers.Length; i++)
                    {
                        var vertexBuffer = drawData.VertexBuffers[i];
                        commandList.SetVertexBuffer(i, vertexBuffer.Buffer, vertexBuffer.Offset, vertexBuffer.Stride);
                    }
                    if (drawData.IndexBuffer != null)
                    {
                        commandList.SetIndexBuffer(drawData.IndexBuffer.Buffer, drawData.IndexBuffer.Offset, drawData.IndexBuffer.Is32Bit);
                    }
                    currentDrawData = drawData;
                }

                var resourceGroupOffset = ComputeResourceGroupOffset(renderNodeReference);

                // Update cbuffer
                renderEffect.Reflection.BufferUploader.Apply(context.CommandList, ResourceGroupPool, resourceGroupOffset);

                // Bind descriptor sets
                for (int i = 0; i < descriptorSetsLocal.Length; ++i)
                {
                    var resourceGroup = ResourceGroupPool[resourceGroupOffset++];
                    if (resourceGroup != null)
                    {
                        descriptorSetsLocal[i] = resourceGroup.DescriptorSet;
                    }
                }

                commandList.SetPipelineState(renderEffect.PipelineState);
                commandList.SetDescriptorSets(0, descriptorSetsLocal);

                // Draw
                if (drawData.IndexBuffer == null)
                {
                    commandList.Draw(drawData.DrawCount, drawData.StartLocation);
                }
                else
                {
                    commandList.DrawIndexed(drawData.DrawCount, drawData.StartLocation);
                }
            }
        }
 public override MeshDraw CreateDebugPrimitive(GraphicsDevice device)
 {
     return cachedDebugPrimitive ?? (cachedDebugPrimitive = GeometricPrimitive.Sphere.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;
        }
Exemple #8
0
        /// <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;
        }
Exemple #9
0
        private InputElementDescription[] PrepareInputElements(PipelineStateDescription pipelineState, MeshDraw drawData)
        {
            // Get the input elements already contained in the mesh's vertex buffers
            var availableInputElements = drawData.VertexBuffers.CreateInputElements();
            var inputElements          = new List <InputElementDescription>(availableInputElements);

            // In addition, add input elements for all attributes that are not contained in a bound buffer, but required by the shader
            foreach (var inputAttribute in pipelineState.EffectBytecode.Reflection.InputAttributes)
            {
                var inputElementIndex = FindElementBySemantic(availableInputElements, inputAttribute.SemanticName, inputAttribute.SemanticIndex);

                // Provided by any vertex buffer?
                if (inputElementIndex >= 0)
                {
                    continue;
                }

                inputElements.Add(new InputElementDescription
                {
                    AlignedByteOffset    = 0,
                    Format               = PixelFormat.R32G32B32A32_Float,
                    InputSlot            = drawData.VertexBuffers.Length,
                    InputSlotClass       = InputClassification.Vertex,
                    InstanceDataStepRate = 0,
                    SemanticIndex        = inputAttribute.SemanticIndex,
                    SemanticName         = inputAttribute.SemanticName
                });
            }

            return(inputElements.ToArray());
        }
Exemple #10
0
        /// <summary>
        /// Creates an Entity that contains our dynamic Vertex and Index buffers.
        /// This Entity will be rendered by the model renderer.
        /// </summary>
        /// <param name="verticesCount"></param>
        /// <param name="indicesCount"></param>
        private void CreateTerrainModelEntity(int verticesCount, int indicesCount)
        {
            // Compute sizes
            var vertexDeclaration = VertexNormalTexture.VertexDeclaration;
            var vertexBufferSize = verticesCount * vertexDeclaration.CalculateSize();
            var indexBufferSize = indicesCount * sizeof(short);

            // Create Vertex and Index buffers
            terrainVertexBuffer = Buffer.Vertex.New(GraphicsDevice, vertexBufferSize, GraphicsResourceUsage.Dynamic);
            terrainIndexBuffer = Buffer.New(GraphicsDevice, indexBufferSize, BufferFlags.IndexBuffer, GraphicsResourceUsage.Dynamic);

            // Prepare mesh and entity
            var meshDraw = new MeshDraw
            {
                PrimitiveType = PrimitiveType.TriangleStrip,
                VertexBuffers = new[] { new VertexBufferBinding(terrainVertexBuffer, vertexDeclaration, verticesCount) },
                IndexBuffer = new IndexBufferBinding(terrainIndexBuffer, false, indicesCount),
            };

            // Load the material and set parameters
            TerrainMaterial.Parameters.Set(VertexTextureTerrainKeys.MeshTexture0, WaterTexture);
            TerrainMaterial.Parameters.Set(VertexTextureTerrainKeys.MeshTexture1, GrassTexture);
            TerrainMaterial.Parameters.Set(VertexTextureTerrainKeys.MeshTexture2, MountainTexture);

            // Set up material regions
            TerrainMaterial.Parameters.Set(VertexTextureTerrainKeys.MinimumHeight0, -10);
            TerrainMaterial.Parameters.Set(VertexTextureTerrainKeys.OptimalHeight0, 40);
            TerrainMaterial.Parameters.Set(VertexTextureTerrainKeys.MaximumHeight0, 70);

            TerrainMaterial.Parameters.Set(VertexTextureTerrainKeys.MinimumHeight1, 60);
            TerrainMaterial.Parameters.Set(VertexTextureTerrainKeys.OptimalHeight1, 80);
            TerrainMaterial.Parameters.Set(VertexTextureTerrainKeys.MaximumHeight1, 90);

            TerrainMaterial.Parameters.Set(VertexTextureTerrainKeys.MinimumHeight2, 85);
            TerrainMaterial.Parameters.Set(VertexTextureTerrainKeys.OptimalHeight2, 95);
            TerrainMaterial.Parameters.Set(VertexTextureTerrainKeys.MaximumHeight2, 125);

            terrainMesh = new Mesh { Draw = meshDraw, MaterialIndex = 0 };
            TerrainEntity.GetOrCreate<ModelComponent>().Model = new Model { terrainMesh, TerrainMaterial };
        }