summaryrefslogtreecommitdiffstats
path: root/impostor.cginc
diff options
context:
space:
mode:
authoryum <yum.food.vr@gmail.com>2026-01-14 23:26:14 -0800
committeryum <yum.food.vr@gmail.com>2026-01-14 23:26:14 -0800
commitd01a5d14765cb106327f805c642bc150f5414b3f (patch)
tree5fbc3a96dd8c61e76e3ae8f78f59514356492402 /impostor.cginc
parentd1eb208ecbeba1ab7bf894d9f14d2652739bc63e (diff)
Impostors: implement metallic gloss, normals
Diffstat (limited to 'impostor.cginc')
-rw-r--r--impostor.cginc80
1 files changed, 54 insertions, 26 deletions
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