Пример #1
0
        public unsafe static BoundingBox ComputeBoundingBox(this VertexBufferBindingData vertexBufferBinding, ref Matrix matrix)
        {
            var positionOffset = vertexBufferBinding.Declaration
                                 .EnumerateWithOffsets()
                                 .First(x => x.VertexElement.SemanticAsText == "POSITION")
                                 .Offset;

            var boundingBox = BoundingBox.Empty;

            var vertexStride = vertexBufferBinding.Declaration.VertexStride;

            fixed(byte *bufferStart = &vertexBufferBinding.Buffer.Value.Content[vertexBufferBinding.Offset])
            {
                byte *buffer = bufferStart;

                for (int i = 0; i < vertexBufferBinding.Count; ++i)
                {
                    var     position = (Vector3 *)(buffer + positionOffset);
                    Vector3 transformedPosition;

                    Vector3.TransformCoordinate(ref *position, ref matrix, out transformedPosition);
                    BoundingBox.Merge(ref boundingBox, ref transformedPosition, out boundingBox);

                    buffer += vertexStride;
                }
            }

            return(boundingBox);
        }
Пример #2
0
        /// <summary>
        /// Generates an index mapping with the specified vertex elements.
        /// If no vertex elements are specified, use the whole vertex.
        /// </summary>
        /// <param name="vertexBufferBinding">The vertex buffer binding.</param>
        /// <param name="usages">The vertex element usages to consider.</param>
        /// <returns></returns>
        public static unsafe IndexMappingResult GenerateIndexMapping(this VertexBufferBindingData vertexBufferBinding, params string[] usages)
        {
            var bufferData   = vertexBufferBinding.Buffer.Value.Content;
            var vertexStride = vertexBufferBinding.Declaration.VertexStride;
            var vertexCount  = vertexBufferBinding.Count;
            var activeBytes  = stackalloc byte[vertexStride];

            var vertexMapping = new List <int>();
            var indexMapping  = new int[vertexCount];

            var mapping = new Dictionary <VertexKey, int>(new VertexKeyEqualityComparer(activeBytes, vertexStride));

            // Create a "mask" of part of the vertices that will be used
            // TODO: Use bit packing?
            for (int i = 0; i < vertexBufferBinding.Declaration.VertexStride; ++i)
            {
                activeBytes[i] = (byte)(usages.Length == 0 ? 1 : 0);
            }

            foreach (var vertexElement in vertexBufferBinding.Declaration.EnumerateWithOffsets())
            {
                if (usages.Contains(vertexElement.VertexElement.SemanticAsText))
                {
                    for (int i = 0; i < vertexElement.Size; ++i)
                    {
                        activeBytes[vertexElement.Offset + i] = 1;
                    }
                }
            }

            // Generate index buffer
            fixed(byte *bufferPointerStart = &bufferData[vertexBufferBinding.Offset])
            {
                var bufferPointer = bufferPointerStart;

                for (int i = 0; i < vertexCount; ++i)
                {
                    // Create VertexKey (will generate hash)
                    var vertexKey = new VertexKey(bufferPointer, activeBytes, vertexStride);

                    // Get or create new index
                    int currentIndex;
                    if (!mapping.TryGetValue(vertexKey, out currentIndex))
                    {
                        currentIndex = vertexMapping.Count;
                        mapping.Add(vertexKey, currentIndex);
                        vertexMapping.Add(i);
                    }

                    // Assign index in result buffer
                    indexMapping[i] = currentIndex;

                    bufferPointer += vertexStride;
                }
            }

            return(new IndexMappingResult {
                Vertices = vertexMapping.ToArray(), Indices = indexMapping
            });
        }
Пример #3
0
        /// <summary>
        /// Determines whether the specified vertex buffer binding data is simple.
        /// A vertex buffer binding data is simple if:
        /// * Offset is 0.
        /// * Stride is 0 (automatic), or equals to Declaration.VertexStride.
        /// * Buffer.Content.Length is equal to Declaration.VertexStride * Count
        /// </summary>
        /// <param name="vertexBufferBindingData">The vertex buffer binding data.</param>
        /// <returns></returns>
        public static bool IsSimple(this VertexBufferBindingData vertexBufferBindingData)
        {
            if (vertexBufferBindingData.Offset != 0)
            {
                return(false);
            }

            var stride = vertexBufferBindingData.Declaration.VertexStride;

            if (vertexBufferBindingData.Stride != 0 &&
                vertexBufferBindingData.Stride != stride)
            {
                return(false);
            }

            var buffer = vertexBufferBindingData.Buffer.Value;

            if (buffer.Content.Length != stride * vertexBufferBindingData.Count)
            {
                return(false);
            }

            return(true);
        }
Пример #4
0
        public unsafe static void CompactHalf(this VertexBufferBindingData vertexBufferBinding)
        {
            var vertexElementsWithOffsets = vertexBufferBinding.Declaration
                                            .EnumerateWithOffsets()
                                            .OrderBy(x => x.Offset)
                                            .ToArray();

            var vertexElements = new VertexElementConvertInfo[vertexElementsWithOffsets.Length];

            int currentOffset = 0;

            for (int index = 0; index < vertexElementsWithOffsets.Length; index++)
            {
                var vertexElementConvertInfo = new VertexElementConvertInfo();
                vertexElementConvertInfo.VertexElementWithOffset = vertexElementsWithOffsets[index];
                var vertexElement       = vertexElementsWithOffsets[index].VertexElement;
                var vertexElementFormat = vertexElementConvertInfo.VertexElementWithOffset.VertexElement.Format;

                // First iteration?
                if (index == 0)
                {
                    currentOffset = vertexElementsWithOffsets[index].Offset;
                }

                vertexElements[index] = vertexElementConvertInfo;
                vertexElementConvertInfo.OldFormat = vertexElementConvertInfo.VertexElementWithOffset.VertexElement.Format;

                int offsetShift = 0;

                switch (vertexElementFormat)
                {
                case PixelFormat.R32G32_Float:
                    vertexElementFormat = PixelFormat.R16G16_Float;

                    // Adjust next offset if current object has been resized
                    offsetShift = Utilities.SizeOf <Half2>() - Utilities.SizeOf <Vector2>();
                    break;

                case PixelFormat.R32G32B32_Float:
                    vertexElementFormat = PixelFormat.R16G16B16A16_Float;

                    // Adjust next offset if current object has been resized
                    offsetShift = Utilities.SizeOf <Half4>() - Utilities.SizeOf <Vector3>();
                    break;

                case PixelFormat.R32G32B32A32_Float:
                    vertexElementFormat = PixelFormat.R16G16B16A16_Float;

                    // Adjust next offset if current object has been resized
                    offsetShift = Utilities.SizeOf <Half4>() - Utilities.SizeOf <Vector4>();
                    break;
                }

                // Has format changed?
                vertexElementConvertInfo.NeedConversion = vertexElementFormat != vertexElementConvertInfo.VertexElementWithOffset.VertexElement.Format;

                // Create new vertex element with adjusted offset, and maybe new vertex format (if modified)
                vertexElementConvertInfo.VertexElementWithOffset.VertexElement
                    = new VertexElement(vertexElement.semanticName, vertexElement.SemanticIndex, vertexElementFormat, currentOffset);

                // Increment next offset by the same difference as in original declaration
                if (index + 1 < vertexElementsWithOffsets.Length)
                {
                    currentOffset += vertexElementsWithOffsets[index + 1].Offset - vertexElementsWithOffsets[index].Offset;
                }

                currentOffset += offsetShift;

                vertexElements[index] = vertexElementConvertInfo;
            }

            var oldVertexStride = vertexBufferBinding.Declaration.VertexStride;

            vertexBufferBinding.Declaration = new VertexDeclaration(vertexElements.Select(x => x.VertexElementWithOffset.VertexElement).ToArray());

            var newVertexStride = vertexBufferBinding.Declaration.VertexStride;
            var newBufferData   = new byte[vertexBufferBinding.Count * newVertexStride];

            fixed(byte *oldBuffer = &vertexBufferBinding.Buffer.Value.Content[vertexBufferBinding.Offset])
            fixed(byte *newBuffer = &newBufferData[0])
            {
                var oldBufferVertexPtr = (IntPtr)oldBuffer;
                var newBufferVertexPtr = (IntPtr)newBuffer;

                for (int i = 0; i < vertexBufferBinding.Count; ++i)
                {
                    foreach (var element in vertexElements)
                    {
                        var oldBufferElementPtr = oldBufferVertexPtr + element.VertexElementWithOffset.Offset;
                        var newBufferElementPtr = newBufferVertexPtr + element.VertexElementWithOffset.VertexElement.AlignedByteOffset;

                        if (element.NeedConversion)
                        {
                            // Convert floatX => halfX
                            switch (element.OldFormat)
                            {
                            case PixelFormat.R32G32_Float:
                                *((Half2 *)newBufferElementPtr) = (Half2)(*((Vector2 *)oldBufferElementPtr));
                                break;

                            case PixelFormat.R32G32B32_Float:
                                // Put 1.0f in
                                *((Half4 *)newBufferElementPtr) = (Half4)(new Vector4(*((Vector3 *)oldBufferElementPtr), 1.0f));
                                break;

                            case PixelFormat.R32G32B32A32_Float:
                                *((Half4 *)newBufferElementPtr) = (Half4)(*((Vector4 *)oldBufferElementPtr));
                                break;
                            }
                        }
                        else
                        {
                            // Copy as is
                            Utilities.CopyMemory(newBufferElementPtr, oldBufferElementPtr, element.VertexElementWithOffset.Size);
                        }
                    }

                    oldBufferVertexPtr += oldVertexStride;
                    newBufferVertexPtr += newVertexStride;
                }
            }

            vertexBufferBinding.Offset = 0;
            vertexBufferBinding.Buffer = new BufferData(BufferFlags.VertexBuffer, newBufferData);
        }
Пример #5
0
        /// <summary>
        /// Transform a vertex buffer positions, normals, tangents and bitangents using the given matrix.
        /// </summary>
        /// <param name="meshData">The mesh data.</param>
        public unsafe static void TransformBuffer(this VertexBufferBindingData vertexBufferBinding, ref Matrix matrix)
        {
            // List of items that need to be transformed by the matrix
            var vertexElementsToTransform1 = vertexBufferBinding.Declaration
                                             .EnumerateWithOffsets()
                                             .Where(x => x.VertexElement.SemanticName == VertexElementUsage.Position &&
                                                    (x.VertexElement.Format == PixelFormat.R32G32B32A32_Float ||
                                                     x.VertexElement.Format == PixelFormat.R32G32B32_Float))
                                             .ToArray();

            // List of items that need to be transformed by the inverse transpose matrix
            var vertexElementsToTransform2 = vertexBufferBinding.Declaration
                                             .EnumerateWithOffsets()
                                             .Where(x => (x.VertexElement.SemanticName == VertexElementUsage.Normal ||
                                                          x.VertexElement.SemanticName == VertexElementUsage.Tangent ||
                                                          x.VertexElement.SemanticName == VertexElementUsage.BiTangent) &&
                                                    x.VertexElement.Format == PixelFormat.R32G32B32_Float)
                                             .ToArray();

            // If needed, compute matrix inverse transpose
            Matrix inverseTransposeMatrix;

            if (vertexElementsToTransform2.Length > 0)
            {
                Matrix.Invert(ref matrix, out inverseTransposeMatrix);
                Matrix.Transpose(ref inverseTransposeMatrix, out inverseTransposeMatrix);
            }
            else
            {
                inverseTransposeMatrix = Matrix.Identity;
            }

            // Transform buffer data
            var bufferData   = vertexBufferBinding.Buffer.Value.Content;
            var vertexStride = vertexBufferBinding.Declaration.VertexStride;
            var vertexCount  = vertexBufferBinding.Count;

            fixed(byte *bufferPointerStart = &bufferData[vertexBufferBinding.Offset])
            {
                var bufferPointer = bufferPointerStart;

                for (int i = 0; i < vertexCount; ++i)
                {
                    // Transform positions
                    foreach (var vertexElement in vertexElementsToTransform1)
                    {
                        var elementPointer = bufferPointer + vertexElement.Offset;
                        if (vertexElement.VertexElement.Format == PixelFormat.R32G32B32A32_Float)
                        {
                            Vector4.Transform(ref *(Vector4 *)elementPointer, ref matrix, out *(Vector4 *)elementPointer);
                        }
                        else
                        {
                            Vector3.TransformCoordinate(ref *(Vector3 *)elementPointer, ref matrix, out *(Vector3 *)elementPointer);
                        }
                    }

                    // Transform normals
                    foreach (var vertexElement in vertexElementsToTransform2)
                    {
                        var elementPointer = bufferPointer + vertexElement.Offset;
                        Vector3.TransformNormal(ref *(Vector3 *)elementPointer, ref inverseTransposeMatrix, out *(Vector3 *)elementPointer);
                    }

                    bufferPointer += vertexStride;
                }
            }
        }