diff options
| author | yum <yum.food.vr@gmail.com> | 2026-01-14 19:07:31 -0800 |
|---|---|---|
| committer | yum <yum.food.vr@gmail.com> | 2026-01-14 19:07:31 -0800 |
| commit | 22dc9b8c81ca6b4d90e2a77e71c21945d15e3d0f (patch) | |
| tree | 009edacb0d0685b5236490e6fb15c94948c83239 | |
| parent | b7b7f43ce5b4377aa44688f6e60d6ee2e9a61b98 (diff) | |
Impostors: cleanup
| -rw-r--r-- | impostor.cginc | 101 |
1 files changed, 31 insertions, 70 deletions
diff --git a/impostor.cginc b/impostor.cginc index bdb24e7..4236778 100644 --- a/impostor.cginc +++ b/impostor.cginc @@ -17,9 +17,8 @@ float _DebugMode; float2 HemiOctEncode(float3 N) { N.y = max(N.y, 1e-4); - N = normalize(N); - float3 p = hemi_octahedron_to_plane(N, 0, float3(1,0,0), float3(0,1,0), 1); - return float2(p.x, p.z); + float3 p = hemi_octahedron_to_plane(normalize(N), 0, float3(1,0,0), float3(0,1,0), 1); + return p.xz; } float3 HemiOctDecode(float2 uv) { @@ -41,25 +40,20 @@ float3 DirFromCell(float2 cell, float gridRes) { return HemiOctDecode(uv); } -float4 SampleAtlas(float2 uv, float2 cell) { - uv = clamp(uv, 0.0, 1.0); +float2 ClampUvInCell(float2 uv) { + uv = saturate(uv); float2 halfTexelInCell = 0.5 * _ImpostorAtlas_TexelSize.xy * (float)_GridResolution; - uv = clamp(uv, halfTexelInCell, 1.0 - halfTexelInCell); - return _ImpostorAtlas.Sample(bilinear_clamp_s, (cell + uv) / (float)_GridResolution); + return clamp(uv, halfTexelInCell, 1.0 - halfTexelInCell); } float4 SampleAtlasGrad(float2 uv, float2 cell, float2 uvGradX, float2 uvGradY) { - uv = clamp(uv, 0.0, 1.0); - float2 halfTexelInCell = 0.5 * _ImpostorAtlas_TexelSize.xy * (float)_GridResolution; - uv = clamp(uv, halfTexelInCell, 1.0 - halfTexelInCell); + uv = ClampUvInCell(uv); - float invGridRes = 1.0 / (float)_GridResolution; + float invGridRes = rcp((float)_GridResolution); float2 atlasUv = (cell + uv) * invGridRes; // Important: gradients must be computed in-cell; do not let integer cell offsets affect mip selection. - float2 atlasGradX = uvGradX * invGridRes; - float2 atlasGradY = uvGradY * invGridRes; - return _ImpostorAtlas.SampleGrad(bilinear_clamp_s, atlasUv, atlasGradX, atlasGradY); + return _ImpostorAtlas.SampleGrad(bilinear_clamp_s, atlasUv, uvGradX * invGridRes, uvGradY * invGridRes); } // Branchless barycentric weights in a unit square split into two triangles along the (0,0)-(1,1) diagonal. @@ -76,7 +70,7 @@ float4 GridCellBarycentric4(float2 p) { } // Compute UV on a virtual plane facing frameDir -float2 VirtualPlaneUV(float3 frameDir, float3 pivotToCam, float3 vertexToCam, float size) { +float2 VirtualPlaneUV(float3 frameDir, float3 pivotToCam, float3 vertexToCam) { float3 planeN = normalize(frameDir); float3 up = abs(planeN.y) > 0.999 ? float3(0,0,1) : float3(0,1,0); float3 planeX = normalize(cross(planeN, up)); @@ -89,10 +83,7 @@ float2 VirtualPlaneUV(float3 frameDir, float3 pivotToCam, float3 vertexToCam, fl float3 offset = vertexToCam * ratio - pivotToCam; float2 uv = float2(dot(planeX, offset), dot(planeY, offset)); - uv /= (2.0f * size); - uv *= -1.0f; - uv += 0.5; - return uv; + return uv * -1.0 + 0.5; } struct appdata { @@ -153,38 +144,17 @@ v2f vert(appdata v) { } // General purpose ray-sphere intersection. -bool raySphereIntersect( - float3 ro, float3 rayDir, - float3 origin, float radius, - out float3 posNear, out float3 posFar) { - float3 originToRo = ro - origin; - - float b = dot(originToRo, rayDir); - float c = dot(originToRo, originToRo) - radius * radius; - float disc = b * b - c; - - if (disc < 0) { - return false; - } - - float t_near = -b - sqrt(disc); - float t_far = -b + sqrt(disc); - - posNear = ro + rayDir * t_near; - posFar = ro + rayDir * t_far; - - return true; +bool RaySphereIntersect(float3 ro, float3 rayDir, float3 origin, float radius) { + float3 originToRo = ro - origin; + float b = dot(originToRo, rayDir); + float c = dot(originToRo, originToRo) - radius * radius; + return (b * b - c) >= 0.0; } float4 frag(v2f i) : SV_Target { // Sphere culling first - float3 eyeVec = i.worldPos - _WorldSpaceCameraPos; - float3 viewDir = normalize(eyeVec); - float3 posNear, posFar; - bool didIntersect = raySphereIntersect( - _WorldSpaceCameraPos, viewDir, - i.centerPos, _SphereRadius, - posNear, posFar); + float3 viewDir = normalize(i.worldPos - _WorldSpaceCameraPos); + bool didIntersect = RaySphereIntersect(_WorldSpaceCameraPos, viewDir, i.centerPos, _SphereRadius); clip(didIntersect - 0.5); // Camera position for grid computation (matches billboard orientation) @@ -198,10 +168,10 @@ float4 frag(v2f i) : SV_Target { // For lattice lookup, use the camera-to-impostor-center direction (matches billboard orientation). // Using the per-fragment view ray (camera→quad point) causes the selected lattice points/weights // to vary across the billboard, which reads as "not smooth" while moving around the impostor. - float3 centerToCamWS = normalize(camPos - center); - float3 viewOS = normalize(mul((float3x3)unity_WorldToObject, centerToCamWS)); + float3x3 worldToObject = (float3x3)unity_WorldToObject; + float3 viewOS = normalize(mul(worldToObject, normalize(camPos - center))); - // Get continuous grid position and find the 3 frames + // Get continuous grid position and find the 4 frames float gridRes = (float)_GridResolution; float2 grid = GridFromDir(viewOS, gridRes); float2 gridFloor = floor(grid); @@ -222,30 +192,21 @@ float4 frag(v2f i) : SV_Target { float3 dir10 = DirFromCell(cell10, gridRes); float3 dir11 = DirFromCell(cell11, gridRes); - // Compute virtual plane UVs for all 3 frames - float3 pivotToCamOS = mul((float3x3)unity_WorldToObject, camPos - center); - float3 vertexPosOS = mul((float3x3)unity_WorldToObject, i.worldPos - center); + // Compute virtual plane UVs for all 4 frames + float3 pivotToCamOS = mul(worldToObject, camPos - center); + float3 vertexPosOS = mul(worldToObject, i.worldPos - center); float3 vertexToCamOS = pivotToCamOS - vertexPosOS; - float2 uv00 = VirtualPlaneUV(dir00, pivotToCamOS, vertexToCamOS, 0.5); - float2 uv01 = VirtualPlaneUV(dir01, pivotToCamOS, vertexToCamOS, 0.5); - float2 uv10 = VirtualPlaneUV(dir10, pivotToCamOS, vertexToCamOS, 0.5); - float2 uv11 = VirtualPlaneUV(dir11, pivotToCamOS, vertexToCamOS, 0.5); - - float2 uv00dx = ddx(uv00); - float2 uv00dy = ddy(uv00); - float2 uv01dx = ddx(uv01); - float2 uv01dy = ddy(uv01); - float2 uv10dx = ddx(uv10); - float2 uv10dy = ddy(uv10); - float2 uv11dx = ddx(uv11); - float2 uv11dy = ddy(uv11); + 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 and blend frames - float4 s00 = SampleAtlasGrad(uv00, cell00, uv00dx, uv00dy); - float4 s01 = SampleAtlasGrad(uv01, cell01, uv01dx, uv01dy); - float4 s10 = SampleAtlasGrad(uv10, cell10, uv10dx, uv10dy); - float4 s11 = SampleAtlasGrad(uv11, cell11, uv11dx, uv11dy); + 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; #ifndef IMPOSTOR_SHADOW_PASS |
