Ejemplo n.º 1
0
 /// <summary>
 /// Add the triangle to the split information.
 /// </summary>
 /// <param name="currentSplit">The current split information.</param>
 /// <param name="index0">The index of the first vertex.</param>
 /// <param name="index1">The index of the second vertex.</param>
 /// <param name="index2">The index of the third vertex.</param>
 /// <param name="triangleIndex">The original index of the triangle.</param>
 private static void AddTriangle(SplitInformation currentSplit, uint index0, uint index1, uint index2, int triangleIndex)
 {
     if (currentSplit.UsedIndices.Add(index0))
     {
         currentSplit.IndexRemapping.Add(index0, (ushort)(currentSplit.UsedIndices.Count - 1));
     }
     if (currentSplit.UsedIndices.Add(index1))
     {
         currentSplit.IndexRemapping.Add(index1, (ushort)(currentSplit.UsedIndices.Count - 1));
     }
     if (currentSplit.UsedIndices.Add(index2))
     {
         currentSplit.IndexRemapping.Add(index2, (ushort)(currentSplit.UsedIndices.Count - 1));
     }
     currentSplit.LastTriangleIndex = triangleIndex;
 }
Ejemplo n.º 2
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);
        }
Ejemplo n.º 3
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;
        }
Ejemplo n.º 4
0
 /// <summary>
 /// Add the triangle to the split information.
 /// </summary>
 /// <param name="currentSplit">The current split information.</param>
 /// <param name="index0">The index of the first vertex.</param>
 /// <param name="index1">The index of the second vertex.</param>
 /// <param name="index2">The index of the third vertex.</param>
 /// <param name="triangleIndex">The original index of the triangle.</param>
 private static void AddTriangle(SplitInformation currentSplit, uint index0, uint index1, uint index2, int triangleIndex)
 {
     if (currentSplit.UsedIndices.Add(index0)) currentSplit.IndexRemapping.Add(index0, (ushort)(currentSplit.UsedIndices.Count - 1));
     if (currentSplit.UsedIndices.Add(index1)) currentSplit.IndexRemapping.Add(index1, (ushort)(currentSplit.UsedIndices.Count - 1));
     if (currentSplit.UsedIndices.Add(index2)) currentSplit.IndexRemapping.Add(index2, (ushort)(currentSplit.UsedIndices.Count - 1));
     currentSplit.LastTriangleIndex = triangleIndex;
 }
Ejemplo n.º 5
0
        private void Run(double[][] inputs, double[][] validationInputs)
        {
            var root       = Tree.Root = new DecisionNode(Tree);
            var thresholds = ThresholdsCalculator.Calculate(inputs);

            for (int attributeIndex = 0; attributeIndex < GlobalVariables.Dimensions; attributeIndex++)
            {
                var min = thresholds[attributeIndex].Min();

                thresholds[attributeIndex]
                    = thresholds[attributeIndex].RemoveAll(min);

                var minSplitInformation = new SplitInformation(inputs.GetColumn(attributeIndex),
                                                               validationInputs.GetColumn(attributeIndex),
                                                               validation.Length,
                                                               ComparisonKind.GreaterThan,
                                                               min,
                                                               learn.Length);

                var minSplit = new SuggestSplitPoint(attributeIndex,
                                                     ComparisonKind.GreaterThan,
                                                     min,
                                                     minSplitInformation,
                                                     null);

                var minNode = new SplitDecisionNode(Tree, root, minSplit.Left,
                                                    minSplit.ComparisonKind, minSplit.SplitValue, attributeIndex);

                inputs           = inputs.CutRowByColumnValue(attributeIndex, ComparisonKind.GreaterThan, min);
                validationInputs = validationInputs.CutRowByColumnValue(attributeIndex, ComparisonKind.GreaterThan, min);

                root.Branches.AttributeIndex = attributeIndex;
                root.Branches.AddRange(minNode);
                root = minNode;

                var max = thresholds[attributeIndex].Max();

                thresholds[attributeIndex]
                    = thresholds[attributeIndex].RemoveAll(max);

                var maxSplitInformation = new SplitInformation(inputs.GetColumn(attributeIndex),
                                                               validationInputs.GetColumn(attributeIndex),
                                                               validation.Length,
                                                               ComparisonKind.LessThan,
                                                               max,
                                                               learn.Length);

                var maxSplit = new SuggestSplitPoint(attributeIndex,
                                                     ComparisonKind.LessThan,
                                                     max,
                                                     maxSplitInformation);

                var maxNode = new SplitDecisionNode(Tree, root, maxSplit.Left,
                                                    maxSplit.ComparisonKind, maxSplit.SplitValue, attributeIndex);

                inputs           = inputs.CutRowByColumnValue(attributeIndex, ComparisonKind.LessThan, max);
                validationInputs = validationInputs.CutRowByColumnValue(attributeIndex, ComparisonKind.LessThan, max);

                root.Branches.AttributeIndex = attributeIndex;
                root.Branches.AddRange(maxNode);
                root = maxNode;
            }

            int[] maxAttributeUsage = null;
            if (GlobalVariables.GrowCondition.MaxAttributeUsage.HasValue)
            {
                maxAttributeUsage = Enumerable.Repeat(GlobalVariables.GrowCondition.MaxAttributeUsage.Value, thresholds.Length).ToArray();
            }

            Split(root, inputs, validationInputs, thresholds, root.GetHeight(), maxAttributeUsage);
        }
Ejemplo n.º 6
0
        private void Split(DecisionNode root, double[][] inputs, double[][] validationInputs, double[][] thresholds, int height, int[] attributeUsage)
        {
            if (GlobalVariables.GrowCondition.MaxTreeHeight.HasValue && GlobalVariables.GrowCondition.MaxTreeHeight <= height)
            {
                root.Output = inputs.Length;
                return;
            }

            SuggestSplitPoint suggestSplitPoint = null;

            for (int thresholdAttribute = 0; thresholdAttribute < thresholds.Length; thresholdAttribute++)
            {
                for (int thresholdIndex = 0; thresholdIndex < thresholds[thresholdAttribute].Length; thresholdIndex++)
                {
                    var comparisonKind = ComparisonKind.GreaterThanOrEqual;
                    var splitInformationLeft
                        = new SplitInformation(inputs.GetColumn(thresholdAttribute),
                                               validationInputs.GetColumn(thresholdAttribute),
                                               validation.Length,
                                               comparisonKind,
                                               thresholds[thresholdAttribute][thresholdIndex],
                                               learn.Length);

                    var splitInformationRight
                        = new SplitInformation(inputs.GetColumn(thresholdAttribute),
                                               validationInputs.GetColumn(thresholdAttribute),
                                               validation.Length,
                                               comparisonKind.GetOpposed(),
                                               thresholds[thresholdAttribute][thresholdIndex],
                                               learn.Length);

                    var localBestSplitPoint = new SuggestSplitPoint(thresholdAttribute,
                                                                    comparisonKind,
                                                                    thresholds[thresholdAttribute][thresholdIndex],
                                                                    splitInformationLeft,
                                                                    splitInformationRight);

                    // Check 1. both braches have correct size, 2. left branch has correct size and right is 0, 3. right branch has correct size and left is 0,
                    if (GlobalVariables.GrowCondition.MinLeafSize.HasValue
                        &&
                        !((splitInformationLeft.ConfusionMatrix.TruePositives >= GlobalVariables.GrowCondition.MinLeafSize.Value
                           &&
                           splitInformationRight.ConfusionMatrix.TruePositives >= GlobalVariables.GrowCondition.MinLeafSize.Value)
                          ||
                          (splitInformationLeft.ConfusionMatrix.TruePositives >= GlobalVariables.GrowCondition.MinLeafSize.Value
                           &&
                           splitInformationRight.ConfusionMatrix.TruePositives == 0)
                          ||
                          (splitInformationRight.ConfusionMatrix.TruePositives >= GlobalVariables.GrowCondition.MinLeafSize.Value
                           &&
                           splitInformationLeft.ConfusionMatrix.TruePositives == 0)))
                    {
                        continue;
                    }

                    var parentSize = splitInformationLeft.ConfusionMatrix.TruePositives
                                     + splitInformationRight.ConfusionMatrix.TruePositives;

                    if (parentSize <= 1)
                    {
                        continue;
                    }

                    if (suggestSplitPoint == null ||
                        localBestSplitPoint.IsBetterThan(suggestSplitPoint))
                    {
                        suggestSplitPoint = localBestSplitPoint;
                    }
                }
            }

            if (suggestSplitPoint == null || !suggestSplitPoint.IsBetterThanParent(root))
            {
                root.Output = inputs.Length;
                return;
            }

            if (GlobalVariables.GrowCondition.MaxAttributeUsage.HasValue)
            {
                attributeUsage[suggestSplitPoint.AttributeIndex] = attributeUsage[suggestSplitPoint.AttributeIndex] - 1;

                if (attributeUsage[suggestSplitPoint.AttributeIndex] == 0)
                {
                    thresholds[suggestSplitPoint.AttributeIndex] = new double[0];
                }
            }

            var children = new[]
            {
                new SplitDecisionNode(Tree, root, suggestSplitPoint.Left, suggestSplitPoint.ComparisonKind, suggestSplitPoint.SplitValue, suggestSplitPoint.AttributeIndex),
                new SplitDecisionNode(Tree, root, suggestSplitPoint.Right, suggestSplitPoint.ComparisonKind.GetOpposed(), suggestSplitPoint.SplitValue, suggestSplitPoint.AttributeIndex)
            };

            root.Branches.AttributeIndex = suggestSplitPoint.AttributeIndex;
            root.Branches.AddRange(children);

            foreach (var child in children)
            {
                var fulfillingInputs
                    = inputs.CutRowByColumnValue(suggestSplitPoint.AttributeIndex, child.Comparison, child.Value.Value);
                var fulfillingValidation
                    = validationInputs.CutRowByColumnValue(suggestSplitPoint.AttributeIndex, child.Comparison, child.Value.Value);

                var tempTresholds = thresholds.Copy();

                tempTresholds[suggestSplitPoint.AttributeIndex]
                    = tempTresholds[suggestSplitPoint.AttributeIndex].GetVeryfied(child.Comparison, suggestSplitPoint.SplitValue);

                Split(child, fulfillingInputs, fulfillingValidation, tempTresholds, height + 1, attributeUsage?.Copy());
            }
        }