예제 #1
0
            public void Execute()
            {
                var bvh = new BoundingVolumeHierarchy(Nodes, NodeFilters);

                bvh.BuildFirstNLevels(Points, Ranges, BranchNodeOffsets, ThreadCount, out int branchCount);
                BranchCount[0] = branchCount;
            }
예제 #2
0
        private bool FindInteractionVolumeHit(Ray ray, out int interactionVolumeHitIndex, out IntersectInfo info)
        {
            interactionVolumeHitIndex = -1;
            if (interactionVolumes.Count == 0 || interactionVolumes[0].CollisionVolume == null)
            {
                info = null;
                return(false);
            }

            List <IRayTraceable> mesheTraceables = new List <IRayTraceable>();

            foreach (InteractionVolume interactionVolume in interactionVolumes)
            {
                IRayTraceable traceData = interactionVolume.CollisionVolume;
                mesheTraceables.Add(new Transform(traceData, interactionVolume.TotalTransform));
            }
            IRayTraceable allObjects = BoundingVolumeHierarchy.CreateNewHierachy(mesheTraceables);

            info = allObjects.GetClosestIntersection(ray);
            if (info != null)
            {
                for (int i = 0; i < interactionVolumes.Count; i++)
                {
                    List <IRayTraceable> insideBounds = new List <IRayTraceable>();
                    interactionVolumes[i].CollisionVolume.GetContained(insideBounds, info.closestHitObject.GetAxisAlignedBoundingBox());
                    if (insideBounds.Contains(info.closestHitObject))
                    {
                        interactionVolumeHitIndex = i;
                        return(true);
                    }
                }
            }

            return(false);
        }
예제 #3
0
        public static IPrimitive Convert(IObject3D item, MaterialAbstract partMaterial = null)
        {
            List <IPrimitive> renderCollection = new List <IPrimitive>();

            if (partMaterial == null)
            {
                partMaterial = new SolidMaterial(new ColorF(.9, .2, .1), .01, 0.0, 2.0);
            }
            int index = 0;

            Vector3[] triangle = new Vector3[3];
            foreach (Mesh mesh in item.VisibleMeshes().Select(i => i.Mesh))
            {
                foreach (Face face in mesh.Faces)
                {
                    foreach (Vertex vertex in face.Vertices())
                    {
                        triangle[index++] = vertex.Position;
                        if (index == 3)
                        {
                            index = 0;
                            renderCollection.Add(new TriangleShape(triangle[0], triangle[1], triangle[2], partMaterial));
                        }
                    }
                }
            }

            return(BoundingVolumeHierarchy.CreateNewHierachy(renderCollection));
        }
예제 #4
0
        public static IRayTraceable Convert(PolygonMesh.Mesh simpleMesh)
        {
            List <IRayTraceable> renderCollection = new List <IRayTraceable>();

            //SolidMaterial redStuff = new SolidMaterial(new RGBA_Floats(.9, .2, .1), .01, 0.0, 2.0);
            SolidMaterial mhBlueStuff = new SolidMaterial(new RGBA_Floats(0, .32, .58), .01, 0.0, 2.0);
            int           index       = 0;

            Vector3[] triangle = new Vector3[3];
            //PolygonMesh.Mesh simpleMesh = PolygonMesh.Processors.StlProcessing.Load("complex.stl");
            //PolygonMesh.Mesh simpleMesh = PolygonMesh.Processors.StlProcessing.Load("Spider With Base.stl");
            foreach (PolygonMesh.Face face in simpleMesh.Faces)
            {
                foreach (PolygonMesh.Vertex vertex in face.Vertices())
                {
                    triangle[index++] = vertex.Position;
                    if (index == 3)
                    {
                        index = 0;
                        renderCollection.Add(new TriangleShape(triangle[0], triangle[1], triangle[2], mhBlueStuff));
                    }
                }
            }

            return(BoundingVolumeHierarchy.CreateNewHierachy(renderCollection));
        }
예제 #5
0
            public void Execute()
            {
                if (ShouldDoWork[0] == 0)
                {
                    // Restore original branch count
                    BranchCount[0] = OldBranchCount[0];
                    return;
                }

                int minBranchNodeIndex = BranchNodeOffsets[0] - 1;
                int branchCount        = BranchCount[0];

                for (int i = 1; i < BranchCount[0]; i++)
                {
                    minBranchNodeIndex = math.min(BranchNodeOffsets[i] - 1, minBranchNodeIndex);
                }

                var bvh = new BoundingVolumeHierarchy(Nodes, NodeFilters);

                bvh.Refit(Aabbs, 1, minBranchNodeIndex);

                if (NodeFilters != null)
                {
                    bvh.BuildCombinedCollisionFilter(LeafFilters, 1, minBranchNodeIndex);
                }
            }
예제 #6
0
        public static IPrimitive Convert(IObject3D rootItem)
        {
            var tracePrimitives = new List <IPrimitive>();

            foreach (var item in rootItem.VisibleMeshes())
            {
                SolidMaterial partMaterial;
                var           color = item.WorldColor(rootItem);
                if (color.alpha != 0)
                {
                    partMaterial = new SolidMaterial(new ColorF(color.Red0To1, color.Green0To1, color.Blue0To1), .01, 0.0, 2.0);
                }
                else
                {
                    partMaterial = new SolidMaterial(new ColorF(.9, .2, .1), .01, 0.0, 2.0);
                }

                var worldMatrix = item.WorldMatrix(rootItem);

                item.Mesh.AddTracePrimitives(partMaterial, worldMatrix, tracePrimitives);
            }

            // return an empty collection
            return(BoundingVolumeHierarchy.CreateNewHierachy(tracePrimitives));
        }
예제 #7
0
        public static IPrimitive Convert(PolygonMesh.Mesh simpleMesh, MaterialAbstract partMaterial = null)
        {
            List <IPrimitive> renderCollection = new List <IPrimitive>();

            if (partMaterial == null)
            {
                partMaterial = new SolidMaterial(new RGBA_Floats(.9, .2, .1), .01, 0.0, 2.0);
            }
            int index = 0;

            Vector3[] triangle = new Vector3[3];
            foreach (PolygonMesh.Face face in simpleMesh.Faces)
            {
                foreach (PolygonMesh.Vertex vertex in face.Vertices())
                {
                    triangle[index++] = vertex.Position;
                    if (index == 3)
                    {
                        index = 0;
                        renderCollection.Add(new TriangleShape(triangle[0], triangle[1], triangle[2], partMaterial));
                    }
                }
            }

            return(BoundingVolumeHierarchy.CreateNewHierachy(renderCollection));
        }
예제 #8
0
        public static ITraceable Convert(IObject3D item, MaterialAbstract partMaterial = null)
        {
            var renderCollection = new List <ITraceable>();

            if (partMaterial == null)
            {
                partMaterial = new SolidMaterial(new ColorF(.9, .2, .1), .01, 0.0, 2.0);
            }

            int index    = 0;
            var triangle = new Vector3[3];

            foreach (Mesh mesh in item.VisibleMeshes().Select(i => i.Mesh))
            {
                throw new NotImplementedException();
                //foreach (Face face in mesh.Faces)
                //{
                //	foreach (Vertex vertex in face.Vertices())
                //	{
                //		triangle[index++] = vertex.Position;
                //		if (index == 3)
                //		{
                //			index = 0;
                //			renderCollection.Add(new TriangleShape(triangle[0], triangle[1], triangle[2], partMaterial));
                //		}
                //	}
                //}
            }

            return(BoundingVolumeHierarchy.CreateNewHierachy(renderCollection));
        }
예제 #9
0
        public static void CreateITraceableForMeshGroup(List <PlatingMeshGroupData> perMeshGroupInfo, List <MeshGroup> meshGroups, int meshGroupIndex, ReportProgressRatio reportProgress)
        {
            if (meshGroups != null)
            {
                MeshGroup meshGroup = meshGroups[meshGroupIndex];
                perMeshGroupInfo[meshGroupIndex].meshTraceableData.Clear();
                int totalActionCount = 0;
                foreach (Mesh mesh in meshGroup.Meshes)
                {
                    totalActionCount += mesh.Faces.Count;
                }
                int  currentAction   = 0;
                bool needUpdateTitle = true;
                for (int i = 0; i < meshGroup.Meshes.Count; i++)
                {
                    Mesh mesh = meshGroup.Meshes[i];
                    List <IPrimitive> allPolys = AddTraceDataForMesh(mesh, totalActionCount, ref currentAction, ref needUpdateTitle, reportProgress);

                    needUpdateTitle = true;
                    if (reportProgress != null)
                    {
                        bool continueProcessing;
                        reportProgress(currentAction / (double)totalActionCount, "Creating Trace Group", out continueProcessing);
                    }

                    // only allow limited recusion to speed this up building this data
                    IPrimitive traceData = BoundingVolumeHierarchy.CreateNewHierachy(allPolys, 0);
                    perMeshGroupInfo[meshGroupIndex].meshTraceableData.Add(traceData);
                }
            }
        }
예제 #10
0
        public static void CreateITraceableForMesh(List <PlatingMeshData> perMeshInfo, List <Mesh> meshes, int i)
        {
            if (meshes[i] != null)
            {
                List <IRayTraceable> allPolys  = new List <IRayTraceable>();
                List <Vector3>       positions = new List <Vector3>();
                foreach (Face face in meshes[i].Faces)
                {
                    positions.Clear();
                    foreach (Vertex vertex in face.VertexIterator())
                    {
                        positions.Add(vertex.Position);
                    }

                    // We should use the teselator for this if it is greater than 3.
                    Vector3 next = positions[1];
                    for (int positionIndex = 2; positionIndex < positions.Count; positionIndex++)
                    {
                        TriangleShape triangel = new TriangleShape(positions[0], next, positions[positionIndex], null);
                        allPolys.Add(triangel);
                        next = positions[positionIndex];
                    }
                }

                perMeshInfo[i].traceableData = BoundingVolumeHierarchy.CreateNewHierachy(allPolys);
            }
        }
예제 #11
0
        /// <summary>
        /// Create a bounding volume hierarchy for the give mesh.
        /// </summary>
        /// <param name="mesh">The mesh to add the BVH to.</param>
        /// <param name="material">The tracing material to use.</param>
        /// <param name="matrix">A transformation to apply to the trace data</param>
        /// <param name="maxRecursion">The max depth to create the BVH tree.</param>
        /// <returns>The created BVH tree.</returns>
        public static ITraceable CreateBVHData(this Mesh mesh, MaterialAbstract material, Matrix4X4 matrix, int maxRecursion = int.MaxValue)
        {
            var allPolys = new List <ITraceable>();

            mesh.AddTraceables(material, matrix, allPolys);

            return(BoundingVolumeHierarchy.CreateNewHierachy(allPolys, maxRecursion));
        }
예제 #12
0
        public static IPrimitive CreateTraceDataForMesh(Mesh mesh)
        {
            int  unusedInt             = 0;
            bool unusedBool            = false;
            List <IPrimitive> allPolys = AddTraceDataForMesh(mesh, 0, ref unusedInt, ref unusedBool, null);

            return(BoundingVolumeHierarchy.CreateNewHierachy(allPolys));
        }
예제 #13
0
        public static IPrimitive Convert(List <IObject3D> renderDatas)
        {
            List <IPrimitive> renderCollection = new List <IPrimitive>();

            foreach (var renderData in renderDatas)
            {
                renderCollection.Add(Convert(renderData));
            }

            return(BoundingVolumeHierarchy.CreateNewHierachy(renderCollection));
        }
예제 #14
0
        public void NodeCount()
        {
            const int primitiveCount = 1_000;

            for (int i = 0; i < 10; i++)
            {
                BoundingVolumeHierarchy bvh = RandomBVH(primitiveCount);
                int nodeCount = CountNodes(bvh);
                Debug.WriteLine($"Node count in percentage of primitives: {(float)nodeCount / primitiveCount}");
                Assert.IsTrue(nodeCount <= primitiveCount * 2);
            }
예제 #15
0
        public static IPrimitive CreateTraceData(this FaceList faceList, List <Vector3Float> vertexList, int maxRecursion = int.MaxValue)
        {
            var allPolys = new List <IPrimitive>();

            foreach (var face in faceList)
            {
                allPolys.Add(new TriangleShape(vertexList[face.v0], vertexList[face.v1], vertexList[face.v2], null));
            }

            return(BoundingVolumeHierarchy.CreateNewHierachy(allPolys, maxRecursion));
        }
        private bool FindHitObject3DControl(Ray ray, out IObject3DControl hitObject3DControl, out IntersectInfo info)
        {
            var object3DControls = this.Object3DControls;

            hitObject3DControl = null;

            if (!object3DControls.Any())
            {
                info = null;
                return(false);
            }

            var traceables = new List <ITraceable>();

            foreach (var object3DControl in object3DControls)
            {
                ITraceable traceable = object3DControl.GetTraceable();
                if (traceable != null)
                {
                    traceables.Add(traceable);
                }
            }

            if (traceables.Count <= 0)
            {
                info = null;
                return(false);
            }

            var bvhHierachy = BoundingVolumeHierarchy.CreateNewHierachy(traceables);

            info = bvhHierachy.GetClosestIntersection(ray);
            if (info != null)
            {
                // we hit some part of the collection of controls, figure out which one
                foreach (var object3DControlBase in object3DControls)
                {
                    var insideBounds = new List <IBvhItem>();
                    var traceable    = object3DControlBase.GetTraceable();
                    if (traceable != null)
                    {
                        traceable.GetContained(insideBounds, info.ClosestHitObject.GetAxisAlignedBoundingBox());
                        if (insideBounds.Contains(info.ClosestHitObject))
                        {
                            // we hit the control that has the hit point within its bounds
                            hitObject3DControl = object3DControlBase;
                            return(true);
                        }
                    }
                }
            }

            return(false);
        }
예제 #17
0
        /// <summary>
        /// Create a bounding volume hierarchy for the given mesh.
        /// </summary>
        /// <param name="mesh">The mesh to add the BVH to.</param>
        /// <returns>The created BVH tree.</returns>
        public static ITraceable CreateBVHData(this Mesh mesh, BvhCreationOptions bvhCreationOptions = BvhCreationOptions.LegacySlowConstructionFastTracing)
        {
            // test new BvHBuilderAac
            // BvhBuilderAac.Create(mesh);

            var allPolys = new List <ITraceable>();

            mesh.AddTraceables(null, Matrix4X4.Identity, allPolys);

            return(BoundingVolumeHierarchy.CreateNewHierachy(allPolys, bvhCreationOptions));
        }
예제 #18
0
        private bool FindInteractionVolumeHit(Ray ray, out InteractionVolume hitIAVolume, out IntersectInfo info)
        {
            var iaVolumes = this.InteractionVolumes;

            hitIAVolume = null;

            if (!iaVolumes.Any())
            {
                info = null;
                return(false);
            }

            // TODO: Rewrite as projection without extra list
            // - Looks like the extra list is always required as CreateNewHierachy requires a List and we can only produce an IEnumerable without the list overhead
            // - var uiTraceables = iaVolumes.Where(ia => ia.CollisionVolume != null).Select(ia => new Transform(ia.CollisionVolume, ia.TotalTransform)).ToList<IPrimitive>();
            var uiTraceables = new List <IPrimitive>();

            foreach (var interactionVolume in iaVolumes.OfType <InteractionVolume>())
            {
                if (interactionVolume.CollisionVolume != null)
                {
                    IPrimitive traceData = interactionVolume.CollisionVolume;
                    uiTraceables.Add(new Transform(traceData, interactionVolume.TotalTransform));
                }
            }

            if (uiTraceables.Count <= 0)
            {
                info = null;
                return(false);
            }

            IPrimitive allUiObjects = BoundingVolumeHierarchy.CreateNewHierachy(uiTraceables);

            info = allUiObjects.GetClosestIntersection(ray);
            if (info != null)
            {
                foreach (var iaVolume in iaVolumes.OfType <InteractionVolume>())
                {
                    var insideBounds = new List <IBvhItem>();
                    if (iaVolume.CollisionVolume != null)
                    {
                        iaVolume.CollisionVolume.GetContained(insideBounds, info.closestHitObject.GetAxisAlignedBoundingBox());
                        if (insideBounds.Contains(info.closestHitObject))
                        {
                            hitIAVolume = iaVolume;
                            return(true);
                        }
                    }
                }
            }

            return(false);
        }
예제 #19
0
        public static IPrimitive Convert(List <PolygonMesh.MeshGroup> meshGroups, MaterialAbstract partMaterial = null)
        {
            List <IPrimitive> renderCollection = new List <IPrimitive>();

            foreach (MeshGroup meshGroup in meshGroups)
            {
                renderCollection.Add(Convert(meshGroup, partMaterial));
            }

            return(BoundingVolumeHierarchy.CreateNewHierachy(renderCollection));
        }
예제 #20
0
        public IRayTraceable GetIRayTraceableRecursive(Union objectToProcess)
        {
            List <IRayTraceable> items = new List <IRayTraceable>();

            foreach (CsgObject copiedObject in objectToProcess.AllObjects)
            {
                items.Add(GetIRayTraceableRecursive((dynamic)copiedObject));
            }

            return(BoundingVolumeHierarchy.CreateNewHierachy(items));
        }
예제 #21
0
        public static ITraceable CreateTraceData(FaceList faceList, List <Vector3Float> vertexList, BvhCreationOptions bvhCreationOptions = BvhCreationOptions.FavorFastTracing)
        {
            var allPolys = new List <ITraceable>();

            foreach (var face in faceList)
            {
                allPolys.Add(new TriangleShape(vertexList[face.v0], vertexList[face.v1], vertexList[face.v2], null));
            }

            return(BoundingVolumeHierarchy.CreateNewHierachy(allPolys, bvhCreationOptions));
        }
예제 #22
0
            public void Execute(int index)
            {
                Assert.IsTrue(BranchNodeOffsets[index] >= 0);
                var bvh      = new BoundingVolumeHierarchy(Nodes, NodeFilters);
                int lastNode = bvh.BuildBranch(Points, Aabbs, Ranges[index], BranchNodeOffsets[index]);

                if (NodeFilters != null)
                {
                    bvh.BuildCombinedCollisionFilter(BodyFilters, BranchNodeOffsets[index], lastNode);
                    bvh.BuildCombinedCollisionFilter(Ranges[index].Root);
                }
            }
예제 #23
0
 public void Construct()
 {
     Objects.Clear();
     Objects.AddRange(_intersectables);
     if (_constructBvh)
     {
         BVH = new BoundingVolumeHierarchy(_boundables);
         Objects.Add(BVH);
     }
     else
     {
         Objects.AddRange(_boundables);
     }
 }
            public void Execute()
            {
                if (ShouldDoWork[0] == 0)
                {
                    // If we need to to skip tree building tasks, than set BranchCount to zero so
                    // that BuildBranchesJob also gets early out in runtime.
                    BranchCount[0] = 0;
                    return;
                }

                var bvh = new BoundingVolumeHierarchy(Nodes, NodeFilters);

                bvh.BuildFirstNLevels(Points, Ranges, BranchNodeOffsets, ThreadCount, out int branchCount);
                BranchCount[0] = branchCount;
            }
예제 #25
0
        private void AddCubeOfShperes()
        {
            List <IRayTraceable> scanData1 = new List <IRayTraceable>();
            Random rand = new Random(0);
            double dist = 2;

            for (int i = 0; i < 4000; i++)
            {
                BaseShape littleShpere = new SphereShape(new Vector3(rand.NextDouble() * dist - dist / 2, rand.NextDouble() * dist - dist / 2, rand.NextDouble() * dist - dist / 2),
                                                         rand.NextDouble() * .1 + .01,
                                                         new SolidMaterial(new RGBA_Floats(rand.NextDouble() * .5 + .5, rand.NextDouble() * .5 + .5, rand.NextDouble() * .5 + .5), 0, 0.0, 2.0));
                scanData1.Add(littleShpere);
            }

            renderCollection.Add(BoundingVolumeHierarchy.CreateNewHierachy(scanData1));
        }
예제 #26
0
        private bool FindMeshGroupHitPosition(Vector2 screenPosition, out int meshHitIndex)
        {
            meshHitIndex = 0;
            if (MeshGroupExtraData.Count == 0 || MeshGroupExtraData[0].meshTraceableData == null)
            {
                return(false);
            }

            List <IPrimitive> mesheTraceables = new List <IPrimitive>();

            for (int i = 0; i < MeshGroupExtraData.Count; i++)
            {
                foreach (IPrimitive traceData in MeshGroupExtraData[i].meshTraceableData)
                {
                    mesheTraceables.Add(new Transform(traceData, MeshGroupTransforms[i].TotalTransform));
                }
            }
            IPrimitive allObjects = BoundingVolumeHierarchy.CreateNewHierachy(mesheTraceables);

            Vector2       meshViewerWidgetScreenPosition = meshViewerWidget.TransformFromParentSpace(this, screenPosition);
            Ray           ray  = meshViewerWidget.TrackballTumbleWidget.GetRayFromScreen(meshViewerWidgetScreenPosition);
            IntersectInfo info = allObjects.GetClosestIntersection(ray);

            if (info != null)
            {
                meshSelectInfo.planeDownHitPos = info.hitPosition;
                meshSelectInfo.lastMoveDelta   = new Vector3();

                for (int i = 0; i < MeshGroupExtraData.Count; i++)
                {
                    List <IPrimitive> insideBounds = new List <IPrimitive>();
                    foreach (IPrimitive traceData in MeshGroupExtraData[i].meshTraceableData)
                    {
                        traceData.GetContained(insideBounds, info.closestHitObject.GetAxisAlignedBoundingBox());
                    }
                    if (insideBounds.Contains(info.closestHitObject))
                    {
                        meshHitIndex = i;
                        return(true);
                    }
                }
            }

            return(false);
        }
예제 #27
0
        public static IPrimitive CreateTraceData(this Mesh mesh, int maxRecursion = int.MaxValue)
        {
            List <IPrimitive> allPolys  = new List <IPrimitive>();
            List <Vector3>    positions = new List <Vector3>();
            List <Vector2>    uvs       = new List <Vector2>();

            foreach (Face face in mesh.Faces)
            {
                positions.Clear();
                bool hasTexture = false;

                foreach (FaceEdge faceEdge in face.FaceEdges())
                {
                    if (mesh.TextureUV.ContainsKey((faceEdge, 0)))
                    {
                        uvs.Add(faceEdge.GetUv(0));
                        hasTexture = true;
                    }
                    positions.Add(faceEdge.FirstVertex.Position);
                }

                // We should use the tessellator for this if it is greater than 3.
                Vector3 next   = positions[1];
                Vector2 nextuv = hasTexture ? uvs[1] : Vector2.Zero;
                for (int positionIndex = 2; positionIndex < positions.Count; positionIndex++)
                {
                    TriangleShape triangel;
                    if (hasTexture)
                    {
                        triangel = new TriangleShapeUv(positions[0], next, positions[positionIndex],
                                                       uvs[0], nextuv, uvs[positionIndex], null);
                    }
                    else
                    {
                        triangel = new TriangleShape(positions[0], next, positions[positionIndex], null);
                    }
                    allPolys.Add(triangel);
                    next = positions[positionIndex];
                }
            }

            return(BoundingVolumeHierarchy.CreateNewHierachy(allPolys, maxRecursion));
        }
예제 #28
0
            public void Execute(int index)
            {
                // This is need since we schedule the job before we know the exact number of
                // branches we need to build.
                if (index >= BranchCount[0])
                {
                    return;
                }

                Assert.IsTrue(BranchNodeOffsets[index] >= 0);
                var bvh      = new BoundingVolumeHierarchy(Nodes, NodeFilters);
                int lastNode = bvh.BuildBranch(Points, Aabbs, Ranges[index], BranchNodeOffsets[index]);

                if (NodeFilters != null)
                {
                    bvh.BuildCombinedCollisionFilter(BodyFilters, BranchNodeOffsets[index], lastNode);
                    bvh.BuildCombinedCollisionFilter(Ranges[index].Root);
                }
            }
예제 #29
0
            public void Execute()
            {
                int minBranchNodeIndex = BranchNodeOffsets[0] - 1;
                int branchCount        = BranchCount[0];

                for (int i = 1; i < BranchCount[0]; i++)
                {
                    minBranchNodeIndex = math.min(BranchNodeOffsets[i] - 1, minBranchNodeIndex);
                }

                var bvh = new BoundingVolumeHierarchy(Nodes, NodeFilters);

                bvh.Refit(Aabbs, 1, minBranchNodeIndex);

                if (NodeFilters != null)
                {
                    bvh.BuildCombinedCollisionFilter(LeafFilters, 1, minBranchNodeIndex);
                }
            }
        private bool FindInteractionVolumeHit(Ray ray, out int interactionVolumeHitIndex, out IntersectInfo info)
        {
            interactionVolumeHitIndex = -1;
            if (interactionVolumes.Count == 0 || interactionVolumes[0].CollisionVolume == null)
            {
                info = null;
                return(false);
            }

            // TODO: Rewrite as projection without extra list
            List <IPrimitive> uiTraceables = new List <IPrimitive>();

            foreach (InteractionVolume interactionVolume in interactionVolumes)
            {
                if (interactionVolume.CollisionVolume != null)
                {
                    IPrimitive traceData = interactionVolume.CollisionVolume;
                    uiTraceables.Add(new Transform(traceData, interactionVolume.TotalTransform));
                }
            }

            IPrimitive allUiObjects = BoundingVolumeHierarchy.CreateNewHierachy(uiTraceables);

            info = allUiObjects.GetClosestIntersection(ray);
            if (info != null)
            {
                for (int i = 0; i < interactionVolumes.Count; i++)
                {
                    List <IBvhItem> insideBounds = new List <IBvhItem>();
                    if (interactionVolumes[i].CollisionVolume != null)
                    {
                        interactionVolumes[i].CollisionVolume.GetContained(insideBounds, info.closestHitObject.GetAxisAlignedBoundingBox());
                        if (insideBounds.Contains(info.closestHitObject))
                        {
                            interactionVolumeHitIndex = i;
                            return(true);
                        }
                    }
                }
            }

            return(false);
        }