Пример #1
0
 /// <summary>
 ///
 /// </summary>
 /// <param name="obj"></param>
 /// <param name="nodeCell"></param>
 /// <param name="node"></param>
 /// <param name="processFinishedEvent"></param>
 public ProessNodeInfo(IVoxelizable obj, AACell nodeCell, OctreeNode node, CountdownEvent processFinishedEvent)
 {
     Obj                  = obj;
     NodeCell             = nodeCell;
     Node                 = node;
     ProcessFinishedEvent = processFinishedEvent;
 }
Пример #2
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="nodeCell"></param>
        /// <returns></returns>
        private static bool IsNodeEmpty(IVoxelizable obj, AACell nodeCell)
        {
            if (obj is Mesh)
            {
                var faces = (obj as Mesh).Faces;
                foreach (var face in faces)
                {
                    if (Collision.AACellAndFace(nodeCell, face))
                    {
                        return(false);
                    }
                }
            }

            else if (obj is Sphere)
            {
                return(!Collision.AACellAndSphere(nodeCell, (obj as Sphere).Radius));
            }

            return(true);
        }
Пример #3
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="nodeCell"></param>
        /// <returns></returns>
        private static Voxel GetVoxel(IVoxelizable obj, AACell nodeCell)
        {
            // TODO get color/normal/material of voxel at collision point

            //var color = new ColorRGB((int)DateTime.Now.Ticks);
            var color = new ColorRGB((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble());

            var voxel = new Voxel(color, Vector3.Zero);

            if (obj is Sphere)
            {
                voxel.Normal = nodeCell.Center.Normalize();
            }
            else
            {
                // temporary, not accurate!
                voxel.Normal = nodeCell.Center.Normalize();
            }

            return(voxel);
        }
Пример #4
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="nodeCell"></param>
        /// <param name="node"></param>
        /// <returns></returns>
        private void ProcessNodeMultithreaded(IVoxelizable obj, AACell nodeCell, OctreeNode node)
        {
            var center        = nodeCell.Center;
            var childNodeSize = (nodeCell.Max.X - nodeCell.Min.X) * .5f;

            var nodeInfo = OctreeNodeInfo.Empty;

            var childCell = nodeCell;

            if (childNodeSize > voxelSizeThreshold && maxDepth > 0)
            {
                #region check child nodes

                // xyz
                childCell.Max = center;
                if (!IsNodeEmpty(obj, childCell))
                {
                    nodeInfo |= OctreeNodeInfo.x0y0z0;
                }

                // Xyz
                childCell.Min.X += childNodeSize;
                childCell.Max.X += childNodeSize;
                if (!IsNodeEmpty(obj, childCell))
                {
                    nodeInfo |= OctreeNodeInfo.x1y0z0;
                }

                // XYz
                childCell.Min.Y += childNodeSize;
                childCell.Max.Y += childNodeSize;
                if (!IsNodeEmpty(obj, childCell))
                {
                    nodeInfo |= OctreeNodeInfo.x1y1z0;
                }

                // xYz
                childCell.Min.X -= childNodeSize;
                childCell.Max.X -= childNodeSize;
                if (!IsNodeEmpty(obj, childCell))
                {
                    nodeInfo |= OctreeNodeInfo.x0y1z0;
                }

                // xyZ
                childCell.Min.Y -= childNodeSize;
                childCell.Max.Y -= childNodeSize;
                childCell.Min.Z += childNodeSize;
                childCell.Max.Z += childNodeSize;
                if (!IsNodeEmpty(obj, childCell))
                {
                    nodeInfo |= OctreeNodeInfo.x0y0z1;
                }

                // XyZ
                childCell.Min.X += childNodeSize;
                childCell.Max.X += childNodeSize;
                if (!IsNodeEmpty(obj, childCell))
                {
                    nodeInfo |= OctreeNodeInfo.x1y0z1;
                }

                // XYZ
                childCell.Min.Y += childNodeSize;
                childCell.Max.Y += childNodeSize;
                if (!IsNodeEmpty(obj, childCell))
                {
                    nodeInfo |= OctreeNodeInfo.x1y1z1;
                }

                // xYZ
                childCell.Min.X -= childNodeSize;
                childCell.Max.X -= childNodeSize;
                if (!IsNodeEmpty(obj, childCell))
                {
                    nodeInfo |= OctreeNodeInfo.x0y1z1;
                }

                #endregion
            }

            node.Info = nodeInfo;
            if (nodeInfo == OctreeNodeInfo.Empty)
            {
                node.Voxel = GetVoxel(obj, nodeCell);
            }
            else
            {
                var childNodes             = new OctreeNode[8];
                var childNodesProcessEvent = new CountdownEvent(8);

                #region process child nodes

                // xyz
                childCell.Min = nodeCell.Min;
                childCell.Max = center;
                if (nodeInfo.HasFlag(OctreeNodeInfo.x0y0z0))
                {
                    childNodes[0] = new OctreeNode();
                    ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessNodeOnThread), new ProessNodeInfo(obj, childCell, childNodes[0], childNodesProcessEvent));
                }

                // Xyz
                childCell.Min.X += childNodeSize;
                childCell.Max.X += childNodeSize;
                if (nodeInfo.HasFlag(OctreeNodeInfo.x1y0z0))
                {
                    childNodes[1] = new OctreeNode();
                    ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessNodeOnThread), new ProessNodeInfo(obj, childCell, childNodes[1], childNodesProcessEvent));
                }

                // XYz
                childCell.Min.Y += childNodeSize;
                childCell.Max.Y += childNodeSize;
                if (nodeInfo.HasFlag(OctreeNodeInfo.x1y1z0))
                {
                    childNodes[2] = new OctreeNode();
                    ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessNodeOnThread), new ProessNodeInfo(obj, childCell, childNodes[2], childNodesProcessEvent));
                }

                // xYz
                childCell.Min.X -= childNodeSize;
                childCell.Max.X -= childNodeSize;
                if (nodeInfo.HasFlag(OctreeNodeInfo.x0y1z0))
                {
                    childNodes[3] = new OctreeNode();
                    ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessNodeOnThread), new ProessNodeInfo(obj, childCell, childNodes[3], childNodesProcessEvent));
                }

                // xyZ
                childCell.Min.Y -= childNodeSize;
                childCell.Max.Y -= childNodeSize;
                childCell.Min.Z += childNodeSize;
                childCell.Max.Z += childNodeSize;
                if (nodeInfo.HasFlag(OctreeNodeInfo.x0y0z1))
                {
                    childNodes[4] = new OctreeNode();
                    ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessNodeOnThread), new ProessNodeInfo(obj, childCell, childNodes[4], childNodesProcessEvent));
                }

                // XyZ
                childCell.Min.X += childNodeSize;
                childCell.Max.X += childNodeSize;
                if (nodeInfo.HasFlag(OctreeNodeInfo.x1y0z1))
                {
                    childNodes[5] = new OctreeNode();
                    ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessNodeOnThread), new ProessNodeInfo(obj, childCell, childNodes[5], childNodesProcessEvent));
                }

                // XYZ
                childCell.Min.Y += childNodeSize;
                childCell.Max.Y += childNodeSize;
                if (nodeInfo.HasFlag(OctreeNodeInfo.x1y1z1))
                {
                    childNodes[6] = new OctreeNode();
                    ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessNodeOnThread), new ProessNodeInfo(obj, childCell, childNodes[6], childNodesProcessEvent));
                }

                // xYZ
                childCell.Min.X -= childNodeSize;
                childCell.Max.X -= childNodeSize;
                if (nodeInfo.HasFlag(OctreeNodeInfo.x0y1z1))
                {
                    childNodes[7] = new OctreeNode();
                    ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessNodeOnThread), new ProessNodeInfo(obj, childCell, childNodes[7], childNodesProcessEvent));
                }

                #endregion

                // wait for threads to end
                childNodesProcessEvent.Wait();

                node.OctreeNodes = (from n in childNodes where n != null select n).ToList();
                node.SetVoxelAsAverage();
            }
        }
Пример #5
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="mesh"></param>
        /// <param name="nodeCell"></param>
        /// <param name="node"></param>
        /// <returns></returns>
        private void ProcessNode(IVoxelizable obj, AACell nodeCell, OctreeNode node, int nodeDepth)
        {
            var center        = nodeCell.Center;
            var childNodeSize = (nodeCell.Max.X - nodeCell.Min.X) * .5f;

            var nodeInfo = OctreeNodeInfo.Empty;

            var childCell = nodeCell;

            if (childNodeSize > voxelSizeThreshold && maxDepth > nodeDepth)
            {
                #region check child nodes

                // xyz
                childCell.Max = center;
                if (!IsNodeEmpty(obj, childCell))
                {
                    nodeInfo |= OctreeNodeInfo.x0y0z0;
                }

                // Xyz
                childCell.Min.X += childNodeSize;
                childCell.Max.X += childNodeSize;
                if (!IsNodeEmpty(obj, childCell))
                {
                    nodeInfo |= OctreeNodeInfo.x1y0z0;
                }

                // XYz
                childCell.Min.Y += childNodeSize;
                childCell.Max.Y += childNodeSize;
                if (!IsNodeEmpty(obj, childCell))
                {
                    nodeInfo |= OctreeNodeInfo.x1y1z0;
                }

                // xYz
                childCell.Min.X -= childNodeSize;
                childCell.Max.X -= childNodeSize;
                if (!IsNodeEmpty(obj, childCell))
                {
                    nodeInfo |= OctreeNodeInfo.x0y1z0;
                }

                // xyZ
                childCell.Min.Y -= childNodeSize;
                childCell.Max.Y -= childNodeSize;
                childCell.Min.Z += childNodeSize;
                childCell.Max.Z += childNodeSize;
                if (!IsNodeEmpty(obj, childCell))
                {
                    nodeInfo |= OctreeNodeInfo.x0y0z1;
                }

                // XyZ
                childCell.Min.X += childNodeSize;
                childCell.Max.X += childNodeSize;
                if (!IsNodeEmpty(obj, childCell))
                {
                    nodeInfo |= OctreeNodeInfo.x1y0z1;
                }

                // XYZ
                childCell.Min.Y += childNodeSize;
                childCell.Max.Y += childNodeSize;
                if (!IsNodeEmpty(obj, childCell))
                {
                    nodeInfo |= OctreeNodeInfo.x1y1z1;
                }

                // xYZ
                childCell.Min.X -= childNodeSize;
                childCell.Max.X -= childNodeSize;
                if (!IsNodeEmpty(obj, childCell))
                {
                    nodeInfo |= OctreeNodeInfo.x0y1z1;
                }

                #endregion
            }

            node.Info = nodeInfo;
            if (nodeInfo == OctreeNodeInfo.Empty)
            {
                node.Voxel = GetVoxel(obj, nodeCell);
            }
            else
            {
                nodeDepth++;

                var childNodes = new OctreeNode[8];

                #region process child nodes

                // xyz
                childCell.Min = nodeCell.Min;
                childCell.Max = center;
                if (nodeInfo.HasFlag(OctreeNodeInfo.x0y0z0))
                {
                    childNodes[0] = new OctreeNode();
                    ProcessNode(obj, childCell, childNodes[0], nodeDepth);
                }

                // Xyz
                childCell.Min.X += childNodeSize;
                childCell.Max.X += childNodeSize;
                if (nodeInfo.HasFlag(OctreeNodeInfo.x1y0z0))
                {
                    childNodes[1] = new OctreeNode();
                    ProcessNode(obj, childCell, childNodes[1], nodeDepth);
                }

                // XYz
                childCell.Min.Y += childNodeSize;
                childCell.Max.Y += childNodeSize;
                if (nodeInfo.HasFlag(OctreeNodeInfo.x1y1z0))
                {
                    childNodes[2] = new OctreeNode();
                    ProcessNode(obj, childCell, childNodes[2], nodeDepth);
                }

                // xYz
                childCell.Min.X -= childNodeSize;
                childCell.Max.X -= childNodeSize;
                if (nodeInfo.HasFlag(OctreeNodeInfo.x0y1z0))
                {
                    childNodes[3] = new OctreeNode();
                    ProcessNode(obj, childCell, childNodes[3], nodeDepth);
                }

                // xyZ
                childCell.Min.Y -= childNodeSize;
                childCell.Max.Y -= childNodeSize;
                childCell.Min.Z += childNodeSize;
                childCell.Max.Z += childNodeSize;
                if (nodeInfo.HasFlag(OctreeNodeInfo.x0y0z1))
                {
                    childNodes[4] = new OctreeNode();
                    ProcessNode(obj, childCell, childNodes[4], nodeDepth);
                }

                // XyZ
                childCell.Min.X += childNodeSize;
                childCell.Max.X += childNodeSize;
                if (nodeInfo.HasFlag(OctreeNodeInfo.x1y0z1))
                {
                    childNodes[5] = new OctreeNode();
                    ProcessNode(obj, childCell, childNodes[5], nodeDepth);
                }

                // XYZ
                childCell.Min.Y += childNodeSize;
                childCell.Max.Y += childNodeSize;
                if (nodeInfo.HasFlag(OctreeNodeInfo.x1y1z1))
                {
                    childNodes[6] = new OctreeNode();
                    ProcessNode(obj, childCell, childNodes[6], nodeDepth);
                }

                // xYZ
                childCell.Min.X -= childNodeSize;
                childCell.Max.X -= childNodeSize;
                if (nodeInfo.HasFlag(OctreeNodeInfo.x0y1z1))
                {
                    childNodes[7] = new OctreeNode();
                    ProcessNode(obj, childCell, childNodes[7], nodeDepth);
                }

                #endregion

                node.OctreeNodes = (from n in childNodes where n != null select n).ToList();
                node.SetVoxelAsAverage();
            }
        }
Пример #6
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="maxDepth"></param>
        /// <param name="voxelSizeThreshold"></param>
        /// <returns></returns>
        public static VoxelOctree Create(IVoxelizable obj, int maxDepth, float voxelSizeThreshold)
        {
            var octree = new VoxelOctree(maxDepth, voxelSizeThreshold);

            var timer = new HighPerformanceTimer();

            timer.Start();

            var cellSize    = obj.BoundingBox.Size;
            var newCellSize = (cellSize.X > cellSize.Y ? (cellSize.X > cellSize.Z ? cellSize.X : cellSize.Z) : (cellSize.Y > cellSize.Z ? cellSize.Y : cellSize.Z)) * 0.5f;

            var generateNewOctree = true;

            if (obj is WavefrontObjMesh && File.Exists((obj as WavefrontObjMesh).Filename + ".octree"))
            {
                generateNewOctree = !octree.LoadFromFile((obj as WavefrontObjMesh).Filename + ".octree", maxDepth);
            }

            if (generateNewOctree)
            {
                #region calculate RootCell (equal edge sizes)

                var center = obj.BoundingBox.Center;
                octree.RootCell = new AACell {
                    Min = new Vector3(center.X - newCellSize, center.Y - newCellSize, center.Z - newCellSize), Max = new Vector3(center.X + newCellSize, center.Y + newCellSize, center.Z + newCellSize)
                };

                #endregion

                // create octree recursively
                octree.RootNode = new OctreeNode();

                if (VoxelOctree.GenerateOnMultipleThreads)
                {
                    Log.Instance.AddMsg(LogLevel.Info, string.Format("Generating VoxelOctree/MT [maxDepth: {0}; voxelSizeThreshold: {1}] ...", maxDepth, voxelSizeThreshold));
                    octree.ProcessNodeMultithreaded(obj, octree.RootCell, octree.RootNode);
                }
                else
                {
                    Log.Instance.AddMsg(LogLevel.Info, string.Format("Generating VoxelOctree/ST [maxDepth: {0}; voxelSizeThreshold: {1}] ...", maxDepth, voxelSizeThreshold));
                    octree.ProcessNode(obj, octree.RootCell, octree.RootNode, 0);
                }
            }

            timer.Stop();

            // count all nodes
            var nodeCount = CountNodesRecursive(octree.RootNode) + 1;

            // get actual tree depth
            octree.maxDepth = VoxelOctree.GetMaxDepth(octree.RootNode);

            #region calculate smallest voxel size

            var smallestVoxelSize = newCellSize * 2f;
            for (var i = 0; i < octree.maxDepth; i++)
            {
                smallestVoxelSize *= .5f;
            }

            #endregion

            Log.Instance.AddMsg(LogLevel.Info, string.Format("VoxelOctree [size: {0}; nodes: {1}; depth: {2}; voxelSize: {3}] generated in {4}", newCellSize * 2f, nodeCount, octree.maxDepth, smallestVoxelSize, FormatString.GetDuration((int)timer.Duration)));

            if (obj is WavefrontObjMesh && generateNewOctree)
            {
                octree.SaveToFile((obj as WavefrontObjMesh).Filename + ".octree");
            }

            return(octree);
        }