Ejemplo n.º 1
0
        // Pass:
        //   parameterName -
        //      used for the FbxTexture name. Can be something arbitrary since as far as I know,
        //      the texture node's name is unused by importers.
        private static void AddTextureToMaterial(
            FbxExportGlobals G,
            ExportFileReference fileRef,
            FbxSurfaceLambert fbxMaterial,
            string parameterName)
        {
            Debug.Assert(File.Exists(fileRef.m_originalLocation));

            var destPath = Path.Combine(G.m_outputDir, fileRef.m_uri);

            if (!File.Exists(destPath))
            {
                if (!FileUtils.InitializeDirectoryWithUserError(Path.GetDirectoryName(destPath)))
                {
                    return;
                }
                File.Copy(fileRef.m_originalLocation, destPath);
            }

            // It's kind of weird that the parameter name is used for the texture node's name,
            // but as far as I can tell nobody cares about that name, so whatever.
            FbxFileTexture fbxTexture = FbxFileTexture.Create(G.m_scene, parameterName);

            fbxTexture.SetFileName(destPath);
            fbxTexture.SetTextureUse(FbxTexture.ETextureUse.eStandard);
            fbxTexture.SetMappingType(FbxTexture.EMappingType.eUV);
            fbxTexture.SetMaterialUse(FbxFileTexture.EMaterialUse.eModelMaterial);
            fbxTexture.UVSet.Set(new FbxString("uv0"));
            // It's also weird that we only ever assign to the Diffuse slot.
            // Shouldn't we be looking at the parameter name and assigning to Diffuse, Normal, etc
            // based on what we see?
            // TODO: check
            fbxMaterial.Diffuse.ConnectSrcObject(fbxTexture);
            fbxMaterial.TransparentColor.ConnectSrcObject(fbxTexture);
        }
Ejemplo n.º 2
0
  public void Init() {
    string cacheDir = Path.Combine(Application.persistentDataPath, "assetCache");
    m_CacheDir = cacheDir.Replace("\\", "/");
    // Use a different directory from m_CacheDir to avoid having to make ValidGltfCache()
    // smart enough to allow directories with only a thumbnail and no asset data.
    m_ThumbnailCacheDir = Path.Combine(Application.persistentDataPath, "assetThumbnail")
        .Replace("\\", "/");
    m_ActiveRequests = new List<AssetGetter>();
    m_RequestLoadQueue = new List<ModelLoadRequest>();
    m_LoadQueue = new List<ModelLoadRequest>();

    FileUtils.InitializeDirectoryWithUserError(m_CacheDir, "Failed to create asset cache");

    // Create and populate model map.
    m_ModelsByAssetId = new Dictionary<string, Model>();
    try {
      foreach (string folderPath in EnumerateCacheDirectories()) {
        string folderName = Path.GetFileName(folderPath);
        string gltfFile = ValidGltfCache(folderPath, folderName);
        if (gltfFile != null) {
          string path = Path.Combine(folderPath, folderName);
          path = Path.Combine(path, gltfFile);
          m_ModelsByAssetId[folderName] = new Model(Model.Location.PolyAsset(folderName, path));
        } else {
          Debug.LogWarningFormat("Deleting invalid cache folder {0}", folderName);
          Directory.Delete(folderPath, true);
        }
      }
    } catch (DirectoryNotFoundException e) {
      Debug.LogException(e);
    } catch (UnauthorizedAccessException e) {
      Debug.LogException(e);
    }

    m_AssetSetByType = new Dictionary<PolySetType, AssetSet> {
      {
        PolySetType.User,
        new AssetSet()
      },
      {
        PolySetType.Liked,
        new AssetSet()
      },
      {
        PolySetType.Featured,
        new AssetSet { m_RefreshRequested = true }
      }
    };

    App.Instance.AppExit += () => {
      var models = EnumerateCacheDirectories()
        .OrderBy(d => Directory.GetLastAccessTimeUtc(d)).ToArray();
      for (int excess = models.Count() - kAssetDiskCacheSize; excess > 0; excess--) {
        Directory.Delete(models[excess - 1], true);
      }
    };
  }
Ejemplo n.º 3
0
        // Returns a writable name for the export file, creating any directories as necessary;
        // or null on failure.
        private static string MakeExportPath(string parent, string basename, string ext)
        {
            string child = FileUtils.GenerateNonexistentFilename(parent, basename: ext, extension: "");

            if (!FileUtils.InitializeDirectoryWithUserError(
                    child, "Failed to create export directory for " + ext))
            {
                return(null);
            }

            return(Path.Combine(child, string.Format("{0}.{1}", basename, ext)));
        }
Ejemplo n.º 4
0
        private static string GetExportBaseName()
        {
            var    current  = SaveLoadScript.m_Instance.SceneFile;
            string basename = (current.Valid)
        ? Path.GetFileNameWithoutExtension(current.FullPath).Replace(" ", "_")
        : "Untitled";

            string directoryName = FileUtils.GenerateNonexistentFilename(
                App.UserExportPath(), basename, "");

            if (!FileUtils.InitializeDirectoryWithUserError(directoryName, "Failed to export"))
            {
                throw new InvalidOperationException("Directory full (?!)");
            }
            return(Path.Combine(directoryName, basename));
        }
Ejemplo n.º 5
0
        private static void CreateTestDirectory()
        {
            if (sm_TestDirectory == null)
            {
                sm_TestDirectory = Path.Combine(Path.GetTempPath(), "TiltBrushUnitTests");
            }

            if (Directory.Exists(sm_TestDirectory))
            {
                Directory.Delete(sm_TestDirectory, true);
            }
            string failureMessage = string.Format("Can't create unit test directory: {0}", sm_TestDirectory);
            bool   dirCreated     = FileUtils.InitializeDirectoryWithUserError(sm_TestDirectory, failureMessage);

            if (!dirCreated)
            {
                throw new VrAssetServiceException(failureMessage);
            }
        }
Ejemplo n.º 6
0
        private static void ExportBrushStrokesFbx()
        {
            var    current  = SaveLoadScript.m_Instance.SceneFile;
            string basename = (current.Valid)
      ? Path.GetFileNameWithoutExtension(current.FullPath).Replace(" ", "_")
      : "Untitled";

            string directoryName = FileUtils.GenerateNonexistentFilename(
                App.UserExportPath(), basename, "");

            if (!FileUtils.InitializeDirectoryWithUserError(directoryName,
                                                            "Failed to export"))
            {
                return;
            }
            string fbxName = Path.Combine(directoryName, basename + ".fbx");

            ExportFbx.Export(fbxName, ExportFbx.kFbxAscii);
        }
Ejemplo n.º 7
0
            public TemporaryUploadDirectory()
            {
#if UNITY_EDITOR
                if (App.Config && App.Config.m_DebugUpload)
                {
                    // Delay deleting the directory until the next upload
                    string dirName = Path.Combine(Application.temporaryCachePath, "Upload");
                    if (Directory.Exists(dirName))
                    {
                        try { Directory.Delete(dirName, true); }
                        catch (Exception e) { Debug.LogException(e); }
                    }
                }
#endif
                Value = FileUtils.GenerateNonexistentFilename(
                    Application.temporaryCachePath, "Upload", "");
                string failureMessage = $"Can't create upload directory: {Value}";
                bool   dirCreated     = FileUtils.InitializeDirectoryWithUserError(Value, failureMessage);
                if (!dirCreated)
                {
                    throw new VrAssetServiceException(failureMessage);
                }
            }
Ejemplo n.º 8
0
        static public bool StartVideoCapture(string filePath, VideoRecorder recorder,
                                             UsdPathSerializer usdPathSerializer, bool offlineRender = false)
        {
            // Only one video at a time.
            if (m_ActiveVideoRecording != null)
            {
                return(false);
            }

            // Don't start recording unless there is enough space left.
            if (!FileUtils.InitializeDirectoryWithUserError(
                    Path.GetDirectoryName(filePath),
                    "Failed to start video capture"))
            {
                return(false);
            }

            // Vertical video is disabled.
            recorder.IsPortrait = false;

            // Start the capture first, which may fail, so do this before toggling any state.
            // While the state below is important for the actual frame capture, starting the capture process
            // does not require it.
            int sampleRate = 0;

            if (AudioCaptureManager.m_Instance.IsCapturingAudio)
            {
                sampleRate = AudioCaptureManager.m_Instance.SampleRate;
            }

            if (!recorder.StartCapture(filePath, sampleRate,
                                       AudioCaptureManager.m_Instance.IsCapturingAudio, offlineRender,
                                       offlineRender ? App.UserConfig.Video.OfflineFPS : App.UserConfig.Video.FPS))
            {
                OutputWindowScript.ReportFileSaved("Failed to start capture!", null,
                                                   OutputWindowScript.InfoCardSpawnPos.Brush);
                return(false);
            }

            m_ActiveVideoRecording = recorder;

            // Perform any necessary VR camera rendering optimizations to reduce CPU & GPU workload

            // Debug reduce quality for capture.
            // XXX This should just be ADAPTIVE RENDERING
            if (m_DebugVideoCaptureQualityLevel != -1)
            {
                m_PreCaptureQualityLevel = QualityControls.m_Instance.QualityLevel;
                QualityControls.m_Instance.QualityLevel = m_DebugVideoCaptureQualityLevel;
            }

            App.VrSdk.SetHmdScalingFactor(m_VideoCaptureResolutionScale);

            // Setup SSAA
            RenderWrapper wrapper = recorder.gameObject.GetComponent <RenderWrapper>();

            m_PreCaptureSuperSampling = wrapper.SuperSampling;
            wrapper.SuperSampling     = m_SuperSampling;

#if USD_SUPPORTED
            // Read from the Usd serializer if we're recording offline.  Write to it otherwise.
            m_UsdPathSerializer = usdPathSerializer;
            if (!offlineRender)
            {
                m_UsdPath = SaveLoadScript.m_Instance.SceneFile.Valid ?
                            Path.ChangeExtension(filePath, "usda") : null;
                m_RecordingStopwatch = new System.Diagnostics.Stopwatch();
                m_RecordingStopwatch.Start();
                if (!m_UsdPathSerializer.StartRecording(m_UsdPath))
                {
                    UnityEngine.Object.Destroy(m_UsdPathSerializer);
                    m_UsdPathSerializer = null;
                }
            }
            else
            {
                recorder.SetCaptureFramerate(Mathf.RoundToInt(App.UserConfig.Video.OfflineFPS));
                m_UsdPath = null;
                if (m_UsdPathSerializer.Load(App.Config.m_VideoPathToRender))
                {
                    m_UsdPathSerializer.StartPlayback();
                }
                else
                {
                    UnityEngine.Object.Destroy(m_UsdPathSerializer);
                    m_UsdPathSerializer = null;
                }
            }
#endif

            return(true);
        }
Ejemplo n.º 9
0
        public static string ExportScene()
        {
            var    current       = SaveLoadScript.m_Instance.SceneFile;
            string safeHumanName = FileUtils.SanitizeFilename(current.HumanName);
            string basename      = FileUtils.SanitizeFilename(
                (current.Valid && (safeHumanName != "")) ? safeHumanName : "Untitled");

            string parent = FileUtils.GenerateNonexistentFilename(App.UserExportPath(), basename, "");

            if (!FileUtils.InitializeDirectoryWithUserError(
                    parent, "Failed to create export directory"))
            {
                return("");
            }

            // Set up progress bar.
            var progress = new Progress();

            if (App.PlatformConfig.EnableExportJson)
            {
                progress.SetWork("json");
            }
#if FBX_SUPPORTED
            if (App.PlatformConfig.EnableExportFbx)
            {
                progress.SetWork("fbx");
            }
#endif
#if USD_SUPPORTED
            if (App.PlatformConfig.EnableExportUsd)
            {
                progress.SetWork("usd");
            }
#endif
#if (UNITY_EDITOR || EXPERIMENTAL_ENABLED)
            if (Config.IsExperimental)
            {
                progress.SetWork("wrl");
                progress.SetWork("stl");
#if FBX_SUPPORTED
                progress.SetWork("obj");
#endif
            }
#endif
            if (App.PlatformConfig.EnableExportGlb)
            {
                progress.SetWork("glb");
            }

            string filename;

            if (App.PlatformConfig.EnableExportJson &&
                (filename = MakeExportPath(parent, basename, "json")) != null)
            {
                using (var unused = new AutoTimer("raw export"))
                {
                    OverlayManager.m_Instance.UpdateProgress(0.1f);
                    ExportRaw.Export(filename);
                }
            }
            progress.CompleteWork("json");

#if FBX_SUPPORTED
            if (App.PlatformConfig.EnableExportFbx &&
                (filename = MakeExportPath(parent, basename, "fbx")) != null)
            {
                using (var unused = new AutoTimer("fbx export")) {
                    OverlayManager.m_Instance.UpdateProgress(0.3f);
                    ExportFbx.Export(filename,
                                     App.UserConfig.Export.ExportBinaryFbx ? ExportFbx.kFbxBinary : ExportFbx.kFbxAscii,
                                     App.UserConfig.Export.ExportFbxVersion);
                    OverlayManager.m_Instance.UpdateProgress(0.5f);
                }
            }
            progress.CompleteWork("fbx");
#endif

#if USD_SUPPORTED
            if (App.PlatformConfig.EnableExportUsd &&
                (filename = MakeExportPath(parent, basename, "usd")) != null)
            {
                using (var unused = new AutoTimer("usd export")) {
                    ExportUsd.ExportPayload(filename);
                }
            }
            progress.CompleteWork("usd");
#endif

#if (UNITY_EDITOR || EXPERIMENTAL_ENABLED)
            if (Config.IsExperimental &&
                (filename = MakeExportPath(parent, basename, "wrl")) != null)
            {
                ExportVrml.Export(filename);
                progress.CompleteWork("wrl");
            }

            if (Config.IsExperimental &&
                (filename = MakeExportPath(parent, basename, "stl")) != null)
            {
                ExportStl.Export(filename);
                progress.CompleteWork("stl");
            }

#if FBX_SUPPORTED
            if (Config.IsExperimental &&
                App.PlatformConfig.EnableExportFbx &&
                (filename = MakeExportPath(parent, basename, "obj")) != null)
            {
                // This has never been tested with the new fbx export style and may not work
                ExportFbx.Export(filename, ExportFbx.kObj);
                progress.CompleteWork("obj");
            }
#endif
#endif

            var results = new ExportGlTF.ExportResults();
            if (App.PlatformConfig.EnableExportGlb)
            {
                string extension   = App.Config.m_EnableGlbVersion2 ? "glb" : "glb1";
                int    gltfVersion = App.Config.m_EnableGlbVersion2 ? 2 : 1;
                filename = MakeExportPath(parent, basename, extension);
                if (filename != null)
                {
                    using (var unused = new AutoTimer("glb export"))
                    {
                        OverlayManager.m_Instance.UpdateProgress(0.7f);
                        var exporter = new ExportGlTF();
                        // TBT doesn't need (or want) brush textures in the output because it replaces all
                        // the materials, so it's fine to keep those http:. However, Sketchfab doesn't support
                        // http textures so if uploaded, this glb will have missing textures.
                        results = exporter.ExportBrushStrokes(
                            filename, AxisConvention.kGltf2, binary: true, doExtras: false,
                            includeLocalMediaContent: true,
                            gltfVersion: gltfVersion);
                        progress.CompleteWork("glb");
                    }
                }
            }

            OutputWindowScript.m_Instance.CreateInfoCardAtController(
                InputManager.ControllerName.Brush, basename + " exported! Your download will begin in 5 seconds.");
            ControllerConsoleScript.m_Instance.AddNewLine("Located in " + App.UserExportPath());

            string readmeFilename = Path.Combine(App.UserExportPath(), kExportReadmeName);
            if (!File.Exists(readmeFilename) && !Directory.Exists(readmeFilename))
            {
                File.WriteAllText(readmeFilename, kExportReadmeBody);
            }

            return(results.exportedFiles[0]);
        }
Ejemplo n.º 10
0
        internal static FbxSurfaceMaterial CreateFbxMaterial(
            FbxExportGlobals G, string meshNamespace, IExportableMaterial exportableMaterial,
            HashSet <string> createdMaterialNames)
        {
            string materialName;

            if (exportableMaterial is BrushDescriptor)
            {
                // Toolkit uses this guid (in "N" format) to look up a BrushDescriptor.
                // See Toolkit's ModelImportSettings.GetDescriptorForStroke
                materialName = $"{exportableMaterial.UniqueName:N}_{meshNamespace}_{exportableMaterial.DurableName}";
            }
            else if (exportableMaterial is DynamicExportableMaterial dem)
            {
                // Comes from {fbx,obj,gltf,...} import from {Poly, Media Library}
                // This is a customized version of a BrushDescriptor -- almost certainly
                // Pbr{Blend,Opaque}{Double,Single}Sided with maybe an added texture and
                // some of its params customized.
                // TBT will merge the material created by Unity for this FbxMaterial with
                // the premade material it has for the parent guid.
                materialName = $"{dem.Parent.m_Guid:N}_{meshNamespace}_{dem.DurableName}";
            }
            else
            {
                Debug.LogWarning($"Unknown class {exportableMaterial.GetType().Name}");
                materialName = $"{meshNamespace}_{exportableMaterial.DurableName}";
            }
            // If only ExportFbx were a non-static class we could merge it with FbxExportGlobals
            materialName = ExportUtils.CreateUniqueName(materialName, createdMaterialNames);

            FbxSurfaceLambert material = FbxSurfaceLambert.Create(G.m_scene, materialName);

            material.Ambient.Set(new FbxDouble3(0, 0, 0));
            material.Diffuse.Set(new FbxDouble3(1.0, 1.0, 1.0));
            if (exportableMaterial.EmissiveFactor > 0)
            {
                material.EmissiveFactor.Set(exportableMaterial.EmissiveFactor);
                material.Emissive.Set(new FbxDouble3(1.0, 1.0, 1.0));
            }
            if (exportableMaterial.BlendMode != ExportableMaterialBlendMode.None)
            {
                var blendMode = FbxProperty.Create(material, Globals.FbxStringDT, "BlendMode");
                switch (exportableMaterial.BlendMode)
                {
                case ExportableMaterialBlendMode.AlphaMask:
                    blendMode.SetString(new FbxString("AlphaMask"));
                    material.TransparencyFactor.Set(0.2);
                    break;

                case ExportableMaterialBlendMode.AdditiveBlend:
                    blendMode.SetString(new FbxString("AdditiveBlend"));
                    break;
                }
            }

            // Export the texture
            if (exportableMaterial.HasExportTexture())
            {
                // This is not perfectly unique, but it is good enough for fbx export
                // better would be to use <durable>_<guid> but that's ugly, and nobody uses
                // the textures anyway, so... let's leave well enough alone for now.
                string albedoTextureName = exportableMaterial.DurableName;
                var    fullTextureDir    = Path.Combine(G.m_outputDir, kRelativeTextureDir);
                if (!Directory.Exists(fullTextureDir))
                {
                    if (!FileUtils.InitializeDirectoryWithUserError(fullTextureDir))
                    {
                        throw new IOException("Cannot write textures");
                    }
                }
                string   src             = exportableMaterial.GetExportTextureFilename();
                var      textureFileName = albedoTextureName + ".png";
                var      textureFilePath = Path.Combine(fullTextureDir, textureFileName);
                FileInfo srcInfo         = new FileInfo(src);
                if (srcInfo.Exists && !new FileInfo(textureFilePath).Exists)
                {
                    srcInfo.CopyTo(textureFilePath);
                }

                FbxFileTexture texture = FbxFileTexture.Create(G.m_scene, albedoTextureName + "_texture");
                texture.SetFileName(textureFilePath);
                texture.SetTextureUse(FbxTexture.ETextureUse.eStandard);
                texture.SetMappingType(FbxTexture.EMappingType.eUV);
                texture.SetMaterialUse(FbxFileTexture.EMaterialUse.eModelMaterial);
                texture.UVSet.Set(new FbxString("uv0"));
                material.Diffuse.ConnectSrcObject(texture);
                material.TransparentColor.ConnectSrcObject(texture);
            }
            else
            {
                foreach (var kvp in exportableMaterial.TextureUris)
                {
                    string parameterName = kvp.Key;
                    string textureUri    = kvp.Value;
                    if (ExportFileReference.IsHttp(textureUri))
                    {
                        // fbx can't deal with http references to textures
                        continue;
                    }
                    ExportFileReference fileRef = ExportFileReference.GetOrCreateSafeLocal(
                        G.m_disambiguationContext, textureUri, exportableMaterial.UriBase,
                        $"{meshNamespace}_{Path.GetFileName(textureUri)}");
                    AddTextureToMaterial(G, fileRef, material, parameterName);
                }
            }
            return(material);
        }
Ejemplo n.º 11
0
        private static void ExportEnvironments()
        {
#if !GAMEOBJ_EXPORT_TO_GLTF
            Debug.LogError("Enable the define and fix up the code");
#else
            // Save the original RenderSettings
            Environment.RenderSettingsLite originalRenderSettings = Environment.GetRenderSettings();

            // Clear out the existing environments directory to do a clean export
            string projectPath           = Path.GetDirectoryName(Application.dataPath);
            string environmentExportPath = Path.Combine(projectPath,
                                                        ExportUtils.kProjectRelativeEnvironmentExportRoot);
            try {
                Directory.Delete(environmentExportPath, recursive: true);
            } catch (DirectoryNotFoundException) {
                // It's okay if this directory doesn't exist yet as it will be created later.
            }

            // Clear out the existing textures directory to do a clean export
            string textureExportPath = Path.Combine(projectPath,
                                                    ExportUtils.kProjectRelativeTextureExportRoot);
            try {
                Directory.Delete(textureExportPath, recursive: true);
            } catch (DirectoryNotFoundException) {
                // It's okay if this directory doesn't exist yet as it will be created later.
            }
            if (!FileUtils.InitializeDirectoryWithUserError(
                    textureExportPath, "Failed to export, can't create texture export directory"))
            {
                return;
            }

            // Get the environment
            TiltBrushManifest manifest = AssetDatabase.LoadAssetAtPath <TiltBrushManifest>("Assets/Manifest.asset");
            foreach (Environment env in manifest.Environments)
            {
                // Copy over the RenderSettings
                Environment.SetRenderSettings(env.m_RenderSettings);

                // Set up the environment
                string envGuid = env.m_Guid.ToString("D");
                Debug.LogFormat("Exporting environment: {0}", env.m_RenderSettings.m_EnvironmentPrefab);
                GameObject envPrefab     = Resources.Load <GameObject>(env.m_RenderSettings.m_EnvironmentPrefab);
                GameObject envGameObject = UObject.Instantiate(envPrefab);
                envGameObject.name = envGuid;

                // Hide game objects that don't get exported to Poly.
                foreach (Transform child in envGameObject.transform)
                {
                    if (SceneSettings.ExcludeFromPolyExport(child))
                    {
                        child.gameObject.SetActive(false);
                    }
                }

                // Set up the environment export directory
                string directoryName = Path.Combine(environmentExportPath, envGuid);
                if (!FileUtils.InitializeDirectoryWithUserError(
                        directoryName, "Failed to export, can't create environment export directory"))
                {
                    return;
                }

                string basename = FileUtils.SanitizeFilename(envGameObject.name);
                string gltfName = Path.Combine(directoryName, basename + ".gltf");

                var exporter = new ExportGlTF();
                exporter.ExportGameObject(envGameObject, gltfName, env);

                // DestroyImmediate is required because editor mode never runs object garbage collection.
                UObject.DestroyImmediate(envGameObject);
            }

            // Restore the original RenderSettings
            Environment.SetRenderSettings(originalRenderSettings);
#endif
        }