示例#1
0
        Mesh BuildMeshFromBoxes(VoxelizationInput input, List <AABBi> boxes)
        {
            // Build the mesh, this will also remove all false triangle loops and collinear point triangles.
            Vector3 deltaP = new Vector3((float)input.Octree.SmallestVoxelSideLength, (float)input.Octree.SmallestVoxelSideLength, (float)input.Octree.SmallestVoxelSideLength);

            return(MeshBuilder.BuildMesh(input.Octree.VoxelBounds, deltaP, boxes));
        }
示例#2
0
        public VoxelizationOutput Voxelize(VoxelizationInput input, Action <VoxelizationProgress> progress)
        {
            // Setup VBO state
            GL.EnableClientState(ArrayCap.VertexArray);
            GL.EnableClientState(ArrayCap.IndexArray);

            m_input = input;

            VoxelizationOutput output = new VoxelizationOutput();

            output.Octree = input.Octree;

            VoxelizationProgress vp = new VoxelizationProgress();

            vp.Status = "Voxelizing mesh with " + input.Octree.MaxLevels + " subdivision levels";
            progress(vp);

            GL.PushAttrib(AttribMask.AllAttribBits);
            for (int i = 0; i <= input.Octree.MaxLevels; i++)
            {
                vp.Progress = (i / (input.Octree.MaxLevels + 1.0f));
                vp.Status   = "Voxelizing octree level " + i;
                progress(vp);
                RecursiveSolveStatus(input.Octree.Root, i);
            }
            GL.PopAttrib();

            vp.Progress = 1;
            vp.Status   = "Done voxelizing mesh";
            progress(vp);

            return(output);
        }
示例#3
0
        private static List <Triangle> FindAndFixTJuntions(VoxelizationInput input, List <Triangle> triangles)
        {
            // When one triangle shares two vertices with the edge of another triangle, but does not also
            // share the edge with the triangle, there is a T-Junction present.

FixStart:

            int counter = 0;

            foreach (Triangle t in triangles)
            {
                foreach (Triangle other in triangles)
                {
                    if (t == other)
                    {
                        continue;
                    }

                    Vector3 junctionPoint;
                    int     edge;
                    if (t.HasTJunction(other, VERTEX_EPSILON, out edge, out junctionPoint))
                    {
                        Debug.WriteLine(counter + " FOUND T-JUNCTION!");
                        counter++;

                        Triangle t0 = null, t1 = null;
                        switch (edge)
                        {
                        case 0:     // Edge 0 --- 1
                            t0 = new Triangle(junctionPoint, t.v2, t.v0);
                            t1 = new Triangle(junctionPoint, t.v1, t.v2);
                            break;

                        case 1:     // Edge 1 --- 2
                            t0 = new Triangle(junctionPoint, t.v0, t.v1);
                            t1 = new Triangle(junctionPoint, t.v2, t.v0);
                            break;

                        case 2:     // Edge 2 --- 0
                            t0 = new Triangle(junctionPoint, t.v1, t.v2);
                            t1 = new Triangle(junctionPoint, t.v0, t.v1);
                            break;

                        default:
                            throw new NotImplementedException();
                        }

                        int index = triangles.IndexOf(t);
                        triangles.Remove(t);
                        triangles.Insert(index, t0);
                        triangles.Insert(index, t1);

                        goto FixStart;
                    }
                }
            }

            return(triangles);
        }
示例#4
0
        public static Mesh Filter(VoxelizationInput input, Mesh mesh)
        {
            // Remove the top and bottom polygons
            if (input.RemoveTop || input.RemoveBottom)
            {
                Vector3 upAxis, downAxis;
                if (input.UpAxis == UpAxis.Y)
                {
                    upAxis   = Vector3.UnitY;
                    downAxis = -Vector3.UnitY;
                }
                else // if (input.UpAxis == UpAxis.Z)
                {
                    upAxis   = Vector3.UnitZ;
                    downAxis = -Vector3.UnitZ;
                }

                List <Triangle> filteredTrianlges = new List <Triangle>();

                Triangle[] triangles = Triangle.ToTriangleArray(mesh.Indicies, mesh.Vertices);
                foreach (Triangle t in triangles)
                {
                    Plane   p      = t.Plane;
                    Vector3 normal = t.NormalCounterClockwise();

                    // Remove all top polygon
                    if (input.RemoveTop)
                    {
                        if (Vector3Ex.AlmostEquals(ref normal, ref upAxis))
                        {
                            continue;
                        }
                    }

                    // Remove all bottom polygons that are with-in one voxel of the mesh bounds.
                    if (input.RemoveBottom)
                    {
                        if (Vector3Ex.AlmostEquals(ref normal, ref downAxis))
                        {
                            Vector3 closestPoint = input.Octree.MeshBounds.ClosestPointOnSurface(t.Center);
                            float   distance     = (t.Center - closestPoint).Length;
                            if (distance <= input.Octree.SmallestVoxelSideLength)
                            {
                                continue;
                            }
                        }
                    }

                    filteredTrianlges.Add(t);
                }

                Triangle.FromTriangleArray(filteredTrianlges, out mesh.Indicies, out mesh.Vertices);
            }

            return(mesh);
        }
示例#5
0
        List <AABBi> GetRelevantOccluders(VoxelizationInput input, List <Occluder> occluders)
        {
            var occluderBounds =
                from occluder in occluders
                where occluder.DeltaOcclusion > input.MinimumOcclusion
                orderby occluder.DeltaOcclusion descending
                select occluder.Bounds;

            return(occluderBounds.ToList());
        }
示例#6
0
        long MeasureOccluderOcclusion(SilhouetteOcclusionValidator sov, VoxelizationInput input, List <AABBi> occluderBounds)
        {
            Mesh           mesh       = BuildMeshFromBoxes(input, occluderBounds);
            RenderableMesh renderable = new RenderableMesh(mesh, true);

            long sideCoverage, topCoverage;

            sov.ComputeCoverage(renderable, input.Octree.MeshBounds, out sideCoverage, out topCoverage);

            renderable.Dispose();

            return(sideCoverage + topCoverage);
        }
示例#7
0
        protected override void OnClosing(CancelEventArgs e)
        {
            string settingPath = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), "Oxel.Settings.xml");

            VoxelizationInput.Save(settingPath, m_operations.Input);

            if (m_operations != null)
            {
                m_operations.Dispose();
                m_operations = null;
            }

            base.OnClosing(e);
        }
示例#8
0
        internal VoxelizationInput Clone(VoxelizationInput input)
        {
            input.m_voxelLevel    = m_voxelLevel;
            input.m_minVolume     = m_minVolume;
            input.m_type          = m_type;
            input.m_retriangulate = m_retriangulate;
            input.m_minOcclusion  = m_minOcclusion;
            input.m_removeTop     = m_removeTop;
            input.m_removeBottom  = m_removeBottom;
            input.m_upAxis        = m_upAxis;
            input.OriginalMesh    = OriginalMesh;
            input.Octree          = Octree;

            return(input);
        }
示例#9
0
        public MainWindow(VoxelizationInput input)
        {
            InitializeComponent();

            LinkLabel label = new LinkLabel();

            label.Text              = "Bug/Feature?";
            label.BackColor         = Color.Transparent;
            label.LinkColor         = Color.Blue;
            label.ActiveLinkColor   = Color.Blue;
            label.DisabledLinkColor = Color.Blue;
            label.VisitedLinkColor  = Color.Blue;
            label.LinkClicked      += (s, e) =>
            {
                Process.Start("mailto:[email protected]?subject=[Oxel] Bug/Feature");
            };
            ToolStripControlHost host = new ToolStripControlHost(label);

            host.Alignment = ToolStripItemAlignment.Right;
            m_menu.SuspendLayout();
            m_menu.Items.Add(host);
            m_menu.ResumeLayout(true);

            m_gl             = new GLControl(new GraphicsMode(32, 24, 8));
            m_gl.BackColor   = System.Drawing.Color.Black;
            m_gl.Dock        = System.Windows.Forms.DockStyle.Fill;
            m_gl.Location    = new System.Drawing.Point(0, 0);
            m_gl.Name        = "m_gl";
            m_gl.Size        = new System.Drawing.Size(716, 516);
            m_gl.TabIndex    = 2;
            m_gl.VSync       = false;
            m_gl.Load       += new System.EventHandler(this.m_gl_Load);
            m_gl.Paint      += new System.Windows.Forms.PaintEventHandler(this.m_gl_Paint);
            m_gl.KeyPress   += new System.Windows.Forms.KeyPressEventHandler(this.m_gl_KeyPress);
            m_gl.MouseDown  += new System.Windows.Forms.MouseEventHandler(this.m_gl_MouseDown);
            m_gl.MouseMove  += new System.Windows.Forms.MouseEventHandler(this.m_gl_MouseMove);
            m_gl.MouseUp    += new System.Windows.Forms.MouseEventHandler(this.m_gl_MouseUp);
            m_gl.MouseWheel += new MouseEventHandler(m_gl_MouseWheel);
            m_gl.Resize     += new System.EventHandler(this.m_gl_Resize);

            this.splitContainer1.Panel1.Controls.Add(this.m_gl);

            m_operations = new Operations();
            m_operations.Initialize(input);

            m_propertyGrid.SelectedObject       = m_operations.Input;
            m_operations.Input.PropertyChanged += new PropertyChangedEventHandler(vp_PropertyChanged);
        }
示例#10
0
        public static bool Save(string file, VoxelizationInput settings)
        {
            try
            {
                XmlSerializer x = new XmlSerializer(typeof(VoxelizationInput));
                using (StreamWriter myWriter = new StreamWriter(file))
                {
                    x.Serialize(myWriter, settings);
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
                return(false);
            }

            return(true);
        }
示例#11
0
        private static List <Edge> FindDistinctiveEdges(VoxelizationInput input, List <Triangle> triangles)
        {
            List <Edge> edges = new List <Edge>();

            foreach (Triangle t in triangles)
            {
                // TODO NDarnell Winding Order
                edges.Add(new Edge(t.v0, t.v1));
                edges.Add(new Edge(t.v1, t.v2));
                edges.Add(new Edge(t.v2, t.v0));
            }

            List <Edge> distinctEdges =
                (from e in edges
                 where edges.FindAll(ed => e.Equals(ed, VERTEX_EPSILON)).Count == 1
                 select e).ToList();

            return(distinctEdges);
        }
示例#12
0
        public static VoxelizationInput Load(string file)
        {
            try
            {
                if (!File.Exists(file))
                {
                    return(null);
                }

                VoxelizationInput settings     = null;
                XmlSerializer     mySerializer = new XmlSerializer(typeof(VoxelizationInput));
                using (FileStream myFileStream = new FileStream(file, FileMode.Open))
                {
                    settings = (VoxelizationInput)mySerializer.Deserialize(myFileStream);
                }

                return(settings);
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
                return(null);
            }
        }
示例#13
0
        public virtual VoxelizationOutput Generate(VoxelizationInput input, Action <VoxelizationProgress> progress)
        {
            VoxelizationProgress vp = new VoxelizationProgress();

            DateTime start = DateTime.Now;

            vp.Status = "Building voxel field from octree";
            progress(vp);

            VoxelField voxelField = new VoxelField(input.Octree);

            Byte  fillByte   = 2;
            float oldPercent = 1.0f;
            float newPercent = 1.0f;

            List <Occluder> occluders = new List <Occluder>();

            vp.Status = "Calculating original mesh silhouette coverage";
            progress(vp);

            SilhouetteOcclusionValidator sov = new SilhouetteOcclusionValidator(1024, 1024);

            long groundSideCoverage, groundTopCoverage;

            sov.ComputeCoverage(input.OriginalMesh, input.Octree.MeshBounds, out groundSideCoverage, out groundTopCoverage);
            long totalCoverage = groundSideCoverage + groundTopCoverage;

            if (totalCoverage == 0)
            {
                totalCoverage = 1;
            }

            vp.Status = "Fitting boxes into mesh...";
            progress(vp);

            long oldOcclusion = 0;

            do
            {
                Vector3i densestVoxel = FindHighestDensityVoxel(voxelField);

                AABBi occluderBounds;
                if (input.Type == OcclusionType.BoxExpansion)
                {
                    occluderBounds = ExpandAndFillBox(voxelField, ref densestVoxel, fillByte);
                }
                //else if (input.Type == OcclusionType.SimulatedAnnealing)
                //{
                //    occluderBounds = SimulatedAnnealingFill(input, sov, voxelField, ref densestVoxel, fillByte, occluders);
                //}
                else if (input.Type == OcclusionType.BruteForce)
                {
                    occluderBounds = BruteForceFill(input, sov, voxelField, densestVoxel, fillByte, occluders);
                }
                else
                {
                    throw new Exception("Unknown occluder generation type!");
                }

                List <AABBi> relevantOccluders = GetRelevantOccluders(input, occluders);
                relevantOccluders.Add(occluderBounds);

                long newOcclusion = MeasureOccluderOcclusion(sov, input, relevantOccluders);

                Occluder occluder = new Occluder();
                occluder.Bounds         = occluderBounds;
                occluder.DeltaOcclusion = (newOcclusion - oldOcclusion) / (double)totalCoverage;

                occluders.Add(occluder);

                if (occluder.DeltaOcclusion > input.MinimumOcclusion)
                {
                    oldOcclusion = newOcclusion;
                }

                Debug.WriteLine("Coverage " + occluder.DeltaOcclusion);
                Debug.WriteLine("Bounds (" + occluder.Bounds.MinX + "x" + occluder.Bounds.MaxX + " " + occluder.Bounds.MinY + "x" + occluder.Bounds.MaxY + " " + occluder.Bounds.MinZ + "x" + occluder.Bounds.MaxZ + ")");

                oldPercent = newPercent;
                newPercent = MeasureUnboxedVoxels(voxelField);

                Debug.WriteLine("(" + densestVoxel.X + "," + densestVoxel.Y + "," + densestVoxel.Z + ")\tCoverage=" + ((1 - newPercent) * 100) + "%\tDelta=" + ((oldPercent - newPercent) * 100) + "%");

                vp.Progress           = Math.Min(((1 - newPercent) / input.MinimumVolume), 1.0f);
                vp.SilhouetteCoverage = oldOcclusion / (double)totalCoverage;
                vp.VolumeCoverage     = 1 - newPercent;
                vp.Status             = String.Format("Occlusion Progress : {0:0.##}%", (100 * vp.Progress));

                progress(vp);
            } while (newPercent > (1 - input.MinimumVolume));

            Mesh mesh = BuildMeshFromBoxes(input, GetRelevantOccluders(input, occluders));

            VoxelizationOutput output = new VoxelizationOutput();

            if (input.Retriangulate)
            {
                vp.Status = "Retriangulating occluder mesh";
                progress(vp);

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

            vp.Status = "Filtering polygons";
            progress(vp);

            mesh = PolygonFilter.Filter(input, mesh);

            vp.Status = "Generating final occlusion mesh";
            progress(vp);

            // Prepare the output
            output.Octree             = input.Octree;
            output.TimeTaken          = DateTime.Now - start;
            output.VolumeCoverage     = 1 - newPercent;
            output.SilhouetteCoverage = oldOcclusion / (double)totalCoverage;
            output.OccluderMesh       = new RenderableMesh(mesh, true);

            vp.Status = "Cleanup...";
            progress(vp);

            sov.Dispose();

            return(output);
        }
示例#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);
        }
示例#15
0
        internal VoxelizationInput Clone()
        {
            VoxelizationInput input = new VoxelizationInput();

            return(Clone(input));
        }
示例#16
0
        public static void Run(string[] args)
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            ProgramOptions options = new ProgramOptions();

            string            settingPath = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), "Oxel.Settings.xml");
            VoxelizationInput input       = VoxelizationInput.Load(settingPath);

            if (input == null)
            {
                input = new VoxelizationInput();
            }

            if (args.Contains("-c"))
            {
                // Make sure user can see console output
                AttachConsole(PARENT_PROCESS_ID);

                input.Clone(options);

                if (!CommandLineParser.Parse <ProgramOptions>(args, ref options))
                {
                    return;
                }

                options.Clone(input);
            }
            else
            {
                CommandLineParser.Parse <VoxelizationInput>(args, ref input);
            }

            if (options.UseCommandLine)
            {
                Logger.IsCommandLine = true;

                Operations operations = new Operations();
                operations.Initialize(input);
                operations.Open(options.InputMesh, input.WindingOrder);
                WaitHandle waitHandle = operations.GenerateOccluder((VoxelizationProgress vp) => {
                    string coverage =
                        String.Format("Volume Coverage     : {0,5:0.##}%", (100 * vp.VolumeCoverage)) + "    " +
                        String.Format("Silhouette Coverage : {0,5:0.##}%", (100 * vp.SilhouetteCoverage));

                    if (!String.IsNullOrEmpty(vp.Status))
                    {
                        Console.WriteLine(vp.Status + "\r\n");
                    }

                    Console.WriteLine(coverage);
                }, new Action(() => { }));
                waitHandle.WaitOne();
                operations.Save(options.OutputMesh);
            }
            else
            {
                using (MainWindow window = new MainWindow(input))
                {
                    window.ShowDialog();
                }
            }
        }
示例#17
0
        public static Mesh Retriangulate(VoxelizationInput input, Mesh mesh, out List <List <Edge> > debugLoops)
        {
            debugLoops = new List <List <Edge> >();

            try
            {
                Triangle[] triangles = Triangle.ToTriangleArray(mesh.Indicies, mesh.Vertices);

                Debug.WriteLine("Sorting triangles based on plane.");

                List <PolygonTriangles> planeLookup = SortTrianglesIntoPlanes(triangles);

                Debug.WriteLine("Triangles sorted by planes: Done.");

                List <Vector4> processedVerticies = new List <Vector4>();
                List <int>     processedIndicies  = new List <int>();

                foreach (PolygonTriangles polygon in planeLookup)
                {
#if DEBUGGING_TJUNCTIONS
                    if (!Vector3Ex.AlmostEquals(polygon.Plane.Normal, Vector3.UnitY))
                    {
                        continue;
                    }
#endif

                    // Before we can begin margining edges we need to ensure that all shared collinear edges
                    // have a mate, one thing that can prevent this is the presence of T-Junctions, so first
                    // we need to fix them by splitting polygons that produce them.
                    polygon.Triangles = FindAndFixTJuntions(input, polygon.Triangles);

                    // We build a list of distinctive edges because a distinctive edge is either part of the inner loop
                    // or the outer loop of a group of polygons, because if two polygons share an edge that are co-planer
                    // that edge can't be on the inside or the outside of the plane.
                    List <Edge> distinctEdges = FindDistinctiveEdges(input, polygon.Triangles);
                    debugLoops.Add(distinctEdges.ToList());

                    // Merge the edges together that are collinear.
                    List <List <Edge> > outterLoops = FindOuterLoops(distinctEdges);
                    //allLoops.AddRange(outterLoops);

                    Vector3 right = Vector3Ex.GetRight(polygon.Plane.Normal);
                    Vector3 U, V;
                    Vector3Ex.GetBasisVectors(polygon.Plane.Normal, right, out U, out V);

                    Vector3 planeOrigin = polygon.Plane.PointOnPlane;

                    foreach (List <Edge> outterEdgeLoop in outterLoops)
                    {
                        List <Vector2> outerLoopTransformed = new List <Vector2>();
                        for (int i = 0; i < outterEdgeLoop.Count; i++)
                        {
                            Edge e = outterEdgeLoop[i];

                            Vector2 uv = Vector3Ex.Calc2DPoint(e.v0, U, V);

                            outerLoopTransformed.Add(uv);
                        }

                        //Debug.Assert(outerLoopTransformed.Count > 2);
                        if (outerLoopTransformed.Count > 2)
                        {
                            List <Poly2Tri.PolygonPoint> polyPoints = new List <Poly2Tri.PolygonPoint>();
                            foreach (var pt in outerLoopTransformed)
                            {
                                polyPoints.Add(new Poly2Tri.PolygonPoint(pt.X, pt.Y));
                            }
                            Poly2Tri.Polygon p = new Poly2Tri.Polygon(polyPoints);
                            Poly2Tri.P2T.Triangulate(Poly2Tri.TriangulationAlgorithm.DTSweep, p);

                            int currentVerticies = processedVerticies.Count;
                            foreach (var dt in p.Triangles)
                            {
                                processedIndicies.Add((currentVerticies + 0));
                                processedIndicies.Add((currentVerticies + 1));
                                processedIndicies.Add((currentVerticies + 2));

                                Vector3 pt0 = (((float)dt.Points._0.X * U) + ((float)dt.Points._0.Y * V)) - planeOrigin;
                                Vector3 pt1 = (((float)dt.Points._1.X * U) + ((float)dt.Points._1.Y * V)) - planeOrigin;
                                Vector3 pt2 = (((float)dt.Points._2.X * U) + ((float)dt.Points._2.Y * V)) - planeOrigin;
                                processedVerticies.Add(new Vector4(pt0, 1));
                                processedVerticies.Add(new Vector4(pt1, 1));
                                processedVerticies.Add(new Vector4(pt2, 1));

                                currentVerticies += 3;
                            }
                        }
                        else
                        {
                            Debug.WriteLine("outer loop problem!");
                        }
                    }

                    Debug.WriteLine("Distinct Edges " + processedIndicies.Count / 3);
                }

                Mesh retriangulatedMesh = new Mesh();
                retriangulatedMesh.Vertices = processedVerticies.ToArray();
                retriangulatedMesh.Indicies = processedIndicies.ToArray();

                return(retriangulatedMesh);
            }
            catch (Exception)
            {
                return(null);
            }
        }
示例#18
0
        AABBi BruteForceFill(VoxelizationInput input, SilhouetteOcclusionValidator sov, VoxelField voxelField, Vector3i densestVoxel, byte fillByte, List <Occluder> currentOccluders)
        {
            Object syncroot        = new Object();
            Int64  largestVolume   = 1;
            AABBi  largestOccluder = new AABBi(densestVoxel.X, densestVoxel.Y, densestVoxel.Z, densestVoxel.X + 1, densestVoxel.Y + 1, densestVoxel.Z + 1);

            int          MaxTopOccluders = 2000;
            List <AABBi> bestOccluders   = new List <AABBi>(MaxTopOccluders);

            Parallel.For(densestVoxel.Z + 1, voxelField.VoxelSize.Z, max_z =>
            {
                for (Int32 min_z = densestVoxel.Z; min_z >= 0; --min_z)
                {
                    for (Int32 max_y = densestVoxel.Y + 1; max_y < voxelField.VoxelSize.Y; ++max_y)
                    {
                        for (Int32 min_y = densestVoxel.Y; min_y >= 0; --min_y)
                        {
                            for (Int32 max_x = densestVoxel.X + 1; max_x < voxelField.VoxelSize.X; ++max_x)
                            {
                                for (Int32 min_x = densestVoxel.X; min_x >= 0; --min_x)
                                {
                                    Int32 dx     = max_x - min_x;
                                    Int32 dy     = max_y - min_y;
                                    Int32 dz     = max_z - min_z;
                                    Int64 volume = dx * dy * dz;

                                    if (TestRangeForFreeSpace(voxelField, new AABBi(min_x, min_y, min_z, max_x, max_y, max_z)))
                                    {
                                        lock (syncroot)
                                        {
                                            if (volume > largestVolume)
                                            {
                                                largestVolume   = volume;
                                                largestOccluder = new AABBi(min_x, min_y, min_z, max_x, max_y, max_z);
                                                if (bestOccluders.Count >= MaxTopOccluders)
                                                {
                                                    bestOccluders.RemoveAt(MaxTopOccluders - 1);
                                                }
                                                bestOccluders.Insert(0, largestOccluder);
                                            }
                                        }
                                    }
                                    else
                                    {
                                        // if we can't expand outward any further there's no point in checking more.
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }

                Debug.WriteLine("Checked " + max_z);
            });

            List <AABBi> relevantOccluders = GetRelevantOccluders(input, currentOccluders);

            long  bestCoverage       = 0;
            AABBi bestCoverageVolume = largestOccluder;

            foreach (AABBi occluder in bestOccluders)
            {
                List <AABBi> tempOccluders = relevantOccluders.ToList();
                tempOccluders.Add(occluder);
                long coverage = MeasureOccluderOcclusion(sov, input, tempOccluders);
                if (coverage > bestCoverage)
                {
                    bestCoverage       = coverage;
                    bestCoverageVolume = occluder;
                }
            }

            FillRange(voxelField, bestCoverageVolume, fillByte);

            return(bestCoverageVolume);
        }
示例#19
0
 public void Initialize(VoxelizationInput input)
 {
     Input = input;
 }
示例#20
0
        AABBi SimulatedAnnealingFill(VoxelizationInput input, SilhouetteOcclusionValidator sov, VoxelField volume, ref Vector3i densestVoxel, byte fillByte, List <Occluder> currentOccluders)
        {
            AABBi current = new AABBi(densestVoxel.X, densestVoxel.Y, densestVoxel.Z, densestVoxel.X + 1, densestVoxel.Y + 1, densestVoxel.Z + 1);
            AABBi next    = new AABBi(0, 0, 0, 0, 0, 0);

            int iteration = -1;

            List <AABBi> relevantOccluders = GetRelevantOccluders(input, currentOccluders);

            List <AABBi> occluders = relevantOccluders.ToList();

            occluders.Add(current);
            long coverage = MeasureOccluderOcclusion(sov, input, occluders);

            double coolignAlpha = 0.999;
            double temperature  = 400.0;
            double epsilon      = 0.001;

            Random random = new Random(1337);

            int maxItterations = 1000;

            long delta = 0;

            while (temperature > epsilon && iteration < maxItterations)
            {
                iteration++;

                ComputeNext(random, current, next, volume, ref densestVoxel, delta, temperature);

                occluders = relevantOccluders.ToList();
                occluders.Add(next);
                delta = MeasureOccluderOcclusion(sov, input, occluders) - coverage;

                if (delta < 0)
                {
                    next.Clone(current);
                    coverage = delta + coverage;
                }
                else
                {
                    double probability = random.NextDouble();

                    if (probability < Math.Exp(-delta / temperature))
                    {
                        next.Clone(current);
                        coverage = delta + coverage;
                    }
                }

                temperature *= coolignAlpha;

                if (iteration % 400 == 0)
                {
                    Console.WriteLine(coverage);
                }
            }

            FillRange(volume,
                      new Vector3i(current.MinX, current.MinY, current.MinZ),
                      new Vector3i(current.MaxX, current.MaxY, current.MaxZ),
                      fillByte);

            return(current);
        }
示例#21
0
        public WaitHandle GenerateOccluder(Action <VoxelizationProgress> progress, Action done)
        {
            ManualResetEvent waitHandle = new ManualResetEvent(false);

            if (Context == null || Context.OriginalMesh == null)
            {
                Logger.DisplayError("Please Open a mesh first.");
                waitHandle.Set();
                return(waitHandle);
            }

            Input.Octree       = Context.Octree;
            Input.OriginalMesh = Context.OriginalMesh;

            VoxelizationInput  input  = Input.Clone();
            VoxelizationOutput output = null;

            IOccluderGenerator occluder;

            switch (input.Type)
            {
            case OcclusionType.Octree:
                occluder = new OccluderOctree();
                break;

            case OcclusionType.BoxExpansion:
                occluder = new OccluderBoxExpansion();
                break;

            //case OcclusionType.SimulatedAnnealing:
            //    occluder = new OccluderBoxExpansion();
            //    break;
            case OcclusionType.BruteForce:
                occluder = new OccluderBoxExpansion();
                break;

            default:
                throw new Exception("Unknown occluder type.");
            }

            Thread thread = new Thread(() =>
            {
                INativeWindow window = new OpenTK.NativeWindow();
                IGraphicsContext gl  = new GraphicsContext(new GraphicsMode(32, 24, 8), window.WindowInfo);
                gl.MakeCurrent(window.WindowInfo);

                while (window.Exists)
                {
                    window.ProcessEvents();

                    try
                    {
                        RobustVoxelizer voxelizer = new RobustVoxelizer(512, 512);
                        output = voxelizer.Voxelize(input, progress);
                        voxelizer.Dispose();

                        output = occluder.Generate(input, progress);
                    }
                    catch (System.Exception ex)
                    {
                        Debug.WriteLine(ex.ToString());
                    }

                    window.Close();
                    break;
                }

                gl.MakeCurrent(null);

                if (Context.OccluderMesh != null)
                {
                    Context.OccluderMesh.Dispose();
                }

                Context.Octree             = output.Octree;
                Context.OccluderMesh       = output.OccluderMesh;
                Context.VoxelizationOutput = output;

                waitHandle.Set();

                done();
            });

            thread.IsBackground = true;
            thread.SetApartmentState(ApartmentState.STA);
            thread.Start();

            return(waitHandle);
        }