Ejemplo n.º 1
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="desiredDepth"></param>
        private bool LoadFromFile(string filename, int desiredDepth)
        {
            var array = File.ReadAllBytes(filename);

            var index = 0;
            var depth = BitConverter.ToInt32(array, index);

            index += sizeof(int);

            if (depth < desiredDepth)
            {
                return(false);
            }

            maxDepth = depth;

            Log.Instance.AddMsg(LogLevel.Info, string.Format("Loading VoxelOctree from '{0}.octree' ...", filename));

            voxelSizeThreshold = BitConverter.ToSingle(array, index);
            index += sizeof(float);

            RootCell = new AACell(array, index);
            index   += AACell.SizeOf;

            RootNode = new OctreeNode(array, index);
            index   += OctreeNode.SizeOf;

            LoadNodes(array, index, RootNode);

            return(true);
        }
Ejemplo n.º 2
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;
 }
Ejemplo n.º 3
0
 public OmniLight(float radius)
 {
     BoundingBox = new AACell {
         Min = new Vector3(-radius), Max = new Vector3(radius)
     };
     Color = new ColorRGB {
         R = 1f, G = 1f, B = 1f
     };
     Intensity = 1f;
 }
Ejemplo n.º 4
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);
        }
Ejemplo n.º 5
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);
        }
Ejemplo n.º 6
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="ray"></param>
        /// <param name="node"></param>
        /// <param name="maxDepth"></param>
        /// <returns></returns>
        private static IntersectionResult RayAndVoxelNode(Ray ray, OctreeNode node, AACell cell, int maxDepth, ref Vector3 normal)
        {
            var intersectionResult = new IntersectionResult
            {
                Voxel = node.Voxel,
                Point = cell.Center
            };

            if (!Collision.RayAndAACell(ray, cell))
            {
                return(intersectionResult);
            }

            var nodeInfo = node.Info;

            if (nodeInfo == OctreeNodeInfo.Empty || maxDepth == 0)
            {
                intersectionResult.Distance = Intersection.RayAndAACell(ray, cell, ref normal);
                return(intersectionResult);
            }

            var resultNormal = normal;

            maxDepth--;

            #region check child nodes for intersection

            var cellHalfSize    = cell.Size.X * .5f;
            var cellCenter      = cell.Center;
            var nextChildNodeId = 0;
            var childCell       = cell;

            #region 000

            if (nodeInfo.HasFlag(OctreeNodeInfo.x0y0z0))
            {
                childCell     = cell;
                childCell.Max = cellCenter;

                var tmpResult = RayAndVoxelNode(ray, node.OctreeNodes[nextChildNodeId], childCell, maxDepth, ref normal);
                if (tmpResult.Distance < intersectionResult.Distance)
                {
                    resultNormal       = normal;
                    intersectionResult = tmpResult;
                }

                nextChildNodeId++;
            }

            #endregion

            #region 100

            if (nodeInfo.HasFlag(OctreeNodeInfo.x1y0z0))
            {
                childCell        = cell;
                childCell.Max    = cellCenter;
                childCell.Min.X += cellHalfSize;
                childCell.Max.X += cellHalfSize;

                var tmpResult = RayAndVoxelNode(ray, node.OctreeNodes[nextChildNodeId], childCell, maxDepth, ref normal);
                if (tmpResult.Distance < intersectionResult.Distance)
                {
                    resultNormal       = normal;
                    intersectionResult = tmpResult;
                }

                nextChildNodeId++;
            }

            #endregion

            #region 110

            if (nodeInfo.HasFlag(OctreeNodeInfo.x1y1z0))
            {
                childCell        = cell;
                childCell.Min    = cellCenter;
                childCell.Min.Z -= cellHalfSize;
                childCell.Max.Z -= cellHalfSize;

                var tmpResult = RayAndVoxelNode(ray, node.OctreeNodes[nextChildNodeId], childCell, maxDepth, ref normal);
                if (tmpResult.Distance < intersectionResult.Distance)
                {
                    resultNormal       = normal;
                    intersectionResult = tmpResult;
                }

                nextChildNodeId++;
            }

            #endregion

            #region 010

            if (nodeInfo.HasFlag(OctreeNodeInfo.x0y1z0))
            {
                childCell        = cell;
                childCell.Max    = cellCenter;
                childCell.Min.Y += cellHalfSize;
                childCell.Max.Y += cellHalfSize;

                var tmpResult = RayAndVoxelNode(ray, node.OctreeNodes[nextChildNodeId], childCell, maxDepth, ref normal);
                if (tmpResult.Distance < intersectionResult.Distance)
                {
                    resultNormal       = normal;
                    intersectionResult = tmpResult;
                }

                nextChildNodeId++;
            }

            #endregion


            #region 001

            if (nodeInfo.HasFlag(OctreeNodeInfo.x0y0z1))
            {
                childCell        = cell;
                childCell.Max    = cellCenter;
                childCell.Min.Z += cellHalfSize;
                childCell.Max.Z += cellHalfSize;

                var tmpResult = RayAndVoxelNode(ray, node.OctreeNodes[nextChildNodeId], childCell, maxDepth, ref normal);
                if (tmpResult.Distance < intersectionResult.Distance)
                {
                    resultNormal       = normal;
                    intersectionResult = tmpResult;
                }

                nextChildNodeId++;
            }

            #endregion

            #region 101

            if (nodeInfo.HasFlag(OctreeNodeInfo.x1y0z1))
            {
                childCell        = cell;
                childCell.Min    = cellCenter;
                childCell.Min.Y -= cellHalfSize;
                childCell.Max.Y -= cellHalfSize;

                var tmpResult = RayAndVoxelNode(ray, node.OctreeNodes[nextChildNodeId], childCell, maxDepth, ref normal);
                if (tmpResult.Distance < intersectionResult.Distance)
                {
                    resultNormal       = normal;
                    intersectionResult = tmpResult;
                }

                nextChildNodeId++;
            }

            #endregion

            #region 111

            if (nodeInfo.HasFlag(OctreeNodeInfo.x1y1z1))
            {
                childCell     = cell;
                childCell.Min = cellCenter;

                var tmpResult = RayAndVoxelNode(ray, node.OctreeNodes[nextChildNodeId], childCell, maxDepth, ref normal);
                if (tmpResult.Distance < intersectionResult.Distance)
                {
                    resultNormal       = normal;
                    intersectionResult = tmpResult;
                }

                nextChildNodeId++;
            }

            #endregion

            #region 011

            if (nodeInfo.HasFlag(OctreeNodeInfo.x0y1z1))
            {
                childCell        = cell;
                childCell.Min    = cellCenter;
                childCell.Min.X -= cellHalfSize;
                childCell.Max.X -= cellHalfSize;

                var tmpResult = RayAndVoxelNode(ray, node.OctreeNodes[nextChildNodeId], childCell, maxDepth, ref normal);
                if (tmpResult.Distance < intersectionResult.Distance)
                {
                    resultNormal       = normal;
                    intersectionResult = tmpResult;
                }

                nextChildNodeId++;
            }

            #endregion

            #endregion

            if (intersectionResult.Distance < float.MaxValue)
            {
                normal = resultNormal;
            }

            return(intersectionResult);
        }
Ejemplo n.º 7
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="ray"></param>
        /// <param name="cell"></param>
        /// <param name="normal"></param>
        /// <returns></returns>
        private static float RayAndAACell(Ray ray, AACell cell, ref Vector3 normal)
        {
            var tMin = float.MaxValue;

            // ray from outside
            if (!Collision.PointInAACell(ray.Origin, cell))
            {
                #region --> cell.Min.X, cell.Max.X <--

                if (ray.Origin.X <= cell.Min.X)
                {
                    var t = Intersection.RayAndPlane(ray, Vector3.UnitXNegative, System.Math.Abs(cell.Min.X));
                    if (t < tMin)
                    {
                        var hit = ray.Origin.Y + ray.Direction.Y * t;
                        if (hit >= cell.Min.Y && hit <= cell.Max.Y)
                        {
                            hit = ray.Origin.Z + ray.Direction.Z * t;
                            if (hit >= cell.Min.Z && hit <= cell.Max.Z)
                            {
                                tMin   = t;
                                normal = Vector3.UnitXNegative;
                            }
                        }
                    }
                }
                else if (ray.Origin.X >= cell.Max.X)
                {
                    var t = Intersection.RayAndPlane(ray, Vector3.UnitX, System.Math.Abs(cell.Max.X));
                    if (t < tMin)
                    {
                        var hit = ray.Origin.Y + ray.Direction.Y * t;
                        if (hit >= cell.Min.Y && hit <= cell.Max.Y)
                        {
                            hit = ray.Origin.Z + ray.Direction.Z * t;
                            if (hit >= cell.Min.Z && hit <= cell.Max.Z)
                            {
                                tMin   = t;
                                normal = Vector3.UnitX;
                            }
                        }
                    }
                }

                #endregion

                #region --> cell.Min.Y, cell.Max.Y <--

                if (ray.Origin.Y <= cell.Min.Y)
                {
                    var t = Intersection.RayAndPlane(ray, Vector3.UnitYNegative, System.Math.Abs(cell.Min.Y));
                    if (t < tMin)
                    {
                        var hit = ray.Origin.X + ray.Direction.X * t;
                        if (hit > cell.Min.X && hit < cell.Max.X)
                        {
                            hit = ray.Origin.Z + ray.Direction.Z * t;
                            if (hit > cell.Min.Z && hit < cell.Max.Z)
                            {
                                tMin   = t;
                                normal = Vector3.UnitYNegative;
                            }
                        }
                    }
                }
                else if (ray.Origin.Y >= cell.Max.Y)
                {
                    var t = Intersection.RayAndPlane(ray, Vector3.UnitY, System.Math.Abs(cell.Max.Y));
                    if (t < tMin)
                    {
                        var hit = ray.Origin.X + ray.Direction.X * t;
                        if (hit > cell.Min.X && hit < cell.Max.X)
                        {
                            hit = ray.Origin.Z + ray.Direction.Z * t;
                            if (hit > cell.Min.Z && hit < cell.Max.Z)
                            {
                                tMin   = t;
                                normal = Vector3.UnitY;
                            }
                        }
                    }
                }

                #endregion

                #region --> cell.Min.Z, cell.Max.Z <--

                if (ray.Origin.Z <= cell.Min.Z)
                {
                    var t = Intersection.RayAndPlane(ray, Vector3.UnitZNegative, System.Math.Abs(cell.Min.Z));
                    if (t < tMin)
                    {
                        var hit = ray.Origin.X + ray.Direction.X * t;
                        if (hit > cell.Min.X && hit < cell.Max.X)
                        {
                            hit = ray.Origin.Y + ray.Direction.Y * t;
                            if (hit > cell.Min.Y && hit < cell.Max.Y)
                            {
                                tMin   = t;
                                normal = Vector3.UnitZNegative;
                            }
                        }
                    }
                }
                else if (ray.Origin.Z >= cell.Max.Z)
                {
                    var t = Intersection.RayAndPlane(ray, Vector3.UnitZ, System.Math.Abs(cell.Max.Z));
                    if (t < tMin)
                    {
                        var hit = ray.Origin.X + ray.Direction.X * t;
                        if (hit > cell.Min.X && hit < cell.Max.X)
                        {
                            hit = ray.Origin.Y + ray.Direction.Y * t;
                            if (hit > cell.Min.Y && hit < cell.Max.Y)
                            {
                                tMin   = t;
                                normal = Vector3.UnitZ;
                            }
                        }
                    }
                }

                #endregion
            }

            // ray from inside
            else
            {
                #region cell.Min.X <-- --> cell.Max.X

                if (ray.Direction.X > 0f)
                {
                    var t = Intersection.RayAndPlane(ray, Vector3.UnitX, cell.Max.X);

                    if (t < tMin)
                    {
                        var hit = ray.Origin.Y + ray.Direction.Y * t;
                        if (hit > cell.Min.Y && hit < cell.Max.Y)
                        {
                            hit = ray.Origin.Z + ray.Direction.Z * t;
                            if (hit > cell.Min.Z && hit < cell.Max.Z)
                            {
                                tMin   = t;
                                normal = Vector3.UnitXNegative;
                            }
                        }
                    }
                }
                else
                {
                    var t = Intersection.RayAndPlane(ray, Vector3.UnitXNegative, cell.Min.X);

                    if (t < tMin)
                    {
                        var hit = ray.Origin.Y + ray.Direction.Y * t;
                        if (hit > cell.Min.Y && hit < cell.Max.Y)
                        {
                            hit = ray.Origin.Z + ray.Direction.Z * t;
                            if (hit > cell.Min.Z && hit < cell.Max.Z)
                            {
                                tMin   = t;
                                normal = Vector3.UnitX;
                            }
                        }
                    }
                }

                #endregion

                #region cell.Min.Y <-- --> cell.Max.Y

                if (ray.Direction.Y > 0)
                {
                    var t = Intersection.RayAndPlane(ray, Vector3.UnitY, cell.Max.Y);

                    if (t < tMin)
                    {
                        var hit = ray.Origin.X + ray.Direction.X * t;
                        if (hit > cell.Min.X && hit < cell.Max.X)
                        {
                            hit = ray.Origin.Z + ray.Direction.Z * t;
                            if (hit > cell.Min.Z && hit < cell.Max.Z)
                            {
                                tMin   = t;
                                normal = Vector3.UnitYNegative;
                            }
                        }
                    }
                }
                else
                {
                    var t = Intersection.RayAndPlane(ray, Vector3.UnitYNegative, cell.Min.Y);

                    if (t < tMin)
                    {
                        var hit = ray.Origin.X + ray.Direction.X * t;
                        if (hit > cell.Min.X && hit < cell.Max.X)
                        {
                            hit = ray.Origin.Z + ray.Direction.Z * t;
                            if (hit > cell.Min.Z && hit < cell.Max.Z)
                            {
                                tMin   = t;
                                normal = Vector3.UnitY;
                            }
                        }
                    }
                }

                #endregion

                #region cell.Min.Z <-- --> cell.Max.Z

                if (ray.Direction.Z > 0)
                {
                    var t = Intersection.RayAndPlane(ray, Vector3.UnitZ, cell.Max.Z);

                    if (t < tMin)
                    {
                        var hit = ray.Origin.X + ray.Direction.X * t;
                        if (hit > cell.Min.X && hit < cell.Max.X)
                        {
                            hit = ray.Origin.Y + ray.Direction.Y * t;
                            if (hit > cell.Min.Y && hit < cell.Max.Y)
                            {
                                tMin   = t;
                                normal = Vector3.UnitZNegative;
                            }
                        }
                    }
                }
                else
                {
                    var t = Intersection.RayAndPlane(ray, Vector3.UnitZNegative, cell.Min.Z);

                    if (t < tMin)
                    {
                        var hit = ray.Origin.X + ray.Direction.X * t;
                        if (hit > cell.Min.X && hit < cell.Max.X)
                        {
                            hit = ray.Origin.Y + ray.Direction.Y * t;
                            if (hit > cell.Min.Y && hit < cell.Max.Y)
                            {
                                tMin   = t;
                                normal = Vector3.UnitZ;
                            }
                        }
                    }
                }
                #endregion
            }

            return(tMin);
        }
Ejemplo n.º 8
0
        /// <summary>
        ///
        /// </summary>
        private void LoadFromFile(string objFilename)
        {
            Filename = objFilename;

            // TODO read material file *.mtl

            var lines = File.ReadAllLines(objFilename);

            var timer = new HighPerformanceTimer();

            timer.Start();

            var min = new Vector3(float.MaxValue);
            var max = new Vector3(float.MinValue);

            for (var i = 0; i < lines.Length; i++)
            {
                var line = lines[i];

                try
                {
                    if (line.StartsWith("# object"))
                    {
                        if (string.IsNullOrEmpty(Name))
                        {
                            Name = line.Substring("# object ".Length);
                        }
                    }

                    // vertex
                    else if (line.StartsWith("v "))
                    {
                        var parts  = line.Substring("v  ".Length).Replace('.', ',').Split(' ');
                        var vertex = new Vector3(float.Parse(parts[0], System.Globalization.NumberStyles.Float), float.Parse(parts[1]), float.Parse(parts[2]));

                        if (vertex.X < min.X)
                        {
                            min.X = vertex.X;
                        }

                        if (vertex.Y < min.Y)
                        {
                            min.Y = vertex.Y;
                        }

                        if (vertex.Z < min.Z)
                        {
                            min.Z = vertex.Z;
                        }

                        if (vertex.X > max.X)
                        {
                            max.X = vertex.X;
                        }

                        if (vertex.Y > max.Y)
                        {
                            max.Y = vertex.Y;
                        }

                        if (vertex.Z > max.Z)
                        {
                            max.Z = vertex.Z;
                        }

                        Vertices.Add(vertex);
                    }

                    // vertex normal
                    else if (line.StartsWith("vn "))
                    {
                        var parts = line.Substring("vn ".Length).Replace('.', ',').Split(' ');
                        Normals.Add(new Vector3(float.Parse(parts[0]), float.Parse(parts[1]), float.Parse(parts[2])));
                    }

                    // vertex texture coordinates
                    else if (line.StartsWith("vt "))
                    {
                        var parts = line.Substring("vt ".Length).Replace('.', ',').Split(' ');
                        TextureCoords.Add(new Vector2(float.Parse(parts[0]), float.Parse(parts[1])));
                    }

                    // face indices
                    else if (line.StartsWith("f "))
                    {
                        var parts   = line.Substring("f ".Length).Split(' ');
                        var v1Parts = parts[0].Split('/');
                        var v2Parts = parts[1].Split('/');
                        var v3Parts = parts[2].Split('/');

                        Faces.Add(
                            new Face(
                                this,
                                int.Parse(v1Parts[0]) - 1, int.Parse(v2Parts[0]) - 1, int.Parse(v3Parts[0]) - 1,
                                int.Parse(v1Parts[1]) - 1, int.Parse(v2Parts[1]) - 1, int.Parse(v3Parts[1]) - 1,
                                int.Parse(v1Parts[2]) - 1, int.Parse(v2Parts[2]) - 1, int.Parse(v3Parts[2]) - 1
                                )
                            );
                    }
                }
                catch (Exception ex)
                {
                    throw new Exception(string.Format("ObjImporter failed at line='{0}'", line), ex);
                }
            }

            BoundingBox = new AACell {
                Min = min, Max = max
            };

            timer.Stop();

            Log.Instance.AddMsg(LogLevel.Info, string.Format("WavefrontObjMesh '{0}' [vertices: {1}; faces: {2}; size: {3}] loaded in {4}", Name, Vertices.Count, Faces.Count, BoundingBox.Size.ToString(), FormatString.GetDuration((int)timer.Duration)));
        }
Ejemplo n.º 9
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="terrainSize"></param>
        /// <param name="maxTerrainHeight"></param>
        /// <param name="heightMap"></param>
        /// <param name="textureMap"></param>
        /// <returns></returns>
        public void CreateFromHeightMap(float terrainSize, float maxTerrainHeight, float[] heightMap, ColorRGB[] textureMap)
        {
            var heightMapSize = (int)System.Math.Sqrt(heightMap.Length);
            var triangleSize  = terrainSize / heightMapSize;

            var mapIndex         = 0;
            var terrainSizeLimit = terrainSize * .5f;
            var actualMaxHeight  = 0f;

            // if no texture map is specified, color of vertex height is used
            if (textureMap == null)
            {
                textureMap = new ColorRGB[heightMap.Length];
                for (var i = 0; i < heightMap.Length; i++)
                {
                    textureMap[i] = new ColorRGB(heightMap[i]);
                }
            }

            #region generate vertices

            for (var z = -terrainSizeLimit + triangleSize * .5f; z < terrainSizeLimit; z += triangleSize)
            {
                for (var x = -terrainSizeLimit + triangleSize * .5f; x < terrainSizeLimit; x += triangleSize, mapIndex++)
                {
                    var vertexHeight = heightMap[mapIndex] * maxTerrainHeight;
                    if (vertexHeight > actualMaxHeight)
                    {
                        actualMaxHeight = vertexHeight;
                    }

                    Vertices.Add(new Vector3(x, vertexHeight, z));
                }
            }

            #endregion

            // set bounding box (center will be at [0,0,0]
            actualMaxHeight *= .5f;
            BoundingBox      = new AACell
            {
                Min = new Vector3(-terrainSizeLimit + triangleSize * .5f, -actualMaxHeight, -terrainSizeLimit + triangleSize * .5f),
                Max = new Vector3(terrainSizeLimit - triangleSize * .5f, actualMaxHeight, terrainSizeLimit - triangleSize * .5f)
            };

            // update vertex heights(Y) (so bounding box center will be at [0,0,0])
            for (var i = 0; i < Vertices.Count; i++)
            {
                var vertex = Vertices[i];
                vertex.Y   -= actualMaxHeight;
                Vertices[i] = vertex;
            }

            #region generate faces

            for (var y = 0; y < heightMapSize - 1; y++)
            {
                for (var x = 0; x < heightMapSize - 1; x++)
                {
                    var lowerLeft  = x + y * heightMapSize;
                    var lowerRight = (x + 1) + y * heightMapSize;
                    var topLeft    = x + (y + 1) * heightMapSize;
                    var topRight   = (x + 1) + (y + 1) * heightMapSize;

                    Faces.Add(new Face(this, topLeft, lowerRight, lowerLeft, -1, -1, -1, -1, -1, -1));
                    Faces.Add(new Face(this, topLeft, topRight, lowerRight, -1, -1, -1, -1, -1, -1));
                }
            }

            #endregion
        }
Ejemplo n.º 10
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();
            }
        }
Ejemplo n.º 11
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();
            }
        }