diff options
| -rw-r--r-- | 3ner.cginc | 2 | ||||
| -rw-r--r-- | Scripts/Impostors.cs | 64 | ||||
| -rw-r--r-- | impostor.cginc | 80 | ||||
| -rw-r--r-- | pbr.cginc | 10 |
4 files changed, 107 insertions, 49 deletions
@@ -276,7 +276,7 @@ float4 frag(v2f i, uint facing : SV_IsFrontFace) : SV_Target { #if defined(_DEBUG_VIEW_UNLIT) return pbr.albedo; #elif defined(_DEBUG_VIEW_WORLD_SPACE_NORMALS) - return float4(i.normal, 1); + return float4((pbr.normal + 1.0f) * 0.5f, 1); #elif defined(_DEBUG_VIEW_METALLIC_GLOSS) return float4(pbr.metallic, pbr.smoothness, 0, 1); #endif diff --git a/Scripts/Impostors.cs b/Scripts/Impostors.cs index b82dc8f..30b06f6 100644 --- a/Scripts/Impostors.cs +++ b/Scripts/Impostors.cs @@ -131,13 +131,15 @@ public class Impostors : MonoBehaviour public string keyword; public Texture2D atlas; public bool isDepth; + public bool linear; - public BakePass(string name, string keyword, Texture2D atlas, bool isDepth = false) + public BakePass(string name, string keyword, Texture2D atlas, bool isDepth = false, bool linear = false) { this.name = name; this.keyword = keyword; this.atlas = atlas; this.isDepth = isDepth; + this.linear = linear; } } @@ -196,13 +198,14 @@ public class Impostors : MonoBehaviour } } - void ExecutePassesSequentially(BakePass[] passes, RenderTexture colorRT, RenderTexture depthOnlyRT, Material depthBlitMat, int passIndex = 0) + void ExecutePassesSequentially(BakePass[] passes, RenderTexture srgbRT, RenderTexture linearRT, RenderTexture depthOnlyRT, Material depthBlitMat, int passIndex = 0) { if (passIndex >= passes.Length) { // All passes complete RenderTexture.active = null; - RenderTexture.ReleaseTemporary(colorRT); + RenderTexture.ReleaseTemporary(srgbRT); + RenderTexture.ReleaseTemporary(linearRT); RenderTexture.ReleaseTemporary(depthOnlyRT); DestroyImmediate(depthBlitMat); @@ -216,9 +219,10 @@ public class Impostors : MonoBehaviour SetMaterialDebugKeyword(pass.keyword, true); UnityEditor.EditorApplication.delayCall += () => { + RenderTexture colorRT = pass.linear ? linearRT : srgbRT; RenderAtlasPass(pass.atlas, colorRT, depthOnlyRT, pass.isDepth ? depthBlitMat : null); SetMaterialDebugKeyword(pass.keyword, false); - ExecutePassesSequentially(passes, colorRT, depthOnlyRT, depthBlitMat, passIndex + 1); + ExecutePassesSequentially(passes, srgbRT, linearRT, depthOnlyRT, depthBlitMat, passIndex + 1); }; } @@ -235,14 +239,18 @@ public class Impostors : MonoBehaviour BakePass[] passes = new BakePass[] { new BakePass("albedo", "_DEBUG_VIEW_UNLIT", new Texture2D(size, size, TextureFormat.RGBA32, false)), - new BakePass("normals", "_DEBUG_VIEW_WORLD_SPACE_NORMALS", new Texture2D(size, size, TextureFormat.RGBA32, false)), - new BakePass("metallic/gloss", "_DEBUG_VIEW_METALLIC_GLOSS", new Texture2D(size, size, TextureFormat.RGBA32, false)), - new BakePass("depth", "", new Texture2D(size, size, TextureFormat.RFloat, false), true) + new BakePass("normals", "_DEBUG_VIEW_WORLD_SPACE_NORMALS", new Texture2D(size, size, TextureFormat.RGBA32, false), linear: true), + new BakePass("metallic/gloss", "_DEBUG_VIEW_METALLIC_GLOSS", new Texture2D(size, size, TextureFormat.RGBA32, false), linear: true), + new BakePass("depth", "", new Texture2D(size, size, TextureFormat.RFloat, false), isDepth: true) }; - RenderTextureDescriptor desc = new RenderTextureDescriptor(cameraResolution, cameraResolution, RenderTextureFormat.ARGB32, 24); - desc.sRGB = true; - RenderTexture colorRT = RenderTexture.GetTemporary(desc); + RenderTextureDescriptor srgbDesc = new RenderTextureDescriptor(cameraResolution, cameraResolution, RenderTextureFormat.ARGB32, 24); + srgbDesc.sRGB = true; + RenderTexture srgbRT = RenderTexture.GetTemporary(srgbDesc); + + RenderTextureDescriptor linearDesc = new RenderTextureDescriptor(cameraResolution, cameraResolution, RenderTextureFormat.ARGB32, 24); + linearDesc.sRGB = false; + RenderTexture linearRT = RenderTexture.GetTemporary(linearDesc); RenderTextureDescriptor depthDesc = new RenderTextureDescriptor(cameraResolution, cameraResolution, RenderTextureFormat.Depth, 24); RenderTexture depthOnlyRT = RenderTexture.GetTemporary(depthDesc); @@ -250,7 +258,7 @@ public class Impostors : MonoBehaviour // Ensure all debug keywords start disabled foreach (var pass in passes) SetMaterialDebugKeyword(pass.keyword, false); - ExecutePassesSequentially(passes, colorRT, depthOnlyRT, depthBlitMat); + ExecutePassesSequentially(passes, srgbRT, linearRT, depthOnlyRT, depthBlitMat); } struct TextureExportSettings @@ -262,9 +270,11 @@ public class Impostors : MonoBehaviour public FilterMode filter; public bool alphaTransparency; public bool uncompressed; + public bool isNormalMap; public TextureExportSettings(string suffix, bool isEXR = false, bool mipmaps = true, bool sRGB = true, - FilterMode filter = FilterMode.Trilinear, bool alphaTransparency = false, bool uncompressed = false) + FilterMode filter = FilterMode.Trilinear, bool alphaTransparency = false, + bool uncompressed = false, bool isNormalMap = false) { this.suffix = suffix; this.isEXR = isEXR; @@ -273,6 +283,7 @@ public class Impostors : MonoBehaviour this.filter = filter; this.alphaTransparency = alphaTransparency; this.uncompressed = uncompressed; + this.isNormalMap = isNormalMap; } } @@ -289,13 +300,16 @@ public class Impostors : MonoBehaviour TextureImporter importer = AssetImporter.GetAtPath(path) as TextureImporter; if (importer != null) { + if (settings.isNormalMap) importer.textureType = TextureImporterType.NormalMap; importer.mipmapEnabled = settings.mipmaps; importer.sRGBTexture = settings.sRGB; importer.wrapMode = TextureWrapMode.Clamp; importer.filterMode = settings.filter; if (settings.alphaTransparency) importer.alphaIsTransparency = true; if (settings.uncompressed) importer.textureCompression = TextureImporterCompression.Uncompressed; + EditorUtility.SetDirty(importer); importer.SaveAndReimport(); + AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceSynchronousImport); } } @@ -310,24 +324,36 @@ public class Impostors : MonoBehaviour string baseName = gameObject.name.Replace(" ", "_"); - var exportSettings = new (Texture2D atlas, TextureExportSettings settings, string materialProp)[] + var exportSettings = new (TextureExportSettings settings, string materialProp)[] { - (albedoAtlas, new TextureExportSettings("albedo", mipmaps: true, sRGB: true, alphaTransparency: true), "_Impostors_Atlas"), - (normalAtlas, new TextureExportSettings("normal", mipmaps: true, sRGB: false), "_Impostors_Normal_Atlas"), - (metallicGlossAtlas, new TextureExportSettings("metallic_gloss", mipmaps: true, sRGB: false), "_Impostors_Metallic_Gloss_Atlas"), - (depthAtlas, new TextureExportSettings("depth", isEXR: true, mipmaps: false, sRGB: false, filter: FilterMode.Bilinear, uncompressed: true), "_Impostors_Depth_Atlas") + (new TextureExportSettings("albedo", mipmaps: true, sRGB: true, alphaTransparency: true), "_Impostors_Atlas"), + (new TextureExportSettings("normal", mipmaps: true, sRGB: false), "_Impostors_Normal_Atlas"), + (new TextureExportSettings("metallic_gloss", mipmaps: true, sRGB: false), "_Impostors_Metallic_Gloss_Atlas"), + (new TextureExportSettings("depth", isEXR: true, mipmaps: false, sRGB: false, filter: FilterMode.Bilinear, uncompressed: true), "_Impostors_Depth_Atlas") }; + Texture2D[] atlases = { albedoAtlas, normalAtlas, metallicGlossAtlas, depthAtlas }; string[] paths = new string[exportSettings.Length]; for (int i = 0; i < exportSettings.Length; i++) - SaveAndConfigureTexture(exportSettings[i].atlas, exportSettings[i].settings, baseName, out paths[i]); + SaveAndConfigureTexture(atlases[i], exportSettings[i].settings, baseName, out paths[i]); AssetDatabase.Refresh(); for (int i = 0; i < paths.Length; i++) ConfigureTextureImporter(paths[i], exportSettings[i].settings); - // Create impostor + // Wait for shader compiler then create impostor + WaitForCompilerThenCreateImpostor(paths, exportSettings, baseName); + } + + void WaitForCompilerThenCreateImpostor(string[] paths, (TextureExportSettings settings, string materialProp)[] exportSettings, string baseName) + { + if (EditorApplication.isCompiling) + { + EditorApplication.delayCall += () => WaitForCompilerThenCreateImpostor(paths, exportSettings, baseName); + return; + } + Texture2D[] textures = new Texture2D[paths.Length]; for (int i = 0; i < paths.Length; i++) textures[i] = AssetDatabase.LoadAssetAtPath<Texture2D>(paths[i]); diff --git a/impostor.cginc b/impostor.cginc index 1d5c9b5..f271612 100644 --- a/impostor.cginc +++ b/impostor.cginc @@ -73,14 +73,41 @@ float2 ClampUvInCell(float2 uv) { return clamp(uv, halfTexelInCell, 1.0 - halfTexelInCell); } -float4 SampleAtlasGrad(float2 uv, float2 cell, float2 uvGradX, float2 uvGradY) { +struct ImpostorSample { + float4 albedo; + float4 normal; + float4 metallicGloss; +}; + +struct ImpostorResult { + float4 albedo; + float3 normal; + float metallic; + float smoothness; +}; + +ImpostorSample SampleImpostorCell(float2 cell, float3 frameDir, float3 pivotToCamOS, float3 vertexToCamOS, float gridRes) { + float2 uv = VirtualPlaneUV(frameDir, pivotToCamOS, vertexToCamOS); uv = ClampUvInCell(uv); - float invGridRes = rcp((float)_Impostors_Grid_Resolution); + float invGridRes = rcp(gridRes); float2 atlasUv = (cell + uv) * invGridRes; + float2 gradX = ddx(uv) * invGridRes; + float2 gradY = ddy(uv) * invGridRes; + + ImpostorSample s; + s.albedo = _Impostors_Atlas.SampleGrad(bilinear_clamp_s, atlasUv, gradX, gradY); + s.normal = _Impostors_Normal_Atlas.SampleGrad(bilinear_clamp_s, atlasUv, gradX, gradY); + s.metallicGloss = _Impostors_Metallic_Gloss_Atlas.SampleGrad(bilinear_clamp_s, atlasUv, gradX, gradY).xzzy; + return s; +} - // Important: gradients must be computed in-cell; do not let integer cell offsets affect mip selection. - return _Impostors_Atlas.SampleGrad(bilinear_clamp_s, atlasUv, uvGradX * invGridRes, uvGradY * invGridRes); +ImpostorSample BlendImpostorSamples(ImpostorSample s00, ImpostorSample s01, ImpostorSample s10, ImpostorSample s11, float4 bw) { + ImpostorSample result; + result.albedo = s00.albedo * bw.x + s01.albedo * bw.y + s10.albedo * bw.z + s11.albedo * bw.w; + result.normal = s00.normal * bw.x + s01.normal * bw.y + s10.normal * bw.z + s11.normal * bw.w; + result.metallicGloss = s00.metallicGloss * bw.x + s01.metallicGloss * bw.y + s10.metallicGloss * bw.z + s11.metallicGloss * bw.w; + return result; } // Billboard vertex transformation for impostors @@ -106,7 +133,9 @@ void impostor_vert(float4 vertexOS, inout float3 worldPos) { } // Sample impostor atlas with view-dependent blending -float4 impostor_frag(float3 worldPos) { +ImpostorResult impostor_frag(float3 worldPos) { + ImpostorResult result = (ImpostorResult)0; + // Calculate center in fragment shader to avoid extra interpolator float3 center = mul(unity_ObjectToWorld, float4(0,0,0,1)).xyz; @@ -139,34 +168,33 @@ float4 impostor_frag(float3 worldPos) { float2 cell10 = clamp(gridFloor + float2(1,0), 0, gridRes - 1); float2 cell11 = clamp(gridFloor + float2(1,1), 0, gridRes - 1); - // Get directions for each frame - float3 dir00 = DirFromCell(cell00, gridRes); - float3 dir01 = DirFromCell(cell01, gridRes); - float3 dir10 = DirFromCell(cell10, gridRes); - float3 dir11 = DirFromCell(cell11, gridRes); - - // Compute virtual plane UVs for all 4 frames + // Compute shared vectors for virtual plane UV calculation float3 pivotToCamOS = mul(worldToObject, camPos - center); float3 vertexPosOS = mul(worldToObject, worldPos - center); float3 vertexToCamOS = pivotToCamOS - vertexPosOS; - float2 uv00 = VirtualPlaneUV(dir00, pivotToCamOS, vertexToCamOS); - float2 uv01 = VirtualPlaneUV(dir01, pivotToCamOS, vertexToCamOS); - float2 uv10 = VirtualPlaneUV(dir10, pivotToCamOS, vertexToCamOS); - float2 uv11 = VirtualPlaneUV(dir11, pivotToCamOS, vertexToCamOS); + // Sample all atlases for each frame cell + ImpostorSample s00 = SampleImpostorCell(cell00, DirFromCell(cell00, gridRes), pivotToCamOS, vertexToCamOS, gridRes); + ImpostorSample s01 = SampleImpostorCell(cell01, DirFromCell(cell01, gridRes), pivotToCamOS, vertexToCamOS, gridRes); + ImpostorSample s10 = SampleImpostorCell(cell10, DirFromCell(cell10, gridRes), pivotToCamOS, vertexToCamOS, gridRes); + ImpostorSample s11 = SampleImpostorCell(cell11, DirFromCell(cell11, gridRes), pivotToCamOS, vertexToCamOS, gridRes); + + // Blend all samples + ImpostorSample blended = BlendImpostorSamples(s00, s01, s10, s11, bw); + + if (_Impostors_Debug_Mode > 0.5) { + result.albedo = float4(bw.yz, 0, 1); + return result; + } - // Sample and blend frames - float4 s00 = SampleAtlasGrad(uv00, cell00, ddx(uv00), ddy(uv00)); - float4 s01 = SampleAtlasGrad(uv01, cell01, ddx(uv01), ddy(uv01)); - float4 s10 = SampleAtlasGrad(uv10, cell10, ddx(uv10), ddy(uv10)); - float4 s11 = SampleAtlasGrad(uv11, cell11, ddx(uv11), ddy(uv11)); - float4 col = s00 * bw.x + s01 * bw.y + s10 * bw.z + s11 * bw.w; + clip(blended.albedo.a - _Impostors_Cutoff); - if (_Impostors_Debug_Mode > 0.5) - return float4(bw.yz, 0, 1); + result.albedo = blended.albedo; + result.normal = normalize(blended.normal.xyz * 2.0 - 1.0); + result.metallic = blended.metallicGloss.r; + result.smoothness = blended.metallicGloss.a; - clip(col.a - _Impostors_Cutoff); - return col; + return result; } #endif // _IMPOSTORS @@ -161,13 +161,15 @@ Pbr getPbr(v2f i) { #endif // _PARALLAX_HEIGHTMAP #if defined(_IMPOSTORS) - pbr.albedo = impostor_frag(i.worldPos); - pbr.albedo *= _Color; + ImpostorResult imp = impostor_frag(i.worldPos); + pbr.albedo = imp.albedo * _Color; + pbr.normal = imp.normal; + pbr.smoothness = imp.smoothness; + pbr.metallic = imp.metallic * _Metallic; #else pbr.albedo = _MainTex.Sample(aniso16_trilinear_repeat_s, uv_parallax * _MainTex_ST.xy + _MainTex_ST.zw); pbr.albedo *= _Color; apply_marble(i.worldPos, pbr.albedo.xyz); -#endif float3 normal_tangent = UnpackNormal(_BumpMap.Sample(aniso16_trilinear_repeat_s, uv_parallax * _BumpMap_ST.xy)); normal_tangent.xy *= _BumpScale; @@ -186,6 +188,8 @@ Pbr getPbr(v2f i) { float4 metallic_gloss = _MetallicGlossMap.Sample(aniso16_trilinear_repeat_s, uv_parallax * _MetallicGlossMap_ST.xy); pbr.smoothness = metallic_gloss.a * _Glossiness; pbr.metallic = metallic_gloss.r * _Metallic; +#endif // _IMPOSTORS + #if defined(_CLEARCOAT) pbr.cc_roughness = _Clearcoat_Roughness; pbr.cc_strength = _Clearcoat_Strength; |
