From dae24c765c5afa521016526a78fe021807604df1 Mon Sep 17 00:00:00 2001 From: pfcDorn <> Date: Fri, 12 Jan 2024 13:47:48 +0100 Subject: [PATCH] for editor import: convert normal maps to dxt5nm when its enabled in project settings --- .../SceneImporter/ImporterMaterials.cs | 42 +++++++++------- .../Scripts/SceneImporter/ImporterTextures.cs | 35 +++++++++---- .../NormalMapEncodingConverter.cs | 50 +++++++++++++++++++ .../NormalMapEncodingConverter.cs.meta | 3 ++ 4 files changed, 104 insertions(+), 26 deletions(-) create mode 100644 Runtime/Scripts/SceneImporter/NormalMapEncodingConverter.cs create mode 100644 Runtime/Scripts/SceneImporter/NormalMapEncodingConverter.cs.meta diff --git a/Runtime/Scripts/SceneImporter/ImporterMaterials.cs b/Runtime/Scripts/SceneImporter/ImporterMaterials.cs index 9fc90aa4f..1633f6133 100644 --- a/Runtime/Scripts/SceneImporter/ImporterMaterials.cs +++ b/Runtime/Scripts/SceneImporter/ImporterMaterials.cs @@ -11,6 +11,8 @@ namespace UnityGLTF { public partial class GLTFSceneImporter { + internal static List _runtimeNormalTextures = new List(); + protected virtual async Task ConstructMaterial(GLTFMaterial def, int materialIndex) { IUniformMap mapper; @@ -116,7 +118,7 @@ void SetTransformKeyword() if (pbr.BaseColorTexture != null) { TextureId textureId = pbr.BaseColorTexture.Index; - await ConstructTexture(textureId.Value, textureId.Id, !KeepCPUCopyOfTexture, false); + await ConstructTexture(textureId.Value, textureId.Id, !KeepCPUCopyOfTexture, false, false); mrMapper.BaseColorTexture = _assetCache.TextureCache[textureId.Id].Texture; mrMapper.BaseColorTexCoord = pbr.BaseColorTexture.TexCoord; @@ -145,7 +147,7 @@ void SetTransformKeyword() if (pbr.MetallicRoughnessTexture != null) { TextureId textureId = pbr.MetallicRoughnessTexture.Index; - await ConstructTexture(textureId.Value, textureId.Id, !KeepCPUCopyOfTexture, true); + await ConstructTexture(textureId.Value, textureId.Id, !KeepCPUCopyOfTexture, true, false); mrMapper.MetallicRoughnessTexture = _assetCache.TextureCache[textureId.Id].Texture; mrMapper.MetallicRoughnessTexCoord = pbr.MetallicRoughnessTexture.TexCoord; @@ -197,7 +199,7 @@ void SetTransformKeyword() if (specGloss.DiffuseTexture != null) { TextureId textureId = specGloss.DiffuseTexture.Index; - await ConstructTexture(textureId.Value, textureId.Id, !KeepCPUCopyOfTexture, false); + await ConstructTexture(textureId.Value, textureId.Id, !KeepCPUCopyOfTexture, false, false); sgMapper.DiffuseTexture = _assetCache.TextureCache[textureId.Id].Texture; sgMapper.DiffuseTexCoord = specGloss.DiffuseTexture.TexCoord; @@ -226,7 +228,7 @@ void SetTransformKeyword() if (specGloss.SpecularGlossinessTexture != null) { TextureId textureId = specGloss.SpecularGlossinessTexture.Index; - await ConstructTexture(textureId.Value, textureId.Id, !KeepCPUCopyOfTexture, false); + await ConstructTexture(textureId.Value, textureId.Id, !KeepCPUCopyOfTexture, false, false); sgMapper.SpecularGlossinessTexture = _assetCache.TextureCache[textureId.Id].Texture; sgMapper.SpecularGlossinessTexCoord = specGloss.SpecularGlossinessTexture.TexCoord; @@ -258,7 +260,7 @@ void SetTransformKeyword() if (pbr.BaseColorTexture != null) { TextureId textureId = pbr.BaseColorTexture.Index; - await ConstructTexture(textureId.Value, textureId.Id, !KeepCPUCopyOfTexture, false); + await ConstructTexture(textureId.Value, textureId.Id, !KeepCPUCopyOfTexture, false, false); unlitMapper.BaseColorTexture = _assetCache.TextureCache[textureId.Id].Texture; unlitMapper.BaseColorTexCoord = pbr.BaseColorTexture.TexCoord; @@ -301,7 +303,7 @@ void SetTransformKeyword() if (transmission.transmissionTexture != null) { - var td = await FromTextureInfo(transmission.transmissionTexture); + var td = await FromTextureInfo(transmission.transmissionTexture, false); transmissionMapper.TransmissionTexture = td.Texture; transmissionMapper.TransmissionTextureTexCoord = td.TexCoord; var ext = GetTextureTransform(transmission.transmissionTexture); @@ -339,7 +341,7 @@ void SetTransformKeyword() volumeMapper.ThicknessFactor = volume.thicknessFactor; if (volume.thicknessTexture != null) { - var td = await FromTextureInfo(volume.thicknessTexture); + var td = await FromTextureInfo(volume.thicknessTexture, false); volumeMapper.ThicknessTexture = td.Texture; volumeMapper.ThicknessTextureTexCoord = td.TexCoord; var ext = GetTextureTransform(volume.thicknessTexture); @@ -377,7 +379,7 @@ void SetTransformKeyword() iridescenceMapper.IridescenceThicknessMaximum = iridescence.iridescenceThicknessMaximum; if (iridescence.iridescenceTexture != null) { - var td = await FromTextureInfo(iridescence.iridescenceTexture); + var td = await FromTextureInfo(iridescence.iridescenceTexture, false); iridescenceMapper.IridescenceTexture = td.Texture; iridescenceMapper.IridescenceTextureTexCoord = td.TexCoord; var ext = GetTextureTransform(iridescence.iridescenceTexture); @@ -400,7 +402,7 @@ void SetTransformKeyword() if (iridescence.iridescenceThicknessTexture != null) { - var td2 = await FromTextureInfo(iridescence.iridescenceThicknessTexture); + var td2 = await FromTextureInfo(iridescence.iridescenceThicknessTexture, false); iridescenceMapper.IridescenceThicknessTexture = td2.Texture; iridescenceMapper.IridescenceThicknessTextureTexCoord = td2.TexCoord; var ext2 = GetTextureTransform(iridescence.iridescenceThicknessTexture); @@ -436,7 +438,7 @@ void SetTransformKeyword() specularMapper.SpecularColorFactor = specular.specularColorFactor.ToUnityColorLinear(); if (specular.specularTexture != null) { - var td = await FromTextureInfo(specular.specularTexture); + var td = await FromTextureInfo(specular.specularTexture, false); specularMapper.SpecularTexture = td.Texture; specularMapper.SpecularTextureTexCoord = td.TexCoord; var ext = GetTextureTransform(specular.specularTexture); @@ -460,7 +462,7 @@ void SetTransformKeyword() if (specular.specularColorTexture != null) { - var td2 = await FromTextureInfo(specular.specularColorTexture); + var td2 = await FromTextureInfo(specular.specularColorTexture, false); specularMapper.SpecularColorTexture = td2.Texture; specularMapper.SpecularColorTextureTexCoord = td2.TexCoord; var ext2 = GetTextureTransform(specular.specularColorTexture); @@ -496,7 +498,7 @@ void SetTransformKeyword() clearcoatMapper.ClearcoatRoughnessFactor = clearcoat.clearcoatRoughnessFactor; if (clearcoat.clearcoatTexture != null) { - var td = await FromTextureInfo(clearcoat.clearcoatTexture); + var td = await FromTextureInfo(clearcoat.clearcoatTexture, false); clearcoatMapper.ClearcoatTexture = td.Texture; clearcoatMapper.ClearcoatTextureTexCoord = td.TexCoord; var ext = GetTextureTransform(clearcoat.clearcoatTexture); @@ -520,7 +522,7 @@ void SetTransformKeyword() if (clearcoat.clearcoatRoughnessTexture != null) { - var td = await FromTextureInfo(clearcoat.clearcoatRoughnessTexture); + var td = await FromTextureInfo(clearcoat.clearcoatRoughnessTexture, false); clearcoatMapper.ClearcoatRoughnessTexture = td.Texture; clearcoatMapper.ClearcoatRoughnessTextureTexCoord = td.TexCoord; var ext = GetTextureTransform(clearcoat.clearcoatRoughnessTexture); @@ -548,7 +550,10 @@ void SetTransformKeyword() { if (clearcoat.clearcoatNormalTexture != null) { - var td = await FromTextureInfo(clearcoat.clearcoatNormalTexture); + var td = await FromTextureInfo(clearcoat.clearcoatNormalTexture, false); + + _runtimeNormalTextures.Add(td.Texture); + clearcoatNormalMapper.ClearcoatNormalTexture = td.Texture; clearcoatNormalMapper.ClearcoatNormalTextureTexCoord = td.TexCoord; var ext = GetTextureTransform(clearcoat.clearcoatNormalTexture); @@ -581,11 +586,14 @@ void SetTransformKeyword() if (def.NormalTexture != null) { TextureId textureId = def.NormalTexture.Index; - await ConstructTexture(textureId.Value, textureId.Id, !KeepCPUCopyOfTexture, true); + await ConstructTexture(textureId.Value, textureId.Id, !KeepCPUCopyOfTexture, true, true); + uniformMapper.NormalTexture = _assetCache.TextureCache[textureId.Id].Texture; uniformMapper.NormalTexCoord = def.NormalTexture.TexCoord; uniformMapper.NormalTexScale = def.NormalTexture.Scale; + _runtimeNormalTextures.Add(uniformMapper.NormalTexture); + var ext = GetTextureTransform(def.NormalTexture); if (ext != null) { @@ -607,7 +615,7 @@ void SetTransformKeyword() if (def.EmissiveTexture != null) { TextureId textureId = def.EmissiveTexture.Index; - await ConstructTexture(textureId.Value, textureId.Id, !KeepCPUCopyOfTexture, false); + await ConstructTexture(textureId.Value, textureId.Id, !KeepCPUCopyOfTexture, false, false); uniformMapper.EmissiveTexture = _assetCache.TextureCache[textureId.Id].Texture; uniformMapper.EmissiveTexCoord = def.EmissiveTexture.TexCoord; @@ -633,7 +641,7 @@ void SetTransformKeyword() { uniformMapper.OcclusionTexStrength = def.OcclusionTexture.Strength; TextureId textureId = def.OcclusionTexture.Index; - await ConstructTexture(textureId.Value, textureId.Id, !KeepCPUCopyOfTexture, true); + await ConstructTexture(textureId.Value, textureId.Id, !KeepCPUCopyOfTexture, true, false); uniformMapper.OcclusionTexture = _assetCache.TextureCache[textureId.Id].Texture; uniformMapper.OcclusionTexCoord = def.OcclusionTexture.TexCoord; diff --git a/Runtime/Scripts/SceneImporter/ImporterTextures.cs b/Runtime/Scripts/SceneImporter/ImporterTextures.cs index 90cf6dd95..cbbff5d7e 100644 --- a/Runtime/Scripts/SceneImporter/ImporterTextures.cs +++ b/Runtime/Scripts/SceneImporter/ImporterTextures.cs @@ -36,17 +36,17 @@ private async Task CreateNotReferencedTexture(int index) && string.IsNullOrEmpty(Root.Textures[index].Source.Value.Uri)) { await ConstructImageBuffer(Root.Textures[index], index); - await ConstructTexture(Root.Textures[index], index, !KeepCPUCopyOfTexture, true); + await ConstructTexture(Root.Textures[index], index, !KeepCPUCopyOfTexture, true, false); } } - private async Task FromTextureInfo(TextureInfo textureInfo) + private async Task FromTextureInfo(TextureInfo textureInfo, bool isNormal) { var result = new TextureData(); if (textureInfo?.Index?.Value == null) return result; TextureId textureId = textureInfo.Index; - await ConstructTexture(textureId.Value, textureId.Id, !KeepCPUCopyOfTexture, true); + await ConstructTexture(textureId.Value, textureId.Id, !KeepCPUCopyOfTexture, true, isNormal); result.Texture = _assetCache.TextureCache[textureId.Id].Texture; result.TexCoord = textureInfo.TexCoord; @@ -67,7 +67,7 @@ private async Task FromTextureInfo(TextureInfo textureInfo) return result; } - protected async Task ConstructImage(GLTFImage image, int imageCacheIndex, bool markGpuOnly, bool isLinear) + protected async Task ConstructImage(GLTFImage image, int imageCacheIndex, bool markGpuOnly, bool isLinear, bool isNormal) { if (_assetCache.InvalidImageCache[imageCacheIndex]) return; @@ -101,7 +101,7 @@ protected async Task ConstructImage(GLTFImage image, int imageCacheIndex, bool m } await YieldOnTimeoutAndThrowOnLowMemory(); - await ConstructUnityTexture(stream, markGpuOnly, isLinear, image, imageCacheIndex); + await ConstructUnityTexture(stream, markGpuOnly, isLinear, isNormal, image, imageCacheIndex); } } @@ -195,7 +195,7 @@ async Task CheckMimeTypeAndLoadImage(GLTFImage image, Texture2D textu return texture; } - protected virtual async Task ConstructUnityTexture(Stream stream, bool markGpuOnly, bool isLinear, GLTFImage image, int imageCacheIndex) + protected virtual async Task ConstructUnityTexture(Stream stream, bool markGpuOnly, bool isLinear, bool isNormal, GLTFImage image, int imageCacheIndex) { #if UNITY_EDITOR if (stream is AssetDatabaseStream assetDatabaseStream) @@ -206,6 +206,17 @@ protected virtual async Task ConstructUnityTexture(Stream stream, bool markGpuOn _assetCache.ImageCache[imageCacheIndex] = tx; return; } + + bool convertToDxt5nmFormat = false; + if (isNormal && Context.SourceImporter != null) + { + BuildTargetGroup activeTargetGroup = BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget); + if (PlayerSettings.GetNormalMapEncoding(activeTargetGroup) == NormalMapEncoding.DXT5nm) + { + convertToDxt5nmFormat = true; + } + } + #endif Texture2D texture = new Texture2D(4, 4, TextureFormat.RGBA32, GenerateMipMapsForTextures, isLinear); texture.name = string.IsNullOrEmpty(image.Name) ? Path.GetFileNameWithoutExtension(image.Uri) : image.Name; @@ -277,6 +288,12 @@ protected virtual async Task ConstructUnityTexture(Stream stream, bool markGpuOn texture = await CheckMimeTypeAndLoadImage(image, texture, buffer, markGpuOnly); } + if (texture && convertToDxt5nmFormat) + { + await NormalMapEncodingConverter.ConvertToDxt5nmAsync(texture); + texture.Apply(); + } + if (!texture) _assetCache.InvalidImageCache[imageCacheIndex] = newTextureObject; @@ -346,7 +363,7 @@ public virtual async Task LoadTextureAsync(GLTFTexture texture, int textureIndex } await ConstructImageBuffer(texture, textureIndex); - await ConstructTexture(texture, textureIndex, markGpuOnly, isLinear); + await ConstructTexture(texture, textureIndex, markGpuOnly, isLinear, false); } finally { @@ -383,13 +400,13 @@ public virtual Texture GetTexture(int textureIndex) return _assetCache.TextureCache[textureIndex].Texture; } - protected virtual async Task ConstructTexture(GLTFTexture texture, int textureIndex, bool markGpuOnly, bool isLinear) + protected virtual async Task ConstructTexture(GLTFTexture texture, int textureIndex, bool markGpuOnly, bool isLinear, bool isNormal) { if (_assetCache.TextureCache[textureIndex].Texture == null) { int sourceId = GetTextureSourceId(texture); GLTFImage image = _gltfRoot.Images[sourceId]; - await ConstructImage(image, sourceId, markGpuOnly, isLinear); + await ConstructImage(image, sourceId, markGpuOnly, isLinear, isNormal); var source = _assetCache.ImageCache[sourceId]; if (!source) return; diff --git a/Runtime/Scripts/SceneImporter/NormalMapEncodingConverter.cs b/Runtime/Scripts/SceneImporter/NormalMapEncodingConverter.cs new file mode 100644 index 000000000..a3f40d2e8 --- /dev/null +++ b/Runtime/Scripts/SceneImporter/NormalMapEncodingConverter.cs @@ -0,0 +1,50 @@ +using System.Threading.Tasks; +using UnityEngine; + +namespace UnityGLTF +{ + public static class NormalMapEncodingConverter + { + public static Texture2D ConvertToDxt5nm(Texture2D source) + { + var dest = new Texture2D(source.width, source.height, TextureFormat.DXT5, false); + var pixels = source.GetPixels(); + for (var i = 0; i < pixels.Length; i++) + { + var c = pixels[i]; + pixels[i] = new Color(1, c.g, 1, c.r); + } + + dest.SetPixels(pixels); + return dest; + } + + public static void ConvertToDxt5nm(Texture2D source, Texture2D dest) + { + var pixels = source.GetPixels(); + for (var i = 0; i < pixels.Length; i++) + { + var c = pixels[i]; + pixels[i] = new Color(1, c.g, 1, c.r); + } + + dest.SetPixels(pixels); + } + + public static async Task ConvertToDxt5nmAsync(Texture2D texture) + { + var pixels = texture.GetPixels(); + await Task.Run(() => + { + for (var i = 0; i < pixels.Length; i++) + { + var c = pixels[i]; + pixels[i] = new Color(1, c.g, 1, c.r); + } + }); + + texture.SetPixels(pixels); + } + + } +} \ No newline at end of file diff --git a/Runtime/Scripts/SceneImporter/NormalMapEncodingConverter.cs.meta b/Runtime/Scripts/SceneImporter/NormalMapEncodingConverter.cs.meta new file mode 100644 index 000000000..3d0a3b57f --- /dev/null +++ b/Runtime/Scripts/SceneImporter/NormalMapEncodingConverter.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 870ecf89bfc64980a38e2977a56943bb +timeCreated: 1705055769 \ No newline at end of file