Example #1
0
        public VoxelizingOctreeCell(VoxelizingOctree tree, VoxelizingOctreeCell root, Vector3 center, float length, int level)
        {
            Tree   = tree;
            Root   = root;
            Center = center;
            Length = length;
            Level  = level;

            float half_length = length / 2.0f;

            Bounds      = new AABBf();
            Bounds.MinX = center.X - half_length;
            Bounds.MinY = center.Y - half_length;
            Bounds.MinZ = center.Z - half_length;
            Bounds.MaxX = center.X + half_length;
            Bounds.MaxY = center.Y + half_length;
            Bounds.MaxZ = center.Z + half_length;

            VoxelBounds = new AABBi(
                (int)Math.Round((Bounds.MinX - tree.VoxelBounds.MinX) / tree.SmallestVoxelSideLength, MidpointRounding.AwayFromZero),
                (int)Math.Round((Bounds.MinY - tree.VoxelBounds.MinY) / tree.SmallestVoxelSideLength, MidpointRounding.AwayFromZero),
                (int)Math.Round((Bounds.MinZ - tree.VoxelBounds.MinZ) / tree.SmallestVoxelSideLength, MidpointRounding.AwayFromZero),
                (int)Math.Round((Bounds.MaxX - tree.VoxelBounds.MinX) / tree.SmallestVoxelSideLength, MidpointRounding.AwayFromZero),
                (int)Math.Round((Bounds.MaxY - tree.VoxelBounds.MinY) / tree.SmallestVoxelSideLength, MidpointRounding.AwayFromZero),
                (int)Math.Round((Bounds.MaxZ - tree.VoxelBounds.MinZ) / tree.SmallestVoxelSideLength, MidpointRounding.AwayFromZero));
        }
Example #2
0
        // computes the OBB for this set of points relative to this transform matrix.
        public static void ComputeOBB(Vector3[] points, ref Matrix4 matrix, out float[] sides)
        {
            AABBf aabb = new AABBf();

            Matrix4 matrixInverse = matrix;

            matrixInverse.Invert();
            for (int i = 0; i < points.Length; i++)
            {
                Vector3 t = Vector3.Transform(points[i], matrixInverse); // inverse rotate translate
                aabb.Add(t);
            }

            sides    = new float[3];
            sides[0] = aabb.MaxX - aabb.MinX;
            sides[1] = aabb.MaxY - aabb.MinY;
            sides[2] = aabb.MaxZ - aabb.MinZ;

            Vector3 center = new Vector3();

            center.X = sides[0] * 0.5f + aabb.MinX;
            center.Y = sides[1] * 0.5f + aabb.MinY;
            center.Z = sides[2] * 0.5f + aabb.MinZ;

            Vector3 ocenter = Vector3.Transform(center, matrix);

            matrix = matrix * Matrix4.CreateTranslation(ocenter);
        }
Example #3
0
        public static Mesh BuildMesh(List <AABBf> boxList)
        {
            Mesh mesh = new Mesh();

            if (boxList.Count == 0)
            {
                mesh.Vertices = new Vector4[0];
                mesh.Indicies = new int[0];
                return(mesh);
            }

            List <CSGNode> nodes = new List <CSGNode>();

            for (int i = 0; i < boxList.Count; i++)
            {
                AABBf   box  = boxList[i];
                CSGNode node = new CSGNode(new Plane[] {
                    new Plane(0, -1, 0, 0),
                    new Plane(-1, 0, 0, 0),
                    new Plane(0, 0, -1, 0),
                    new Plane(0, 0, 1, box.MaxZ - box.MinZ),
                    new Plane(1, 0, 0, box.MaxX - box.MinX),
                    new Plane(0, 1, 0, box.MaxY - box.MinY)
                });
                node.Translation = new Vector3(box.MinX, box.MinY, box.MinZ);

                nodes.Add(node);
            }

            return(BuildMesh(nodes));
        }
Example #4
0
 public bool Intersects(AABBf other)
 {
     return
         ((MaxX > other.MinX && MaxX < other.MaxX) ||
          (MinX > other.MinX && MinX < other.MaxX) ||
          (MaxY > other.MinY && MaxY < other.MaxY) ||
          (MinY > other.MinY && MinY < other.MaxY) ||
          (MaxZ > other.MinZ && MaxZ < other.MaxZ) ||
          (MinZ > other.MinZ && MinZ < other.MaxZ));
 }
Example #5
0
        public void ComputeCoverage(RenderableMesh mesh, AABBf meshBounds, out long sideCoverage, out long topCoverage)
        {
            float longestSide = Math.Max(Math.Max(meshBounds.MaxX - meshBounds.MinX, meshBounds.MaxY - meshBounds.MinY), meshBounds.MaxZ - meshBounds.MinZ);
            float farPlane    = longestSide * 2.0f;

            float   x      = (meshBounds.MinX + meshBounds.MaxX) / 2.0f;
            float   y      = meshBounds.MinY;
            float   z      = (meshBounds.MinZ + meshBounds.MaxZ) / 2.0f;
            Vector3 origin = new Vector3(x, y, z);
            Vector3 up     = Vector3.UnitY;
            Vector3 look   = -Vector3.UnitX;

            for (int i = 0; i < m_occlusionQueries.Length; i++)
            {
                Matrix4 orbit = Matrix4.CreateRotationY(MathHelper.DegreesToRadians((365 / 64.0f) * i));

                Matrix4 projection = Matrix4.CreatePerspectiveFieldOfView(MathHelper.DegreesToRadians(90), 1.0f, 0.1f, farPlane);
                Matrix4 view       = Matrix4.LookAt(origin + Vector3.Transform(new Vector3(longestSide, 0, 0), orbit), origin, Vector3.TransformNormal(up, orbit));

                RenderView(view, projection, mesh, m_occlusionQueries[i]);

                //Bitmap bmp = GLEx.BitmapColorBuffer(m_pixelWidth, m_pixelHeight);
                //bmp.Save("C:\\test_" + i + ".bmp");
            }

            // Gather all the occlusion queries we performed
            long[] m_occlusionQueryResults = new long[64];
            for (int i = 0; i < m_occlusionQueries.Length; i++)
            {
                int ready = 0;
                while (ready == 0)
                {
                    GL.GetQueryObject(m_occlusionQueries[i], GetQueryObjectParam.QueryResultAvailable, out ready);
                }

                GL.GetQueryObject(m_occlusionQueries[i], GetQueryObjectParam.QueryResult, out m_occlusionQueryResults[i]);
            }

            // Reset the current frame buffer.
            GL.Ext.BindFramebuffer(FramebufferTarget.FramebufferExt, 0);

            long totalSidePixels = 0;
            long totalTopPixels  = 0;

            for (int i = 0; i < m_occlusionQueries.Length; i++)
            {
                totalSidePixels += m_occlusionQueryResults[i];
            }

            sideCoverage = totalSidePixels;
            topCoverage  = totalTopPixels;
        }
Example #6
0
        public AABBf Clone()
        {
            AABBf clone = new AABBf();

            clone.MaxX = this.MaxX;
            clone.MaxY = this.MaxY;
            clone.MaxZ = this.MaxZ;
            clone.MinX = this.MinX;
            clone.MinY = this.MinY;
            clone.MinZ = this.MinZ;

            return(clone);
        }
Example #7
0
        public static AABBf CreateBoundingBox(IEnumerable <Triangle> triangles)
        {
            AABBf box = new AABBf();

            foreach (Triangle t in triangles)
            {
                box.Add(t.v0);
                box.Add(t.v1);
                box.Add(t.v2);
            }

            return(box);
        }
Example #8
0
        public static Mesh BuildMesh(AABBf aabb, Vector3 delta_p, List <AABBi> boxList)
        {
            Mesh mesh = BuildMesh(boxList);

            Vector4 aabb_min = new Vector4(aabb.MinX, aabb.MinY, aabb.MinZ, 0);
            Vector4 delta_p4 = new Vector4(delta_p, 1);

            for (int i = 0; i < mesh.Vertices.Length; i++)
            {
                mesh.Vertices[i] = aabb_min + Vector4.Multiply(mesh.Vertices[i], delta_p4);
            }

            return(mesh);
        }
Example #9
0
        private void PropagateStatus(VoxelizingOctreeCell seed, CellStatus status, VoxelizingOctreeCell current)
        {
            Vector4[] cell_bounds_verts = new Vector4[8];

            AABBf bounds = current.Bounds;

            cell_bounds_verts[0] = new Vector4(bounds.MaxX, bounds.MaxY, bounds.MaxZ, 1);
            cell_bounds_verts[1] = new Vector4(bounds.MaxX, bounds.MaxY, bounds.MinZ, 1);
            cell_bounds_verts[2] = new Vector4(bounds.MinX, bounds.MaxY, bounds.MinZ, 1);
            cell_bounds_verts[3] = new Vector4(bounds.MinX, bounds.MaxY, bounds.MaxZ, 1);
            cell_bounds_verts[4] = new Vector4(bounds.MaxX, bounds.MinY, bounds.MaxZ, 1);
            cell_bounds_verts[5] = new Vector4(bounds.MaxX, bounds.MinY, bounds.MinZ, 1);
            cell_bounds_verts[6] = new Vector4(bounds.MinX, bounds.MinY, bounds.MinZ, 1);
            cell_bounds_verts[7] = new Vector4(bounds.MinX, bounds.MinY, bounds.MaxZ, 1);

            // Loop over the number of cube faces
            for (int i = 0; i < 6; i++)
            {
                // Loop over the 8 vertices that make up the corners of a voxel cell.  If any of the corners is visible
                // the voxel will have the status accumulated into it.
                for (int n = 0; n < 8; n++)
                {
                    Vector4 result;
                    Vector4.Transform(ref cell_bounds_verts[n], ref cubemapProjections[i], out result);

                    float x = result.X / result.W;
                    float y = result.Y / result.W;
                    float z = result.Z / result.W;

                    if (x >= -1.0f && x <= 1.0f && y >= -1.0f && y <= 1.0f)
                    {
                        int depthBufferX = (int)(((x + 1.0f) / 2.0f) * (CubemapWidth - 1));
                        int depthBufferY = (int)(((y + 1.0f) / 2.0f) * (CubemapHeight - 1));

                        float sampledDepth     = cubemapDepthBuffers[i][depthBufferY * CubemapWidth + depthBufferX];
                        float ndc_sampledDepth = ((sampledDepth * 2.0f) - 1.0f);

                        if (z > -1.0f && z < ndc_sampledDepth)
                        {
                            // Accumulate the status on the cell must overcome threshold to be confirmed as inside or outside.
                            // If enough other voxels propagate the same status to the cell, it becomes a cell of that type.
                            if (current.AccumulateStatus(status))
                            {
                                return;
                            }
                        }
                    }
                }
            }
        }
Example #10
0
        private void CreateUniformBoundingBox(List <Triangle> triangles, out AABBf originalBounds, out AABBf voxelBounds, out Vector3 center, out float length)
        {
            originalBounds = Triangle.CreateBoundingBox(triangles);
            Vector3 size    = new Vector3(originalBounds.MaxX - originalBounds.MinX, originalBounds.MaxY - originalBounds.MinY, originalBounds.MaxZ - originalBounds.MinZ);
            float   maxSize = Math.Max(size.X, Math.Max(size.Y, size.Z));

            center = new Vector3(
                originalBounds.MinX + (size.X / 2.0f),
                originalBounds.MinY + (size.Y / 2.0f),
                originalBounds.MinZ + (size.Z / 2.0f));

            length = maxSize;

            voxelBounds      = new AABBf();
            voxelBounds.MinX = center.X - (length * 0.5f);
            voxelBounds.MinY = center.Y - (length * 0.5f);
            voxelBounds.MinZ = center.Z - (length * 0.5f);
            voxelBounds.MaxX = center.X + (length * 0.5f);
            voxelBounds.MaxY = center.Y + (length * 0.5f);
            voxelBounds.MaxZ = center.Z + (length * 0.5f);
        }
Example #11
0
        private void RenderCubeSide(int cubemapIndex, VoxelizingOctreeCell cell, Vector3 look, Vector3 up)
        {
            AABBf root_bounds = cell.Root.Bounds;
            float root_length = root_bounds.MaxX - root_bounds.MinX;
            float s_div2      = (cell.Bounds.MaxX - cell.Bounds.MinX) * 0.5f;

            GL.MatrixMode(MatrixMode.Projection);
            Matrix4 perspective = Matrix4.CreatePerspectiveFieldOfView(MathHelper.DegreesToRadians(90.0f), 1.0f, s_div2, root_length);

            GL.LoadMatrix(ref perspective);

            Matrix4 modelView = Matrix4.LookAt(cell.Center, cell.Center + look, up);

            GL.MatrixMode(MatrixMode.Modelview);
            GL.LoadMatrix(ref modelView);

            //cubemapProjections[cubemapIndex] = perspective * modelView;
            cubemapProjections[cubemapIndex] = modelView * perspective;

            GL.PushMatrix();

            GL.Ext.BindFramebuffer(FramebufferTarget.FramebufferExt, CubemapFboHandle[cubemapIndex]);

            // since there's only 1 Color buffer attached this is not explicitly required
            GL.DrawBuffer((DrawBufferMode)FramebufferAttachment.ColorAttachment0Ext);

            GL.ClearColor(0.0f, 0.0f, 0.0f, 0f);
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

            GL.Ext.FramebufferTexture2D(FramebufferTarget.FramebufferExt, FramebufferAttachment.ColorAttachment0Ext, TextureTarget.Texture2D, CubemapColorTexture[cubemapIndex], 0);
            GL.Ext.FramebufferRenderbuffer(FramebufferTarget.FramebufferExt, FramebufferAttachment.DepthAttachmentExt, RenderbufferTarget.RenderbufferExt, CubemapDepthRenderbuffer[cubemapIndex]);

            GL.PushAttrib(AttribMask.ViewportBit);
            GL.Viewport(0, 0, CubemapWidth, CubemapHeight);

            DrawTwoSidedOriginalMesh();

            GL.PopAttrib();
            GL.PopMatrix();
        }
Example #12
0
        public static void ComputeBestFitOBB(Vector3[] points, out float[] sides, out Matrix4 matrix, FitStrategy strategy)
        {
            matrix = Matrix4.Identity;
            AABBf aabb = new AABBf();

            for (int i = 0; i < points.Length; i++)
            {
                aabb.Add(points[i]);
            }

            float avolume = (aabb.MaxX - aabb.MinX) * (aabb.MaxY - aabb.MinY) * (aabb.MaxZ - aabb.MinZ);

            Plane plane;

            ComputeBestFitPlane(points, out plane);

            plane.ToMatrix(ref matrix);
            ComputeOBB(points, ref matrix, out sides);

            Matrix4 refmatrix = new Matrix4();

            refmatrix = matrix;

            float volume = sides[0] * sides[1] * sides[2];

            float stepSize = 5;

            switch (strategy)
            {
            case BestFit.FitStrategy.FS_FAST_FIT:
                stepSize = 13;     // 15 degree increments
                break;

            case BestFit.FitStrategy.FS_MEDIUM_FIT:
                stepSize = 7;     // 10 degree increments
                break;

            case BestFit.FitStrategy.FS_SLOW_FIT:
                stepSize = 3;     // 5 degree increments
                break;

            case BestFit.FitStrategy.FS_SLOWEST_FIT:
                stepSize = 1;     // 1 degree increments
                break;
            }

            Quaternion quat = new Quaternion();

            for (float a = 0; a < 180; a += stepSize)
            {
                Matrix4 temp;
                Matrix4.CreateRotationY(MathHelper.DegreesToRadians(a), out temp);
                QuaternionEx.CreateFromMatrix(ref temp, ref quat);

                Matrix4 pmatrix;
                Matrix4.Mult(ref temp, ref refmatrix, out pmatrix);

                float[] psides;
                ComputeOBB(points, ref pmatrix, out psides);
                float v = psides[0] * psides[1] * psides[2];
                if (v < volume)
                {
                    volume   = v;
                    matrix   = pmatrix;
                    sides[0] = psides[0];
                    sides[1] = psides[1];
                    sides[2] = psides[2];
                }
            }

            if (avolume < volume)
            {
                matrix = Matrix4.CreateTranslation(
                    (aabb.MinX + aabb.MaxX) * 0.5f,
                    (aabb.MinY + aabb.MaxY) * 0.5f,
                    (aabb.MinZ + aabb.MaxZ) * 0.5f);
                sides[0] = aabb.MaxX - aabb.MinX;
                sides[1] = aabb.MaxY - aabb.MinY;
                sides[2] = aabb.MaxZ - aabb.MinZ;
            }
        }
Example #13
0
 public bool IsOutside(AABBf other)
 {
     return((MaxX - other.MinX) < 0 || (MinX - other.MaxX) > 0 ||
            (MaxY - other.MinY) < 0 || (MinY - other.MaxY) > 0 ||
            (MaxZ - other.MinZ) < 0 || (MinZ - other.MaxZ) > 0);
 }
Example #14
0
        public VoxelizationOutput Generate(VoxelizationInput input, Action <VoxelizationProgress> progress)
        {
            this.input = input;
            VoxelizationOutput output = new VoxelizationOutput();

            output.Octree = input.Octree;

            List <List <VoxelizingOctreeCell> > cellList = new List <List <VoxelizingOctreeCell> >();

            input.Octree.AccumulateChildren(out cellList);

            VolumeAccumulator volume = new VolumeAccumulator();

            VolumeAccumulator[] volumeAtLevel = new VolumeAccumulator[input.Octree.MaxLevels];
            for (int i = 0; i < input.Octree.MaxLevels; i++)
            {
                List <VoxelizingOctreeCell> childernAtDepth = cellList[i];

                VolumeAccumulator levelVolumeTotal = new VolumeAccumulator();

                Parallel.For(0, childernAtDepth.Count, () => new VolumeAccumulator(), (n, loop, partial) =>
                {
                    VoxelizingOctreeCell cell = childernAtDepth[n];
                    float sideLength          = cell.Length;

                    switch (cell.Status)
                    {
                    case CellStatus.Inside:
                        partial.InsideTotal += (sideLength * sideLength * sideLength);
                        break;

                    case CellStatus.Outside:
                        partial.OutsideTotal += (sideLength * sideLength * sideLength);
                        break;

                    case CellStatus.Intersecting:
                    case CellStatus.IntersectingBounds:
                        if (cell.IsLeaf)
                        {
                            partial.IntersectingTotal += (sideLength * sideLength * sideLength);
                        }
                        break;
                    }

                    return(partial);
                },
                             partial =>
                {
                    lock (levelVolumeTotal)
                    {
                        levelVolumeTotal.InsideTotal       += partial.InsideTotal;
                        levelVolumeTotal.OutsideTotal      += partial.OutsideTotal;
                        levelVolumeTotal.IntersectingTotal += partial.IntersectingTotal;
                    }
                });

                volume.InsideTotal       += levelVolumeTotal.InsideTotal;
                volume.OutsideTotal      += levelVolumeTotal.OutsideTotal;
                volume.IntersectingTotal += levelVolumeTotal.IntersectingTotal;

                volumeAtLevel[i] = levelVolumeTotal;
            }


            Debug.WriteLine("Percentage of inner volume at each octree level");
            for (int i = 0; i < input.Octree.MaxLevels; i++)
            {
                Debug.WriteLine("Level {0}: Inner Volume {1}%", i, (volumeAtLevel[i].InsideTotal / volume.InsideTotal) * 100);
            }

            // A good check to perform is to compare the ratio of intersecting volume leaf nodes to the total volume
            // we've determined is inside.  A tool could use this ratio to automatically determine a good octree level
            // by iterative optimization.  If a mesh for example fails to get at least a 1 : 0.5 ratio of intersecting:inner
            // volume ratio it's a good bet that the octree does not subdivide enough levels in order to find enough inner volume
            // to meet our occlusion needs.  If further subdivision up to some maximum, lets say 8 fails to ever meet this ratio
            // one could say the mesh is not a good candidate for automating occluder generation.
            Debug.WriteLine("");
            float intersecting_inside_ratio = volume.InsideTotal / volume.IntersectingTotal;

            Debug.WriteLine("Intersecting : Inner = 1:{0}", intersecting_inside_ratio);
            Debug.WriteLine("Inner / (Inner + Intersecting) = {0}", volume.InsideTotal / (volume.InsideTotal + volume.IntersectingTotal));

            const float MINIMUM_INTERSECTING_TO_INSIDE_RATIO = 0.25f;

            AABBf  meshBounds = input.Octree.MeshBounds;
            double dX         = meshBounds.MaxX - meshBounds.MinX;
            double dY         = meshBounds.MaxY - meshBounds.MinY;
            double dZ         = meshBounds.MaxZ - meshBounds.MinZ;

            double reduction = 0.5;

            for (int i = 0; i <= input.Octree.MaxLevels * 2; i++)
            {
                reduction *= 0.5;
            }

            dX = dX * reduction;
            dY = dY * reduction;
            dZ = dZ * reduction;

            if (intersecting_inside_ratio > MINIMUM_INTERSECTING_TO_INSIDE_RATIO)
            {
                List <AABBi> innerBounds         = new List <AABBi>();
                float        innerVolumeGathered = 0.0f;
                for (int i = 0; i < input.Octree.MaxLevels; i++)
                {
                    for (int n = 0; n < cellList[i].Count; n++)
                    {
                        if (cellList[i][n].Status == CellStatus.Inside)
                        {
                            AABBf bound = cellList[i][n].Bounds;

                            AABBi bi = new AABBi();
                            bi.MaxX = (int)Math.Round(((double)bound.MaxX - (double)meshBounds.MinX) / dX, MidpointRounding.AwayFromZero);
                            bi.MaxY = (int)Math.Round(((double)bound.MaxY - (double)meshBounds.MinY) / dY, MidpointRounding.AwayFromZero);
                            bi.MaxZ = (int)Math.Round(((double)bound.MaxZ - (double)meshBounds.MinZ) / dZ, MidpointRounding.AwayFromZero);
                            bi.MinX = (int)Math.Round(((double)bound.MinX - (double)meshBounds.MinX) / dX, MidpointRounding.AwayFromZero);
                            bi.MinY = (int)Math.Round(((double)bound.MinY - (double)meshBounds.MinY) / dY, MidpointRounding.AwayFromZero);
                            bi.MinZ = (int)Math.Round(((double)bound.MinZ - (double)meshBounds.MinZ) / dZ, MidpointRounding.AwayFromZero);
                            innerBounds.Add(bi);
                        }
                    }

                    innerVolumeGathered += volumeAtLevel[i].InsideTotal / volume.InsideTotal;
                    if (innerVolumeGathered > input.MinimumVolume)
                    {
                        break;
                    }
                }

                Debug.WriteLine("Enough inner volume found {0}%", innerVolumeGathered * 100.0f);

                Mesh mesh = MeshBuilder.BuildMesh(innerBounds);

                for (int i = 0; i < mesh.Vertices.Length; i++)
                {
                    mesh.Vertices[i].X = (float)(((double)meshBounds.MinX) + (mesh.Vertices[i].X * dX));
                    mesh.Vertices[i].Y = (float)(((double)meshBounds.MinY) + (mesh.Vertices[i].Y * dY));
                    mesh.Vertices[i].Z = (float)(((double)meshBounds.MinZ) + (mesh.Vertices[i].Z * dZ));
                }

                if (input.Retriangulate)
                {
                    Mesh triangulatedMesh = MeshOptimizer.Retriangulate(input, mesh, out output.DebugLines);
                    if (triangulatedMesh != null)
                    {
                        mesh = triangulatedMesh;
                    }
                }

                mesh = PolygonFilter.Filter(input, mesh);

                output.OccluderMesh = new RenderableMesh(mesh, true);
            }
            else
            {
                Debug.WriteLine("Not enough inner volume found to continue.");
            }

            return(output);
        }