Exemplo n.º 1
0
        /// <summary>
        /// Read and write materials with as little code as possible.
        /// </summary>
        public static void MaterialIoTest()
        {
            var scene = Scene.Create();

            scene.Write("/Model/Geom/Cube", new CubeSample(1.0));
            scene.Write("/Model/Geom/Cube", new MaterialBindingSample("/Model/Materials/SampleMat"));
            scene.Write("/Model/Materials/SampleMat", new MaterialSample("/Model/Materials/PrevewShader.outputs:result"));

            var previewSurface = new PreviewSurfaceSample();

            previewSurface.diffuseColor.SetConnectedPath("/Model/Materials/Tex.outputs:result");
            scene.Write("/Model/Materials/PrevewShader", previewSurface);
            scene.Write("/Model/Materials/Tex", new TextureReaderSample("C:\\foo\\bar.png"));

            PrintScene(scene);

            var cube = new CubeSample();

            scene.Read("/Model/Geom/Cube", cube);
            var binding = new MaterialBindingSample();

            scene.Read("/Model/Geom/Cube", binding);
            var material = new MaterialSample();

            scene.Read(binding.binding.GetOnlyTarget(), material);
            var shader = new PreviewSurfaceSample();

            scene.Read(material.surface.GetConnectedPath(), shader);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Exports the given texture to the destination texture path and wires up the preview surface.
        /// </summary>
        /// <returns>
        /// Returns the path to the USD texture object.
        /// </returns>
        protected static string SetupTexture(Scene scene,
                                             string usdShaderPath,
                                             Material material,
                                             PreviewSurfaceSample surface,
                                             string destTexturePath,
                                             string textureName,
                                             string textureOutput)
        {
#if UNITY_EDITOR
            var srcPath = UnityEditor.AssetDatabase.GetAssetPath(material.GetTexture(textureName));
            srcPath = srcPath.Substring("Assets/".Length);
            srcPath = Application.dataPath + "/" + srcPath;
            var fileName = System.IO.Path.GetFileName(srcPath);
            var filePath = System.IO.Path.Combine(destTexturePath, fileName);

            System.IO.File.Copy(srcPath, filePath, overwrite: true);

            // Make file path baked into USD relative to scene file and use forward slashes.
            filePath = ImporterBase.MakeRelativePath(scene.FilePath, filePath);
            filePath = filePath.Replace("\\", "/");

            var uvReader = new PrimvarReaderSample <Vector2>();
            uvReader.varname.defaultValue = new TfToken("st");
            scene.Write(usdShaderPath + "/uvReader", uvReader);
            var tex = new TextureReaderSample(filePath, usdShaderPath + "/uvReader.outputs:result");
            scene.Write(usdShaderPath + "/" + textureName, tex);
            return(usdShaderPath + "/" + textureName + ".outputs:" + textureOutput);
#else
            // Not supported at run-time, too many things can go wrong
            // (can't encode compressed textures, etc).
            throw new System.Exception("Not supported at run-time");
#endif
        }
Exemplo n.º 3
0
        public virtual void ImportParametersFromUsd(Scene scene,
                                                    string materialPath,
                                                    MaterialSample materialSample,
                                                    PreviewSurfaceSample previewSurf,
                                                    SceneImportOptions options)
        {
            var    primvars  = new List <string>();
            string uvPrimvar = null;

            IsSpecularWorkflow = previewSurf.useSpecularWorkflow.defaultValue == 1;

            ImportColorOrMap(scene, previewSurf.diffuseColor, false, options, ref DiffuseMap, ref Diffuse,
                             out uvPrimvar);
            MergePrimvars(uvPrimvar, primvars);

            ImportColorOrMap(scene, previewSurf.emissiveColor, false, options, ref EmissionMap, ref Emission,
                             out uvPrimvar);
            MergePrimvars(uvPrimvar, primvars);

            ImportValueOrMap(scene, previewSurf.normal, true, options, ref NormalMap, ref Normal, out uvPrimvar);
            MergePrimvars(uvPrimvar, primvars);

            ImportValueOrMap(scene, previewSurf.displacement, false, options, ref DisplacementMap, ref Displacement,
                             out uvPrimvar);
            MergePrimvars(uvPrimvar, primvars);

            ImportValueOrMap(scene, previewSurf.occlusion, false, options, ref OcclusionMap, ref Occlusion,
                             out uvPrimvar);
            MergePrimvars(uvPrimvar, primvars);

            ImportValueOrMap(scene, previewSurf.roughness, false, options, ref RoughnessMap, ref Roughness,
                             out uvPrimvar);
            MergePrimvars(uvPrimvar, primvars);

            ImportValueOrMap(scene, previewSurf.clearcoat, false, options, ref ClearcoatMap, ref Clearcoat,
                             out uvPrimvar);
            MergePrimvars(uvPrimvar, primvars);

            ClearcoatRoughness = previewSurf.clearcoatRoughness.defaultValue;

            if (IsSpecularWorkflow)
            {
                ImportColorOrMap(scene, previewSurf.specularColor, false, options, ref SpecularMap, ref Specular,
                                 out uvPrimvar);
                MergePrimvars(uvPrimvar, primvars);
            }
            else
            {
                ImportValueOrMap(scene, previewSurf.metallic, false, options, ref MetallicMap, ref Metallic,
                                 out uvPrimvar);
                MergePrimvars(uvPrimvar, primvars);
            }

            options.materialMap.SetPrimvars(materialPath, primvars);
        }
Exemplo n.º 4
0
        public static void ExportLit(Scene scene,
                                     string usdShaderPath,
                                     Material material,
                                     PreviewSurfaceSample surface,
                                     string destTexturePath)
        {
            Color c;

            if (material.HasProperty("_BaseColorMap") && material.GetTexture("_BaseColorMap") != null)
            {
                var newTex = SetupTexture(scene, usdShaderPath, material, surface, destTexturePath, "_BaseColorMap", "rgb");
                surface.diffuseColor.SetConnectedPath(newTex);
            }
            else if (material.HasProperty("_BaseColor"))
            {
                c = material.GetColor("_BaseColor").linear;
                surface.diffuseColor.defaultValue = new Vector3(c.r, c.g, c.b);
            }
            else
            {
                c = Color.white;
                surface.diffuseColor.defaultValue = new Vector3(c.r, c.g, c.b);
            }

            if (material.HasProperty("_BaseColorMap") && material.GetTexture("_BaseColorMap") != null)
            {
                var newTex = SetupTexture(scene, usdShaderPath, material, surface, destTexturePath, "_BaseColorMap", "a");
                surface.opacity.SetConnectedPath(newTex);
            }
            else if (material.HasProperty("_BaseColor"))
            {
                c = material.GetColor("_BaseColor").linear;
                surface.opacity.defaultValue = c.a;
            }
            else
            {
                c = Color.white;
                surface.opacity.defaultValue = 1.0f;
            }

            var  materialType = (int)material.GetFloat("_MaterialID");
            bool useMetallic  = false;
            bool useSpec      = false;

            switch (materialType)
            {
            case 0: // Subsurf, no metallic parameter
                surface.useSpecularWorkflow.defaultValue = 1;
                break;

            case 1: // Standard, metallic + smoothness.
            case 2: // Anisotropy, metallic + smoothness.
            case 3: // Iridescence, metallic + smoothness.
                surface.useSpecularWorkflow.defaultValue = 0;
                useMetallic = true;
                break;

            case 4: // Specular color.
                surface.useSpecularWorkflow.defaultValue = 0;
                useSpec = true;
                break;

            case 5: // Translucent, no metallic.
                surface.useSpecularWorkflow.defaultValue = 0;
                break;
            }

            if (useSpec && material.HasProperty("_SpecularColorMap") && material.GetTexture("_SpecularColorMap") != null)
            {
                var newTex = SetupTexture(scene, usdShaderPath, material, surface, destTexturePath, "_SpecularColorMap", "rgb");
                surface.specularColor.SetConnectedPath(newTex);
            }
            else if (useSpec && material.HasProperty("_SpecularColor"))
            {
                c = material.GetColor("_SpecularColor");
                surface.specularColor.defaultValue = new Vector3(c.r, c.g, c.b);
            }
            else
            {
                c = new Color(.5f, .5f, .5f);
                surface.specularColor.defaultValue = new Vector3(c.r, c.g, c.b);
            }

            if (useMetallic && material.HasProperty("_MaskMap") && material.GetTexture("_MaskMap") != null)
            {
                var newTex = SetupTexture(scene, usdShaderPath, material, surface, destTexturePath, "_MaskMap", "r");
                surface.metallic.SetConnectedPath(newTex);
            }
            else if (useMetallic && material.HasProperty("_Metallic"))
            {
                surface.metallic.defaultValue = material.GetFloat("_Metallic");
            }
            else
            {
                surface.metallic.defaultValue = 0.5f;
            }

            if (material.HasProperty("_MaskMap") && material.GetTexture("_MaskMap") != null)
            {
                var newTex = SetupTexture(scene, usdShaderPath, material, surface, destTexturePath, "_MaskMap", "a");
                surface.roughness.SetConnectedPath(newTex);
            }
            else if (material.HasProperty("_Smoothness"))
            {
                surface.roughness.defaultValue = 1 - material.GetFloat("_Smoothness");
            }
            else
            {
                surface.roughness.defaultValue = 0.5f;
            }

            if (material.HasProperty("_MaskMap") && material.GetTexture("_MaskMap") != null)
            {
                var newTex = SetupTexture(scene, usdShaderPath, material, surface, destTexturePath, "_MaskMap", "b");
                surface.displacement.SetConnectedPath(newTex);
            }

            if (material.HasProperty("_MaskMap") && material.GetTexture("_MaskMap") != null)
            {
                var newTex = SetupTexture(scene, usdShaderPath, material, surface, destTexturePath, "_MaskMap", "g");
                surface.occlusion.SetConnectedPath(newTex);
            }

            if (material.HasProperty("_CoatMaskMap") && material.GetTexture("_CoatMaskMap") != null)
            {
                var newTex = SetupTexture(scene, usdShaderPath, material, surface, destTexturePath, "_CoatMaskMap", "r");
                surface.clearcoat.SetConnectedPath(newTex);
            }

            if (material.HasProperty("_CoatMask"))
            {
                surface.clearcoatRoughness.defaultValue = material.GetFloat("_CoatMask");
            }

            if (material.HasProperty("_NormalMap") && material.GetTexture("_NormalMap") != null)
            {
                var newTex = SetupTexture(scene, usdShaderPath, material, surface, destTexturePath, "_NormalMap", "rgb");
                surface.normal.SetConnectedPath(newTex);
            }

            if (material.IsKeywordEnabled("_EMISSIVE_COLOR_MAP"))
            {
                if (material.HasProperty("_EmissionMap") && material.GetTexture("_EmissionMap") != null)
                {
                    var newTex = SetupTexture(scene, usdShaderPath, material, surface, destTexturePath, "_EmissionMap", "rgb");
                    surface.emissiveColor.SetConnectedPath(newTex);
                }
                else if (material.HasProperty("_EmissionColor"))
                {
                    c = material.GetColor("_EmissionColor").linear;
                    surface.emissiveColor.defaultValue = new Vector3(c.r, c.g, c.b);
                }
            }
        }
Exemplo n.º 5
0
        public static void ExportLit(Scene scene,
                                     string usdShaderPath,
                                     Material material,
                                     PreviewSurfaceSample surface,
                                     string destTexturePath)
        {
            Color c;

            // useful for debugging which keywords are set in which case to determine actual feature usage
            // (just because a material has an _AlphaCutoff does not mean the option is actually active)
            // Debug.Log("Material: " + material.name + ", Keywords: " + string.Join("\n", material.shaderKeywords), material);
            surface.diffuseColor.defaultValue = new Vector3(1, 1, 1);
            if (material.HasProperty("_BaseColorMap") && material.GetTexture("_BaseColorMap") != null)
            {
                var scale = Vector4.one;
                if (material.HasProperty("_BaseColor"))
                {
                    scale = material.GetColor("_BaseColor").linear;
                }

                var newTex = SetupTexture(scene, usdShaderPath, material, surface, scale, destTexturePath,
                                          "_BaseColorMap", "rgb");
                surface.diffuseColor.SetConnectedPath(newTex);
            }
            else if (material.HasProperty("_BaseColor"))
            {
                c = material.GetColor("_BaseColor").linear;
                surface.diffuseColor.defaultValue = new Vector3(c.r, c.g, c.b);
            }
            else
            {
                c = Color.white;
                surface.diffuseColor.defaultValue = new Vector3(c.r, c.g, c.b);
            }

            if (material.IsKeywordEnabled("_SURFACE_TYPE_TRANSPARENT"))
            {
                if (material.HasProperty("_BaseColorMap") && material.GetTexture("_BaseColorMap") != null)
                {
                    var scale = Vector4.one;
                    if (material.HasProperty("_BaseColor"))
                    {
                        scale.w = material.GetColor("_BaseColor").linear.a;
                    }

                    var newTex = SetupTexture(scene, usdShaderPath, material, surface, scale, destTexturePath,
                                              "_BaseColorMap", "a");
                    surface.opacity.SetConnectedPath(newTex);
                }
                else if (material.HasProperty("_BaseColor"))
                {
                    c = material.GetColor("_BaseColor").linear;
                    surface.opacity.defaultValue = c.a;
                }
                else
                {
                    c = Color.white;
                    surface.opacity.defaultValue = 1.0f;
                }

                if (material.IsKeywordEnabled("_ALPHATEST_ON"))
                {
                    surface.opacityThreshold.defaultValue = material.GetFloat("_AlphaCutoff");
                }
            }

            var  materialType = (int)material.GetFloat("_MaterialID");
            bool useMetallic  = false;
            bool useSpec      = false;

            switch (materialType)
            {
            case 0:     // Subsurf, no metallic parameter
                surface.useSpecularWorkflow.defaultValue = 1;
                break;

            case 1:     // Standard, metallic + smoothness.
            case 2:     // Anisotropy, metallic + smoothness.
            case 3:     // Iridescence, metallic + smoothness.
                surface.useSpecularWorkflow.defaultValue = 0;
                useMetallic = true;
                break;

            case 4:     // Specular color.
                surface.useSpecularWorkflow.defaultValue = 0;
                useSpec = true;
                break;

            case 5:     // Translucent, no metallic.
                surface.useSpecularWorkflow.defaultValue = 0;
                break;
            }

            if (useSpec && material.HasProperty("_SpecularColorMap") &&
                material.GetTexture("_SpecularColorMap") != null)
            {
                var scale = Vector4.one;
                if (useSpec && material.HasProperty("_SpecularColor"))
                {
                    scale = material.GetColor("_SpecularColor");
                }

                var newTex = SetupTexture(scene, usdShaderPath, material, surface, scale, destTexturePath,
                                          "_SpecularColorMap", "rgb");
                surface.specularColor.SetConnectedPath(newTex);
            }
            else if (useSpec && material.HasProperty("_SpecularColor"))
            {
                c = material.GetColor("_SpecularColor");
                surface.specularColor.defaultValue = new Vector3(c.r, c.g, c.b);
            }
            else
            {
                c = new Color(.5f, .5f, .5f);
                surface.specularColor.defaultValue = new Vector3(c.r, c.g, c.b);
            }

            surface.metallic.defaultValue = 1.0f;
            if (useMetallic && material.HasProperty("_MaskMap") && material.GetTexture("_MaskMap") != null)
            {
                var scale = Vector4.one;
                if (useSpec && material.HasProperty("_Metallic"))
                {
                    scale.x = material.GetFloat("_Metallic");
                }

                var newTex = SetupTexture(scene, usdShaderPath, material, surface, scale, destTexturePath, "_MaskMap",
                                          "b", ConversionType.MaskMapToORM);
                surface.metallic.SetConnectedPath(newTex);
            }
            else if (useMetallic && material.HasProperty("_Metallic"))
            {
                surface.metallic.defaultValue = material.GetFloat("_Metallic");
            }
            else
            {
                surface.metallic.defaultValue = 0.5f;
            }

            // TODO seems _Smoothness isn't actually used in HDRP;
            // there's _SmoothnessMin and _SmoothnessMax for remapping which would need to be implemented with scale and bias.
            surface.roughness.defaultValue = 0.0f;
            if (material.HasProperty("_MaskMap") && material.GetTexture("_MaskMap") != null)
            {
                var scale = Vector4.one;
                if (material.HasProperty("_Smoothness"))
                {
                    scale.w = 1 - material.GetFloat("_Smoothness");
                }

                var newTex = SetupTexture(scene, usdShaderPath, material, surface, scale, destTexturePath, "_MaskMap",
                                          "g", ConversionType.MaskMapToORM);
                surface.roughness.SetConnectedPath(newTex);
            }
            else if (material.HasProperty("_Smoothness"))
            {
                surface.roughness.defaultValue = 1 - material.GetFloat("_Smoothness");
            }
            else
            {
                surface.roughness.defaultValue = 0.5f;
            }

            if (material.IsKeywordEnabled("_VERTEX_DISPLACEMENT") ||
                material.IsKeywordEnabled("_TESSELLATION_DISPLACEMENT"))
            {
                if (material.HasProperty("_HeightMap") && material.GetTexture("_HeightMap") != null)
                {
                    // TODO texture scale and bias needs to be constructed from the heightmap parametrization;
                    // there's a lot of options
                    // (_HeightAmplitude, _HeightCenter, _HeightMapParametrization, _HeightMax, _HeightMin, _HeightOffset, _HeightPoMAmplitude, _HeightTessAmplitude, _HeightTessCenter)
                    var newTex = SetupTexture(scene, usdShaderPath, material, surface, Vector4.one, destTexturePath,
                                              "_HeightMap", "r");
                    surface.displacement.SetConnectedPath(newTex);
                }
            }

            if (material.HasProperty("_MaskMap") && material.GetTexture("_MaskMap") != null)
            {
                var newTex = SetupTexture(scene, usdShaderPath, material, surface, Vector4.one, destTexturePath,
                                          "_MaskMap", "r", ConversionType.MaskMapToORM);
                surface.occlusion.SetConnectedPath(newTex);
            }

            if (material.HasProperty("_CoatMaskMap") && material.GetTexture("_CoatMaskMap") != null)
            {
                var newTex = SetupTexture(scene, usdShaderPath, material, surface, Vector4.one, destTexturePath,
                                          "_CoatMaskMap", "r");
                surface.clearcoat.SetConnectedPath(newTex);
            }

            if (material.HasProperty("_CoatMask"))
            {
                surface.clearcoatRoughness.defaultValue = material.GetFloat("_CoatMask");
            }

            if (material.HasProperty("_NormalMap") && material.GetTexture("_NormalMap") != null)
            {
                var newTex = SetupTexture(scene, usdShaderPath, material, surface, Vector4.one, destTexturePath,
                                          "_NormalMap", "rgb", ConversionType.UnpackNormal);
                surface.normal.SetConnectedPath(newTex);
            }

            if (material.IsKeywordEnabled("_EMISSIVE_COLOR_MAP"))
            {
                if (material.HasProperty("_EmissiveColorMap") && material.GetTexture("_EmissiveColorMap") != null)
                {
                    var scale = Vector4.one;
                    if (material.HasProperty("_EmissiveColor"))
                    {
                        scale = material.GetColor("_EmissiveColor").linear;
                    }

                    var newTex = SetupTexture(scene, usdShaderPath, material, surface, scale, destTexturePath,
                                              "_EmissiveColorMap", "rgb");
                    surface.emissiveColor.SetConnectedPath(newTex);
                }
                else if (material.HasProperty("_EmissiveColor"))
                {
                    c = material.GetColor("_EmissiveColor").linear;
                    surface.emissiveColor.defaultValue = new Vector3(c.r, c.g, c.b);
                }
            }
        }
Exemplo n.º 6
0
        public static void ReadWriteTest()
        {
            // Game plan:
            //   1. Create a cube
            //   2. Create a material
            //   3. Create a shader
            //   4. Create a texture
            //   5. Connect the material to the shader's output
            //   6. Connect the shader's albedo parameter to the texture's output
            //   7. Connect the texture to the source file on disk
            //   8. Write all values
            //   9. Bind the cube to the material
            var scene = Scene.Create();

            var cubePath          = "/Model/Geom/Cube";
            var materialPath      = "/Model/Materials/SimpleMat";
            var shaderPath        = "/Model/Materials/SimpleMat/PreviewMaterial";
            var texturePath       = "/Model/Materials/SimpleMat/TextureReader";
            var primvarReaderPath = "/Model/Materials/SimpleMat/UvReader";

            var cube = new CubeSample();

            cube.size = 1;

            var material = new MaterialSample();

            material.surface.SetConnectedPath(shaderPath, "outputs:result");

            var shader = new PreviewSurfaceSample();

            shader.diffuseColor.defaultValue = Vector3.one;
            shader.diffuseColor.SetConnectedPath(texturePath, "outputs:rgb");

            var texture = new TextureReaderSample();

            texture.file.defaultValue = new SdfAssetPath(@"C:\A\Bogus\Texture\Path.png");

            var primvarReader = new PrimvarReaderSample <Vector2>();

            primvarReader.varname.defaultValue = new TfToken("st");

            scene.Write("/Model", new XformSample());
            scene.Write("/Model/Geom", new XformSample());
            scene.Write("/Model/Materials", new XformSample());
            scene.Write(cubePath, cube);
            scene.Write(materialPath, material);
            scene.Write(shaderPath, shader);
            scene.Write(texturePath, texture);
            scene.Write(primvarReaderPath, primvarReader);

            MaterialSample.Bind(scene, cubePath, materialPath);

            var material2      = new MaterialSample();
            var shader2        = new PreviewSurfaceSample();
            var texture2       = new TextureReaderSample();
            var primvarReader2 = new PrimvarReaderSample <Vector2>();

            scene.Read(materialPath, material2);
            scene.Read(shaderPath, shader2);
            scene.Read(texturePath, texture2);
            scene.Read(primvarReaderPath, primvarReader2);

            var param = shader2.GetInputParameters().First();

            AssertEqual(shader.diffuseColor.connectedPath, param.connectedPath);
            AssertEqual("diffuseColor", param.usdName);
            AssertEqual(shader.diffuseColor.defaultValue, param.value);
            AssertEqual("_DiffuseColor", param.unityName);

            AssertEqual(material.surface.defaultValue, material2.surface.defaultValue);
            AssertEqual(material.surface.connectedPath, material2.surface.connectedPath);
            AssertEqual(shader.diffuseColor.defaultValue, shader2.diffuseColor.defaultValue);
            AssertEqual(shader.diffuseColor.connectedPath, shader2.diffuseColor.connectedPath);
            AssertEqual(shader.id, shader2.id);
            AssertEqual(texture.file.defaultValue, texture2.file.defaultValue);
            AssertEqual(primvarReader.varname.defaultValue, primvarReader.varname.defaultValue);

            PrintScene(scene);
        }
Exemplo n.º 7
0
        /// <summary>
        /// Exports the given texture to the destination texture path and wires up the preview surface.
        /// </summary>
        /// <returns>
        /// Returns the path to the USD texture object.
        /// </returns>
        protected static string SetupTexture(Scene scene,
                                             string usdShaderPath,
                                             Material material,
                                             PreviewSurfaceSample surface,
                                             Vector4 scale,
                                             string destTexturePath,
                                             string textureName,
                                             string textureOutput,
                                             ConversionType conversionType = ConversionType.None)
        {
            // We have to handle multiple cases here:
            // - file exists on disk
            //   - file is a supported format => can be directly copied
            //   - file is not in a supported format => need to blit / export
            // - file is only in memory
            //   - a Texture2D
            //   - a Texture
            //   - a RenderTexture
            //   - needs special care if marked as Normal Map
            //     (can probably only be detected in an Editor context, and heuristically at runtime)
            //   => need to blit / export
            // - file is not supported at all (or not yet)
            //   - a 3D texture
            //   => needs to be ignored, log Warning

            bool textureIsExported = false;

            string filePath = null;
            string fileName = null;

            var srcTexture2d = material.GetTexture(textureName);

            bool needsConversion = false;

            switch (conversionType)
            {
            case ConversionType.None:
                break;

            case ConversionType.UnpackNormal:
#if UNITY_EDITOR
                if (UnityEditor.AssetDatabase.Contains(srcTexture2d))
                {
                    // normal needs to be converted if the one on disk isn't really a normal map
                    // (e.g. created from greyscale)
                    UnityEditor.TextureImporter importer =
                        (UnityEditor.TextureImporter)UnityEditor.AssetImporter.GetAtPath(
                            UnityEditor.AssetDatabase.GetAssetPath(srcTexture2d));
                    if (importer.textureType != UnityEditor.TextureImporterType.NormalMap)
                    {
                        Debug.LogWarning("Texture " + textureName + " is set as NormalMap but isn't marked as such",
                                         srcTexture2d);
                    }

                    UnityEditor.TextureImporterSettings dst = new UnityEditor.TextureImporterSettings();
                    importer.ReadTextureSettings(dst);
                    // if this NormalMap is created from greyscale we will export the NormalMap from memory.
                    if (dst.convertToNormalMap)
                    {
                        needsConversion = true;
                        break;
                    }
                }
#endif
                break;

            default:
                needsConversion = true;
                break;
            }

#if UNITY_EDITOR
            // only export from disk if there's no need to do any type of data conversion here
            if (!needsConversion)
            {
                var srcPath = UnityEditor.AssetDatabase.GetAssetPath(srcTexture2d);

                if (!string.IsNullOrEmpty(srcPath))
                {
#if UNITY_2019_2_OR_GREATER
                    // Since textures might be inside of packages for various reasons we should support that.
                    // Usually this would just be "Path.GetFullPath(srcPath)", but USD export messes with the CWD (Working Directory)
                    // and so we have to do a bit more path wrangling here.
                    if (srcPath.StartsWith("Packages"))
                    {
                        var pi = UnityEditor.PackageManager.PackageInfo.FindForAssetPath(srcPath);
                        srcPath = pi.resolvedPath + srcPath.Substring(("Packages/" + pi.name).Length);
                    }
#endif
                    if (srcPath.StartsWith("Assets"))
                    {
                        srcPath = Application.dataPath + "/" + srcPath.Substring("Assets/".Length);
                    }

                    fileName = System.IO.Path.GetFileName(srcPath);
                    filePath = System.IO.Path.Combine(destTexturePath, fileName);

                    if (System.IO.File.Exists(srcPath))
                    {
                        // USDZ officially only supports png / jpg / jpeg
                        // https://graphics.pixar.com/usd/docs/Usdz-File-Format-Specification.html

                        var ext = System.IO.Path.GetExtension(srcPath).ToLowerInvariant();
                        if (ext == ".png" || ext == ".jpg" || ext == ".jpeg")
                        {
                            System.IO.File.Copy(srcPath, filePath, overwrite: true);
                            if (System.IO.File.Exists(filePath))
                            {
                                textureIsExported = true;
                            }
                        }
                    }
                }
            }
#endif

            if (!textureIsExported)
            {
                // Since this is a texture we can't directly export from disk, we need to blit it and output it as PNG.
                // To avoid collisions, e.g. with multiple different textures named the same, each texture gets a pseudo-random name.
                // This will also avoid collisions when exporting multiple models to the same folder, e.g. with a a RenderTexture called "RT"
                // in each of them that might look different between exports.
                // TODO Future work could, if necessary, generate a texture content hash to avoid exporting identical textures multiple times
                // (Unity's content hash isn't reliable for some types of textures unfortunately, e.g. RTs)
#if UNITY_EDITOR
                if (srcTexture2d is Texture2D)
                {
                    fileName = srcTexture2d.name + "_" + srcTexture2d.imageContentsHash.ToString();
                }
                else
                {
                    fileName = srcTexture2d.name + "_" + Random.Range(10000000, 99999999).ToString();
                }
#else
                fileName = srcTexture2d.name + "_" + Random.Range(10000000, 99999999).ToString();
#endif
                filePath = System.IO.Path.Combine(destTexturePath, fileName + ".png");

                // TODO extra care has to be taken of Normal Maps etc., since these are in a converted format in memory (for example 16 bit AG instead of 8 bit RGBA, depending on platform)
                // An example of this conversion in a shader is in Khronos' UnityGLTF implementation.
                // Basically, the blit has do be done with the right unlit conversion shader to get a proper "file-based" tangent space normal map back

                // Blit the texture and get it back to CPU
                // Note: Can't use RenderTexture.GetTemporary because that doesn't properly clear alpha channel
                bool preserveLinear = false;
                switch (conversionType)
                {
                case ConversionType.UnpackNormal:
                    preserveLinear = true;
                    break;
                }

                var rt = new RenderTexture(srcTexture2d.width, srcTexture2d.height, 0, RenderTextureFormat.ARGB32,
                                           preserveLinear ? RenderTextureReadWrite.Linear : RenderTextureReadWrite.Default);
                var resultTex2d = new Texture2D(srcTexture2d.width, srcTexture2d.height, TextureFormat.ARGB32, true,
                                                preserveLinear ? true : false);
                var activeRT = RenderTexture.active;
                try
                {
                    RenderTexture.active = rt;
                    GL.Clear(true, true, Color.clear);

                    // conversion material
                    if (_metalGlossChannelSwapMaterial == null)
                    {
                        _metalGlossChannelSwapMaterial = new Material(Shader.Find("Hidden/USD/ChannelCombiner"));
                    }

                    if (_normalChannelMaterial == null)
                    {
                        _normalChannelMaterial = new Material(Shader.Find("Hidden/USD/NormalChannel"));
                    }

                    _metalGlossChannelSwapMaterial.SetTexture("_R", srcTexture2d);
                    _metalGlossChannelSwapMaterial.SetTexture("_G", srcTexture2d);
                    _metalGlossChannelSwapMaterial.SetTexture("_B", srcTexture2d);
                    _metalGlossChannelSwapMaterial.SetTexture("_A", srcTexture2d);

                    switch (conversionType)
                    {
                    case ConversionType.None:
                        Graphics.Blit(srcTexture2d, rt);
                        break;

                    case ConversionType.SwapRASmoothnessToBGRoughness:
                        _metalGlossChannelSwapMaterial.SetVector("_Invert",
                                                                 new Vector4(0, 1, 0, 1)); // invert resulting g channel, make sure alpha is 1
                        _metalGlossChannelSwapMaterial.SetVector("_RScale", new Vector4(0, 0, 0, 0));
                        _metalGlossChannelSwapMaterial.SetVector("_GScale",
                                                                 new Vector4(0, 0, 0, 1)); // use a channel from _G texture for resulting g
                        _metalGlossChannelSwapMaterial.SetVector("_BScale",
                                                                 new Vector4(1, 0, 0, 0)); // use r channel from _B texture for resulting b
                        _metalGlossChannelSwapMaterial.SetVector("_AScale", new Vector4(0, 0, 0, 0));

                        Graphics.Blit(srcTexture2d, rt, _metalGlossChannelSwapMaterial);
                        break;

                    case ConversionType.InvertAlpha:
                        _metalGlossChannelSwapMaterial.SetVector("_Invert",
                                                                 new Vector4(0, 0, 0, 1)); // invert alpha result
                        _metalGlossChannelSwapMaterial.SetVector("_RScale",
                                                                 new Vector4(1, 0, 0, 0)); // use all color channels as-is
                        _metalGlossChannelSwapMaterial.SetVector("_GScale", new Vector4(0, 1, 0, 0));
                        _metalGlossChannelSwapMaterial.SetVector("_BScale", new Vector4(0, 0, 1, 0));
                        _metalGlossChannelSwapMaterial.SetVector("_AScale", new Vector4(0, 0, 0, 1));

                        Graphics.Blit(srcTexture2d, rt, _metalGlossChannelSwapMaterial);
                        break;

                    case ConversionType.MaskMapToORM:
                        // Input is RGBA (Metallic, Occlusion, Detail, Smoothness)
                        // Output is RGB1 (Occlusion, Roughness = 1 - Smoothness, Metallic, 1)
                        _metalGlossChannelSwapMaterial.SetVector("_Invert",
                                                                 new Vector4(0, 1, 0, 1)); // smoothness to roughness, solid alpha
                        _metalGlossChannelSwapMaterial.SetVector("_RScale", new Vector4(0, 1, 0, 0));
                        _metalGlossChannelSwapMaterial.SetVector("_GScale", new Vector4(0, 0, 0, 1));
                        _metalGlossChannelSwapMaterial.SetVector("_BScale", new Vector4(1, 0, 0, 0));
                        _metalGlossChannelSwapMaterial.SetVector("_AScale", new Vector4(0, 0, 0, 0));

                        Graphics.Blit(srcTexture2d, rt, _metalGlossChannelSwapMaterial);
                        break;

                    case ConversionType.UnpackNormal:
                        Graphics.Blit(srcTexture2d, rt, _normalChannelMaterial);
                        break;
                    }

                    resultTex2d.ReadPixels(new Rect(0, 0, srcTexture2d.width, srcTexture2d.height), 0, 0);
                    resultTex2d.Apply();

                    System.IO.File.WriteAllBytes(filePath, resultTex2d.EncodeToPNG());
                    if (System.IO.File.Exists(filePath))
                    {
                        textureIsExported = true;
                    }
                }
                finally
                {
                    RenderTexture.active = activeRT;
                    rt.Release();
                    GameObject.DestroyImmediate(rt);
                    GameObject.DestroyImmediate(resultTex2d);
                }
            }

            if (!textureIsExported)
            {
                var tmpTex2d = new Texture2D(1, 1, TextureFormat.ARGB32, true);
                try
                {
                    tmpTex2d.SetPixel(0, 0, Color.white);
                    tmpTex2d.Apply();
                    System.IO.File.WriteAllBytes(filePath, tmpTex2d.EncodeToPNG());
                    if (System.IO.File.Exists(filePath))
                    {
                        textureIsExported = true;
                    }
                }
                finally
                {
                    GameObject.DestroyImmediate(tmpTex2d);
                }
            }

            if (textureIsExported)
            {
                // Make file path baked into USD relative to scene file and use forward slashes.
                filePath = ImporterBase.MakeRelativePath(scene.FilePath, filePath);
                filePath = filePath.Replace("\\", "/");

                var uvReader = new PrimvarReaderSample <Vector2>();
                uvReader.varname.defaultValue = new TfToken("st");
                scene.Write(usdShaderPath + "/uvReader", uvReader);
                var usdTexReader = new TextureReaderSample(filePath, usdShaderPath + "/uvReader.outputs:result");
                usdTexReader.wrapS =
                    new Connectable <TextureReaderSample.WrapMode>(
                        TextureReaderSample.GetWrapMode(srcTexture2d.wrapModeU));
                usdTexReader.wrapT =
                    new Connectable <TextureReaderSample.WrapMode>(
                        TextureReaderSample.GetWrapMode(srcTexture2d.wrapModeV));
                if (scale != Vector4.one)
                {
                    usdTexReader.scale = new Connectable <Vector4>(scale);
                }

                // usdTexReader.isSRGB = new Connectable<TextureReaderSample.SRGBMode>(TextureReaderSample.SRGBMode.Auto);
                scene.Write(usdShaderPath + "/" + textureName, usdTexReader);
                return(usdShaderPath + "/" + textureName + ".outputs:" + textureOutput);
            }
            else
            {
                Debug.LogError(
                    "Texture wasn't exported: " + srcTexture2d.name + " (" + textureName + " from material " + material,
                    srcTexture2d);
                return(null);
            }
        }