示例#1
0
        protected TreeNodeProcessor(string dataPath, TreeImportSettings settings, TreeImportData importData)
        {
            Settings      = settings;
            this.dataPath = dataPath;

            tmpFolderPath = Path.Combine(dataPath, "tmp");

            stride           = UnsafeUtility.SizeOf <PointCloudPoint>();
            ChildNodeRecords = new List <NodeRecord>();
            inputBuffer      = new PointCloudPoint[settings.chunkSize];

            if (settings.sampling == TreeImportSettings.SamplingMethod.CellCenter)
            {
                PointCollection         = new CellCenterPointCollection();
                VolatilePointCollection = new CellCenterPointCollection();
            }
            else
            {
                PointCollection         = new PoissonDiskPointCollection();
                VolatilePointCollection = new CellCenterPointCollection();
            }

            PointCollection.Initialize(settings, importData);
            VolatilePointCollection.Initialize(settings, importData);
        }
示例#2
0
        public OctreeNodeProcessor(string dataPath, TreeImportSettings settings, TreeImportData importData) : base(dataPath, settings, importData)
        {
            ChildBuffers = new PointCloudPoint[ChildCount][];
            for (var i = 0; i < ChildCount; ++i)
            {
                ChildBuffers[i] = new PointCloudPoint[settings.chunkSize];
            }

            ChildCounts     = new int[ChildCount];
            ChildFileCounts = new int[ChildCount];
        }
示例#3
0
        public MeshBuilder(string dataPath, TreeImportSettings settings, TreeImportData importData)
        {
            this.dataPath   = dataPath;
            this.importData = importData;
            this.settings   = settings;
            tmpDataPath     = Path.Combine(dataPath, "tmp");

            voxelData = new MeshGenerationData();

            for (var i = 1; i < LutOffsets.Length; ++i)
            {
                neighborData.Add(LutOffsets[i], new MeshGenerationData());
            }
        }
示例#4
0
        /// <summary>
        /// Dispatches mesh generation process on all available worker threads.
        /// </summary>
        /// <param name="importData">Import data generated during preprocessing.</param>
        /// <returns>True if mesh build succeeded, false otherwise.</returns>
        private bool GenerateMeshes(TreeImportData importData)
        {
            var cancelled = false;

            EditorUtility.DisplayProgressBar("Mesh generation", "Preparing for mesh generation...", 0f);
            // meshBuilders = new MeshBuilder[Settings.threadCount];

            for (var i = 0; i < Settings.threadCount; ++i)
            {
                processors[i] = new MeshBuilder(outputPath, Settings, importData);
                threads[i]    = new Thread(processors[i].StartWork);
                threads[i].Start();
            }

            var meshesToDo  = Directory.GetFiles(outputTmpPath, "*.meshdata");
            var meshesCount = meshesToDo.Length;

            foreach (var fileName in meshesToDo)
            {
                var id = Path.GetFileNameWithoutExtension(fileName);
                queue.Enqueue(nodeRecords[id]);
            }

            while (GenerateMeshLoop(out var busyThreadCount, out var voxelsDone))
            {
                var title =
                    $"Generating meshes ({busyThreadCount.ToString()}/{Settings.threadCount.ToString()} threads in use)";
                // var message = $"{doneCount.ToString()}/{meshesCount.ToString()} meshes";
                var message = $"{voxelsDone.ToString()} voxels processed";
                // var progress = (float) doneCount / meshesCount;

                if (EditorUtility.DisplayCancelableProgressBar(title, message, 0f))
                {
                    cancelled = true;
                    break;
                }

                Thread.Sleep(20);
            }

            return(!cancelled);
        }
示例#5
0
        /// <summary>
        /// Starts tree building process with given settings.
        /// </summary>
        public static bool BuildNodeTree(TreeImportSettings settings)
        {
            var processors = new List <PointProcessor>();

            foreach (var inputFile in settings.inputFiles)
            {
                var processor = CreateProcessor(Utility.GetFullPath(inputFile));
                if (processor != null)
                {
                    processors.Add(processor);
                }
            }

            if (processors.Count == 0)
            {
                Debug.LogError("All of given point cloud files are invalid or unsupported.");
                return(false);
            }

            var bounds = CalculateBounds(processors);

            var transformationData = new TransformationData(bounds, settings);

            var unityBounds = bounds.GetUnityBounds(settings);
            var transform   = transformationData.TransformationMatrix;

            unityBounds.center  = transform.MultiplyPoint3x4(unityBounds.center);
            unityBounds.extents = transform.MultiplyVector(unityBounds.extents);

            TreeImportData importData = null;

            if (settings.generateMesh && settings.roadOnlyMesh)
            {
                var histogram = GenerateHistogram(processors, bounds);
                importData = new TreeImportData(unityBounds, histogram);
            }
            else
            {
                importData = new TreeImportData(unityBounds);
            }

            NodeProcessorDispatcher dispatcher;
            var fullOutputPath = Utility.GetFullPath(settings.outputPath);

            try
            {
                EditorUtility.DisplayProgressBar("Creating dispatcher", "Preparing target directory...", 0f);
                dispatcher = new NodeProcessorDispatcher(fullOutputPath, settings);
            }
            finally
            {
                EditorUtility.ClearProgressBar();
            }

            foreach (var processor in processors)
            {
                if (!processor.ConvertPoints(dispatcher, transformationData))
                {
                    Debug.Log("Import cancelled.");
                    return(false);
                }
            }

            if (dispatcher.ProcessPoints(importData))
            {
                dispatcher.GetPointCountResults(out var total, out var used, out var discarded);
                Debug.Log($"Octree build finished successfully.\n" +
                          $"Used points: {used}/{total} ({discarded} discarded on low tree levels)");
                return(true);
            }
            else
            {
                Debug.Log("Octree build failed.");
                return(false);
            }
        }
示例#6
0
 ///<inheritdoc/>
 public void Initialize(TreeImportSettings treeSettings, TreeImportData importData)
 {
     rootBounds   = importData.Bounds;
     settings     = treeSettings;
     cellsPerAxis = new int[3];
 }
示例#7
0
        /// <summary>
        /// Builds tree of all points previously registered through <see cref="AddChunk"/> and <see cref="AddPoint"/> methods. Stores results on disk.
        /// </summary>
        /// <param name="importData">Import data generated during preprocessing.</param>
        /// <returns>True if tree build succeeded, false otherwise.</returns>
        public bool ProcessPoints(TreeImportData importData)
        {
            // Make sure all points are flushed to disk - buffers are ignored during build
            if (pointCount > 0)
            {
                FlushTmpFile(points, 0, pointCount);
                pointCount = 0;
            }

            processors = new ParallelProcessor[Settings.threadCount];
            threads    = new Thread[Settings.threadCount];

            var rootNode = Settings.treeType == TreeType.Octree ? new OctreeNodeRecord(TreeUtility.RootNodeIdentifier, importData.Bounds, 0) : new QuadtreeNodeRecord(TreeUtility.RootNodeIdentifier, importData.Bounds, 0) as NodeRecord;

            nodeRecords.Add(rootNode.Identifier, rootNode);
            var cancelled = false;

            void StopProcessorsIfRunning()
            {
                if (processors != null)
                {
                    foreach (var processor in processors)
                    {
                        processor.StopWork();
                    }

                    foreach (var thread in threads)
                    {
                        thread.Join();
                    }
                }
            }

            try
            {
                EditorUtility.DisplayProgressBar("Starting threads", "Allocating memory...", 0f);

                // This buffer is no loner needed - clear reference and let GC free the memory
                PublicMaxSizeBuffer = null;
                GC.Collect();

                // Start one processor on each of the requested threads
                for (var i = 0; i < Settings.threadCount; ++i)
                {
                    if (Settings.treeType == TreeType.Octree)
                    {
                        processors[i] = new OctreeNodeProcessor(outputPath, Settings, importData);
                    }
                    else
                    {
                        processors[i] = new QuadtreeNodeProcessor(outputPath, Settings, importData);
                    }

                    threads[i] = new Thread(processors[i].StartWork);
                    threads[i].Start();
                }

                // Assign root processing to first worker thread
                processors[0].AssignWork(rootNode);

                // Lock main thread here until either all work is finished or user cancels the process
                while (BuildLoop(out var busyThreadCount, out var finishedPointCount))
                {
                    var title =
                        $"Building tree ({busyThreadCount.ToString()}/{Settings.threadCount.ToString()} threads in use)";
                    var message  = $"{finishedPointCount.ToString()}/{totalPointsCount.ToString()} points";
                    var progress = (float)finishedPointCount / totalPointsCount;

                    if (EditorUtility.DisplayCancelableProgressBar(title, message, progress))
                    {
                        cancelled = true;
                        break;
                    }

                    Thread.Sleep(20);
                }

                if (!cancelled)
                {
                    foreach (var processor in processors)
                    {
                        discardedPointsCount += ((TreeNodeProcessor)processor).DiscardedPoints;
                    }

                    // Generate meshes - stop current work on threads, then restart with mesh builders
                    if (Settings.generateMesh)
                    {
                        StopProcessorsIfRunning();
                        if (!GenerateMeshes(importData))
                        {
                            cancelled = true;
                        }
                    }
                }

                // Tree build succeeded - finalize
                if (!cancelled)
                {
                    FinalizeBuild();
                }
            }
            finally
            {
                // Whether process finishes, crashes, or is cancelled, stop worker threads and clear progress bar
                EditorUtility.ClearProgressBar();

                StopProcessorsIfRunning();
                processors = null;
                threads    = null;

                Directory.Delete(outputTmpPath, true);

                GC.Collect();
            }

            return(!cancelled);
        }