/// <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); }
/// <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 }
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); }
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); } } }
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); } } }
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); }
/// <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); } }