diff options
| author | yum <yum.food.vr@gmail.com> | 2026-01-16 15:35:54 -0800 |
|---|---|---|
| committer | yum <yum.food.vr@gmail.com> | 2026-01-16 15:35:54 -0800 |
| commit | 02c32fcc30e753da96f0aa072ed1d74ca300979c (patch) | |
| tree | a580f5ec83ea23ec3b6b1c5e9c94266e531bb9e6 /impostor.cginc | |
| parent | 5731b075b2ffa40b4f059a01ec0c105e681bf43e (diff) | |
Impostors: fix bounding sphere scale
Diffstat (limited to 'impostor.cginc')
| -rw-r--r-- | impostor.cginc | 73 |
1 files changed, 54 insertions, 19 deletions
diff --git a/impostor.cginc b/impostor.cginc index 8cf306f..b49dfce 100644 --- a/impostor.cginc +++ b/impostor.cginc @@ -84,6 +84,7 @@ struct ImpostorResult { float3 normal; float metallic; float smoothness; + float3 objPos; }; float SampleImpostorDepthCell(float2 cell, float2 uvInCell, float gridRes) { @@ -134,6 +135,23 @@ float2 ImpostorParallaxOffsetForFrame(float3 frameDir, float3 pivotToCamOS, floa return (planeCoord - camXY) * (zSurface / camZ); } +// Reconstruct object space position from frame UV and depth. +// UV encodes X,Y on the virtual plane (0.5 = center), depth encodes Z (0.5 = center). +// The baked orthographic view spans [-Radius, Radius] in each axis. +float3 ReconstructObjPosFromFrame(float3 frameDir, float2 uv, float depth) { + float3 planeX, planeY, planeN; + FrameBasis(frameDir, planeX, planeY, planeN); + + // Invert VirtualPlaneUV: offset = 0.5 - uv, scale by diameter + float2 offsetXY = (0.5 - uv) * 2.0 * _Impostors_Sphere_Radius; + + // Depth 0 = front (toward camera), 0.5 = center, 1 = back (away from camera) + // planeN points toward camera, so positive Z = toward camera + float offsetZ = (0.5 - depth) * 2.0 * _Impostors_Sphere_Radius; + + return offsetXY.x * planeX + offsetXY.y * planeY + offsetZ * planeN; +} + ImpostorSample BlendImpostorSamples(ImpostorSample s0, ImpostorSample s1, ImpostorSample s2, float3 bw) { ImpostorSample result; float3 alpha = float3(s0.albedo.a, s1.albedo.a, s2.albedo.a); @@ -155,25 +173,22 @@ ImpostorSample BlendImpostorSamples(ImpostorSample s0, ImpostorSample s1, Impost } // Billboard vertex transformation for impostors -void impostor_vert(float4 vertexOS, inout float3 worldPos) { +void impostor_vert(inout float3 vertexOS) { float3 center = mul(unity_ObjectToWorld, float4(0,0,0,1)).xyz; - float3 scale = float3( - length(unity_ObjectToWorld._m00_m10_m20), - length(unity_ObjectToWorld._m01_m11_m21), - length(unity_ObjectToWorld._m02_m12_m22)); - #ifdef SHADOW_CASTER_PASS float3 camPos = _Impostors_Main_Camera_Pos; #else float3 camPos = _WorldSpaceCameraPos; #endif - // Billboard facing the camera direction + // Billboard facing the camera direction (world space, then convert back to object space). float3 viewWS = normalize(camPos - center); float3 right, up; BillboardBasis(viewWS, right, up); - worldPos = center + vertexOS.x * right * scale.x + vertexOS.y * up * scale.y; + float radiusScale = _Impostors_Sphere_Radius * 2.0; + float3 worldPos = center + vertexOS.x * right * radiusScale + vertexOS.y * up * radiusScale; + vertexOS = mul(unity_WorldToObject, float4(worldPos, 1)).xyz; } // Sample impostor atlas with view-dependent blending @@ -191,11 +206,7 @@ ImpostorResult impostor_frag(float3 worldPos) { #endif float3 viewDir = normalize(worldPos - camPos); - float3 scale = float3( - length(unity_ObjectToWorld._m00_m10_m20), - length(unity_ObjectToWorld._m01_m11_m21), - length(unity_ObjectToWorld._m02_m12_m22)); - float radiusWS = _Impostors_Sphere_Radius * max(scale.x, max(scale.y, scale.z)); + float radiusWS = _Impostors_Sphere_Radius; float3 originToRo = camPos - center; float b = dot(originToRo, viewDir); @@ -259,15 +270,28 @@ ImpostorResult impostor_frag(float3 worldPos) { uv2 = uvBase2 + ImpostorParallaxOffsetForFrame(frameDir2, pivotToCamOS, uvBase2, depthBlended) * parallaxStrength; } - ImpostorSample s0 = SampleImpostorCell(cell0, uv0, gridRes); - ImpostorSample s1 = SampleImpostorCell(cell1, uv1, gridRes); - ImpostorSample s2 = SampleImpostorCell(cell2, uv2, gridRes); + float2 uv0Final = uv0; + float2 uv1Final = uv1; + float2 uv2Final = uv2; + + ImpostorSample s0 = SampleImpostorCell(cell0, uv0Final, gridRes); + ImpostorSample s1 = SampleImpostorCell(cell1, uv1Final, gridRes); + ImpostorSample s2 = SampleImpostorCell(cell2, uv2Final, gridRes); // Parallax can push UVs into transparent pixels at silhouettes; fall back to unshifted UVs when that happens. if (parallaxStrength > 0.001) { - if (s0.albedo.a < _Impostors_Cutoff && baseAlpha0 > _Impostors_Cutoff) s0 = SampleImpostorCell(cell0, uvBase0, gridRes); - if (s1.albedo.a < _Impostors_Cutoff && baseAlpha1 > _Impostors_Cutoff) s1 = SampleImpostorCell(cell1, uvBase1, gridRes); - if (s2.albedo.a < _Impostors_Cutoff && baseAlpha2 > _Impostors_Cutoff) s2 = SampleImpostorCell(cell2, uvBase2, gridRes); + if (s0.albedo.a < _Impostors_Cutoff && baseAlpha0 > _Impostors_Cutoff) { + uv0Final = uvBase0; + s0 = SampleImpostorCell(cell0, uv0Final, gridRes); + } + if (s1.albedo.a < _Impostors_Cutoff && baseAlpha1 > _Impostors_Cutoff) { + uv1Final = uvBase1; + s1 = SampleImpostorCell(cell1, uv1Final, gridRes); + } + if (s2.albedo.a < _Impostors_Cutoff && baseAlpha2 > _Impostors_Cutoff) { + uv2Final = uvBase2; + s2 = SampleImpostorCell(cell2, uv2Final, gridRes); + } } // Blend 3 samples @@ -286,6 +310,17 @@ ImpostorResult impostor_frag(float3 worldPos) { result.metallic = blended.metallicGloss.r; result.smoothness = blended.metallicGloss.a; + // Reconstruct object space position from each frame's base UV and depth, then blend. + // Using base UVs and base depths ensures geometric consistency (same texel location). + float depth0Pos = SampleImpostorDepthCell(cell0, uv0Final, gridRes); + float depth1Pos = SampleImpostorDepthCell(cell1, uv1Final, gridRes); + float depth2Pos = SampleImpostorDepthCell(cell2, uv2Final, gridRes); + + float3 objPos0 = ReconstructObjPosFromFrame(frameDir0, uv0Final, depth0Pos); + float3 objPos1 = ReconstructObjPosFromFrame(frameDir1, uv1Final, depth1Pos); + float3 objPos2 = ReconstructObjPosFromFrame(frameDir2, uv2Final, depth2Pos); + result.objPos = objPos0 * bw.x + objPos1 * bw.y + objPos2 * bw.z; + return result; } |
