summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoryum <yum.food.vr@gmail.com>2026-01-14 19:07:31 -0800
committeryum <yum.food.vr@gmail.com>2026-01-14 19:07:31 -0800
commit22dc9b8c81ca6b4d90e2a77e71c21945d15e3d0f (patch)
tree009edacb0d0685b5236490e6fb15c94948c83239
parentb7b7f43ce5b4377aa44688f6e60d6ee2e9a61b98 (diff)
Impostors: cleanup
-rw-r--r--impostor.cginc101
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