diff options
| author | yum <yum.food.vr@gmail.com> | 2026-01-14 23:26:14 -0800 |
|---|---|---|
| committer | yum <yum.food.vr@gmail.com> | 2026-01-14 23:26:14 -0800 |
| commit | d01a5d14765cb106327f805c642bc150f5414b3f (patch) | |
| tree | 5fbc3a96dd8c61e76e3ae8f78f59514356492402 /impostor.cginc | |
| parent | d1eb208ecbeba1ab7bf894d9f14d2652739bc63e (diff) | |
Impostors: implement metallic gloss, normals
Diffstat (limited to 'impostor.cginc')
| -rw-r--r-- | impostor.cginc | 80 |
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 |
