summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--3ner.cginc2
-rw-r--r--Scripts/Impostors.cs64
-rw-r--r--impostor.cginc80
-rw-r--r--pbr.cginc10
4 files changed, 107 insertions, 49 deletions
diff --git a/3ner.cginc b/3ner.cginc
index 9b73a53..2452262 100644
--- a/3ner.cginc
+++ b/3ner.cginc
@@ -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
diff --git a/pbr.cginc b/pbr.cginc
index 8a611d4..a1df361 100644
--- a/pbr.cginc
+++ b/pbr.cginc
@@ -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;