/// <summary> /// Creates an asset bundle from the assets located in the processed data directory. /// </summary> /// <returns></returns> Returns true if the asset bundle was created successfully, false otherwise. public bool CreateAssetBundleFromCreatedAssets() { // Delete previous asset bundle. GeneralToolkit.Delete(bundleDirectory); // Copy assets to the temporary directory. GeneralToolkit.Replace(PathType.Directory, processedDataDirectory, GeneralToolkit.tempDirectoryAbsolutePath); AssetDatabase.Refresh(); // Get the assets' relative path locations. string[] assetFullPaths = Directory.GetFiles(GeneralToolkit.tempDirectoryAbsolutePath); string[] assetRelativePaths = new string[assetFullPaths.Length]; for (int i = 0; i < assetFullPaths.Length; i++) { assetRelativePaths[i] = GeneralToolkit.ToRelativePath(assetFullPaths[i]); } // Create an asset bundle from these assets. bool success = GeneralToolkit.CreateAssetBundle(bundleDirectory, bundleName, assetRelativePaths); // If successful, indicate to the processing information file that the asset bundle was created. if (success && File.Exists(processingInfoFilePath)) { File.AppendAllLines(processingInfoFilePath, new string[] { processingInfoSuccessfulBundle }); } // Delete the temporary directory. GeneralToolkit.Delete(GeneralToolkit.tempDirectoryAbsolutePath); // Refresh the database. AssetDatabase.Refresh(); // Return whether the operation was successful. return(success); }
/// <summary> /// Parses the camera setup from a directory containing an "images" folder with an image dataset from the Stanford Light Field Archive, and saves the parsed setup in this directory. /// </summary> public void ParseCameraSetup() { // Inform of process start. Debug.Log(GeneralToolkit.FormatScriptMessage(this.GetType(), "Started parsing camera setup for an image dataset from the Stanford Light Field Archive located at: " + dataHandler.colorDirectory + ".")); // Get the files in the "images" folder. FileInfo[] fileInfos = GeneralToolkit.GetFilesByExtension(dataHandler.colorDirectory, ".png"); // Determine the pixel resolution of the images. Texture2D tempTex = new Texture2D(1, 1); GeneralToolkit.LoadTexture(fileInfos[0].FullName, ref tempTex); Vector2Int pixelResolution = new Vector2Int(tempTex.width, tempTex.height); DestroyImmediate(tempTex); // Prepare repositioning around center if it is selected. Vector3 meanPos = Vector3.zero; // Reset the camera models to fit the color count. _cameraSetup.ResetCameraModels(); _cameraSetup.cameraModels = new CameraModel[dataHandler.sourceColorCount]; // Iteratively add each camera model to the setup. for (int iter = 0; iter < dataHandler.sourceColorCount; iter++) { CameraModel cameraModel = _cameraSetup.AddCameraModel(iter); // Store the image's pixel resolution in the camera model. cameraModel.pixelResolution = pixelResolution; // Store the image's name in the camera model. FileInfo fileInfo = fileInfos[iter]; cameraModel.SetCameraReferenceIndexAndImageName(cameraModel.cameraReferenceIndex, fileInfo.Name); // Store the image's position in the model. string[] split = fileInfo.Name.Split('_'); float positionY = -GeneralToolkit.ParseFloat(split[split.Length - 3]); float positionX = GeneralToolkit.ParseFloat(split[split.Length - 2]); Vector3 pos = scaleFactor * new Vector3(positionX, positionY, 0); cameraModel.transform.position = pos; meanPos += pos; } // If it is selected, reposition the camera setup around its center position. if (repositionAroundCenter) { meanPos /= dataHandler.sourceColorCount; for (int iter = 0; iter < dataHandler.sourceColorCount; iter++) { CameraModel cameraModel = _cameraSetup.cameraModels[iter]; cameraModel.transform.position = cameraModel.transform.position - meanPos; } } // Temporarily move the color images to a safe location. string tempDirectoryPath = Path.Combine(GeneralToolkit.GetDirectoryBefore(dataHandler.dataDirectory), "temp"); GeneralToolkit.Move(PathType.Directory, dataHandler.colorDirectory, tempDirectoryPath); // Save the camera setup information (this would also have cleared the "images" folder if it was still there). Acquisition.Acquisition.SaveAcquisitionInformation(dataHandler, cameraSetup); // Move the color images back into their original location. GeneralToolkit.Delete(dataHandler.colorDirectory); GeneralToolkit.Move(PathType.Directory, tempDirectoryPath, dataHandler.colorDirectory); // Update the camera models of the setup object. _cameraSetup.FindCameraModels(); // Inform of end of process. Debug.Log(GeneralToolkit.FormatScriptMessage(this.GetType(), "Finished parsing camera setup. Result can be previewed in the Scene view.")); }
/// <summary> /// On destroy, destroys the potentially copied mesh in the Resources folder. /// </summary> public virtual void OnDestroy() { if (_loadedMeshFullPath != null) { bool isInResources = _loadedMeshFullPath.Contains(COLIBRIVRSettings.settingsResourcesAbsolutePath); if (isInResources && EditorApplication.isPlaying && GeneralToolkit.IsStartingNewScene()) { GeneralToolkit.Delete(_loadedMeshFullPath); AssetDatabase.Refresh(); } } }
/// <summary> /// Coroutine that saves the specified global mesh asset into the asset bundle. /// </summary> /// <returns></returns> private IEnumerator SaveGlobalMeshAsAssetCoroutine() { // Set the destination paths to a temporary asset folder. string bundledAssetName = GetBundledAssetName(globalMeshAssetName); string assetPathAbsolute = GetAssetPathAbsolute(bundledAssetName); string assetPathRelative = GetAssetPathRelative(bundledAssetName); // Check if the asset has already been processed. if (!dataHandler.IsAssetAlreadyProcessed(assetPathRelative)) { // If the mesh to store is already an asset, move it to the asset bundle path. string dstExtension = Path.GetExtension(_globalMeshPathAbsolute); if (dstExtension == ".asset") { // Copy the asset to the destination path. GeneralToolkit.Replace(PathType.File, _globalMeshPathAbsolute, assetPathAbsolute); // Refresh the asset database. AssetDatabase.Refresh(); } // Otherwise, the mesh first has to be converted into an asset. else { // Copy the mesh to the resources folder. string dstName = "COLIBRITempResource"; string dstFullPath = Path.Combine(COLIBRIVRSettings.settingsResourcesAbsolutePath, dstName + dstExtension); GeneralToolkit.Replace(PathType.File, _globalMeshPathAbsolute, dstFullPath); // Refresh the asset database. AssetDatabase.Refresh(); yield return(null); // Make the mesh readable so that colliders can be added. ModelImporter modelImporter = ModelImporter.GetAtPath(GeneralToolkit.ToRelativePath(dstFullPath)) as ModelImporter; modelImporter.isReadable = true; modelImporter.SaveAndReimport(); // Load the mesh from resources. Mesh loadedMesh = Resources.Load <Mesh>(dstName); // Copy the mesh by instantiating it. globalMesh = (Mesh)Instantiate(loadedMesh); // Recalculate the mesh's normals and bounds. globalMesh.RecalculateNormals(); globalMesh.RecalculateBounds(); // Create an asset from the copied mesh. AssetDatabase.CreateAsset(globalMesh, assetPathRelative); AssetDatabase.Refresh(); // Delete the mesh that was copied into the resources folder. GeneralToolkit.Delete(dstFullPath); } } Mesh meshAsset = AssetDatabase.LoadAssetAtPath <Mesh>(assetPathRelative); globalMesh = (Mesh)Instantiate(meshAsset); }
/// <summary> /// On enable, changes the workspace if entering edit mode after having performed reconstruction in play mode. /// </summary> void OnEnable() { if (!EditorApplication.isPlaying && GeneralToolkit.IsStartingNewScene()) { string indicatorPathAbsolute = Path.Combine(Application.dataPath, _updateDirectoryIndicatorPathEnd); if (File.Exists(indicatorPathAbsolute)) { ChangeWorkspaceAfterSparseReconstruction(); GeneralToolkit.Delete(indicatorPathAbsolute); AssetDatabase.Refresh(); } } }
/// <summary> /// Saves the meshes in the scene as a global mesh asset in the data directory. /// </summary> public void SaveGlobalMesh() { // Combines the different meshes in the scene into a single asset. Mesh outputMesh = new Mesh(); MeshFilter[] meshFilters = FindObjectsOfType <MeshFilter>(); CombineInstance[] combine = new CombineInstance[meshFilters.Length]; for (int i = 0; i < meshFilters.Length; i++) { combine[i].mesh = meshFilters[i].sharedMesh; combine[i].transform = meshFilters[i].transform.localToWorldMatrix; } outputMesh.CombineMeshes(combine, false); // Saves the asset in the data directory. string assetName = "GlobalMesh.asset"; string relativeAssetPath = Path.Combine("Assets", assetName); string globalAssetPath = Path.Combine(Path.GetFullPath(Application.dataPath), assetName); string newGlobalAssetPath = Path.Combine(dataHandler.dataDirectory, assetName); GeneralToolkit.CreateAndUnloadAsset(outputMesh, relativeAssetPath); GeneralToolkit.Replace(PathType.File, globalAssetPath, newGlobalAssetPath); GeneralToolkit.Delete(globalAssetPath); AssetDatabase.Refresh(); }
/// <summary> /// Coroutine that runs the sparse reconstruction process. /// </summary> /// <param name="caller"></param> The processing object calling this method. /// <param name="workspace"></param> The workspace from which to perform this method. /// <param name="COLMAPCameraIndex"></param> The index of the type of source camera (in the list of COLMAP cameras). /// <param name="isSingleCamera"></param> True if the source images were acquired by the same camera, false otherwise. /// <param name="maxImageSize"></param> The maximum image size for the undistortion step. /// <returns></returns> public static IEnumerator RunSparseReconstructionCoroutine(Processing.Processing caller, string workspace, int COLMAPCameraIndex, bool isSingleCamera, int maxImageSize) { // Indicate to the user that the process has started. GeneralToolkit.ResetCancelableProgressBar(true, true); // Create or clear the folders needed for the reconstruction. GeneralToolkit.Delete(GetDatabaseFile(workspace)); GeneralToolkit.CreateOrClear(PathType.Directory, GetSparseDir(workspace)); GeneralToolkit.CreateOrClear(PathType.Directory, GetSparse0Dir(workspace)); GeneralToolkit.CreateOrClear(PathType.Directory, GetDenseDir(workspace)); GeneralToolkit.CreateOrClear(PathType.Directory, GetDense0Dir(workspace)); // Initialize the command parameters. bool displayProgressBar = true; bool stopOnError = true; string[] progressBarParams = new string[3]; int maxStep = 6; progressBarParams[0] = GeneralToolkit.ToString(maxStep); progressBarParams[2] = "Processing canceled by user."; // Launch the different steps of the sparse reconstruction process. float focalLengthFactor = 0; for (int step = 1; step <= maxStep; step++) { // Step one: launch feature extraction. if (step == 1) { progressBarParams[1] = GetProgressBarParamsOne("Feature extraction", true, step, maxStep); CameraModel[] cameraModels = caller.cameraSetup.cameraModels; if (cameraModels != null && cameraModels.Length > 0) { CameraModel cameraParams = cameraModels[0]; float focalLength = Camera.FieldOfViewToFocalLength(cameraParams.fieldOfView.x, cameraParams.pixelResolution.x); focalLengthFactor = focalLength / Mathf.Max(cameraParams.pixelResolution.x, cameraParams.pixelResolution.y); } yield return(caller.StartCoroutine(RunFeatureExtractionCommand(caller, workspace, displayProgressBar, stopOnError, progressBarParams, COLMAPCameraIndex, isSingleCamera, focalLengthFactor))); } // Step two: launch feature matching. else if (step == 2) { progressBarParams[1] = GetProgressBarParamsOne("Feature matching", true, step, maxStep); yield return(caller.StartCoroutine(RunFeatureMatchingCommand(caller, workspace, displayProgressBar, stopOnError, progressBarParams))); } // Step three: launch mapping. else if (step == 3) { progressBarParams[1] = GetProgressBarParamsOne("Mapping", true, step, maxStep); yield return(caller.StartCoroutine(RunMappingCommand(caller, workspace, displayProgressBar, stopOnError, progressBarParams, (focalLengthFactor > 0)))); } // Step four: launch exporting original camera setup as text. else if (step == 4) { progressBarParams[1] = GetProgressBarParamsOne("Exporting camera setup (original) as text", true, step, maxStep); yield return(caller.StartCoroutine(RunExportModelAsTextCommand(caller, workspace, displayProgressBar, stopOnError, progressBarParams))); } // Step five: launch image undistortion. else if (step == 5) { // Launch undistortion. progressBarParams[1] = GetProgressBarParamsOne("Undistortion", true, step, maxStep); yield return(caller.StartCoroutine(RunUndistortionCommand(caller, workspace, displayProgressBar, stopOnError, progressBarParams, maxImageSize))); // Change the workspace and the data directory to the one created in the dense folder. // workspace = GetDense0Dir(workspace); // caller.dataHandler.ChangeDataDirectory(caller, workspace); // Debug.Log(GeneralToolkit.FormatScriptMessage(typeof(COLMAPConnector), "Changed data directory to: " + workspace)); } // Step six: launch exporting undistorted camera setup as text. else if (step == 6) { // Launch export process. progressBarParams[1] = GetProgressBarParamsOne("Exporting camera setup (undistorted) as text", true, step, maxStep); yield return(caller.StartCoroutine(RunExportModelAsTextCommand(caller, GetDense0Dir(workspace), displayProgressBar, stopOnError, progressBarParams))); // Display the parsed camera setup in the Scene view. caller.Deselected(); caller.Selected(); yield return(null); } // For each step, continue only if the user does not cancel the process. if (GeneralToolkit.progressBarCanceled) { break; } } // Change the data directory to the one created in the dense folder. if (!GeneralToolkit.progressBarCanceled) { Debug.Log(GeneralToolkit.FormatScriptMessage(typeof(COLMAPConnector), "Sparse reconstruction was a success.")); } // Indicate to the user that the process has ended. GeneralToolkit.ResetCancelableProgressBar(false, false); }