summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--impostor.cginc98
1 files changed, 49 insertions, 49 deletions
diff --git a/impostor.cginc b/impostor.cginc
index 3a479c8..8cf306f 100644
--- a/impostor.cginc
+++ b/impostor.cginc
@@ -56,6 +56,7 @@ float2 VirtualPlaneUV(float3 frameDir, float3 pivotToCam, float3 vertexToCam) {
float projPivot = dot(planeN, pivotToCam);
float projVertex = dot(planeN, vertexToCam);
+ projVertex = (abs(projVertex) < 1e-4) ? (projVertex < 0 ? -1e-4 : 1e-4) : projVertex;
float ratio = projPivot / projVertex;
float3 offset = vertexToCam * ratio - pivotToCam;
@@ -64,14 +65,6 @@ float2 VirtualPlaneUV(float3 frameDir, float3 pivotToCam, float3 vertexToCam) {
return uv * -1.0 + 0.5;
}
-// General purpose ray-sphere intersection
-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;
-}
-
#if defined(_IMPOSTORS)
float2 ClampUvInCell(float2 uv) {
@@ -102,6 +95,15 @@ float SampleImpostorDepthCell(float2 cell, float2 uvInCell, float gridRes) {
return _Impostors_Depth_Atlas.SampleGrad(bilinear_clamp_s, atlasUv, gradX, gradY).r;
}
+float SampleImpostorAlphaCell(float2 cell, float2 uvInCell, float gridRes) {
+ uvInCell = ClampUvInCell(uvInCell);
+ float invGridRes = rcp(gridRes);
+ float2 atlasUv = (cell + uvInCell) * invGridRes;
+ float2 gradX = ddx(uvInCell) * invGridRes;
+ float2 gradY = ddy(uvInCell) * invGridRes;
+ return _Impostors_Atlas.SampleGrad(bilinear_clamp_s, atlasUv, gradX, gradY).a;
+}
+
ImpostorSample SampleImpostorCell(float2 cell, float2 uvInCell, float gridRes) {
uvInCell = ClampUvInCell(uvInCell);
float invGridRes = rcp(gridRes);
@@ -132,32 +134,6 @@ float2 ImpostorParallaxOffsetForFrame(float3 frameDir, float3 pivotToCamOS, floa
return (planeCoord - camXY) * (zSurface / camZ);
}
-ImpostorSample SampleImpostorCellParallaxSafe(
- float2 cell,
- float3 frameDir,
- float3 pivotToCamOS,
- float3 vertexToCamOS,
- float gridRes)
-{
- float2 uvBase = ClampUvInCell(VirtualPlaneUV(frameDir, pivotToCamOS, vertexToCamOS));
- ImpostorSample baseS = SampleImpostorCell(cell, uvBase, gridRes);
-
- float baseAlpha = baseS.albedo.a;
- float parallaxStrength = _Impostors_Parallax * smoothstep(_Impostors_Cutoff, 1.0, baseAlpha);
- if (parallaxStrength <= 0.001) return baseS;
-
- float depth01 = SampleImpostorDepthCell(cell, uvBase, gridRes);
- float2 uvParallax = uvBase + ImpostorParallaxOffsetForFrame(frameDir, pivotToCamOS, uvBase, depth01) * parallaxStrength;
- ImpostorSample parS = SampleImpostorCell(cell, uvParallax, gridRes);
-
- float denom = max(baseAlpha - _Impostors_Cutoff, 1e-4);
- float t = saturate((parS.albedo.a - _Impostors_Cutoff) / denom);
- baseS.albedo = lerp(baseS.albedo, parS.albedo, t);
- baseS.normal = lerp(baseS.normal, parS.normal, t);
- baseS.metallicGloss = lerp(baseS.metallicGloss, parS.metallicGloss, t);
- return baseS;
-}
-
ImpostorSample BlendImpostorSamples(ImpostorSample s0, ImpostorSample s1, ImpostorSample s2, float3 bw) {
ImpostorSample result;
float3 alpha = float3(s0.albedo.a, s1.albedo.a, s2.albedo.a);
@@ -171,7 +147,7 @@ ImpostorSample BlendImpostorSamples(ImpostorSample s0, ImpostorSample s1, Impost
// Weight normal/metallicGloss by alpha to avoid blending with transparent (zero) pixels
float3 alphaBw = alpha * bw;
- alphaBw /= max(dot(alphaBw, 1.0), 0.001);
+ alphaBw /= max(alphaBw.x + alphaBw.y + alphaBw.z, 0.001);
result.normal = s0.normal * alphaBw.x + s1.normal * alphaBw.y + s2.normal * alphaBw.z;
result.metallicGloss = s0.metallicGloss * alphaBw.x + s1.metallicGloss * alphaBw.y + s2.metallicGloss * alphaBw.z;
@@ -221,8 +197,10 @@ ImpostorResult impostor_frag(float3 worldPos) {
length(unity_ObjectToWorld._m02_m12_m22));
float radiusWS = _Impostors_Sphere_Radius * max(scale.x, max(scale.y, scale.z));
- bool didIntersect = RaySphereIntersect(camPos, viewDir, center, radiusWS);
- clip(didIntersect - 0.5);
+ float3 originToRo = camPos - center;
+ float b = dot(originToRo, viewDir);
+ float c = dot(originToRo, originToRo) - radiusWS * radiusWS;
+ clip(b * b - c);
// For lattice lookup, use the camera-to-impostor-center direction (matches billboard orientation).
float3x3 worldToObject = (float3x3)unity_WorldToObject;
@@ -252,23 +230,45 @@ ImpostorResult impostor_frag(float3 worldPos) {
float3 frameDir1 = DirFromCell(cell1, gridRes);
float3 frameDir2 = DirFromCell(cell2, gridRes);
+ float2 uvBase0 = ClampUvInCell(VirtualPlaneUV(frameDir0, pivotToCamOS, vertexToCamOS));
+ float2 uvBase1 = ClampUvInCell(VirtualPlaneUV(frameDir1, pivotToCamOS, vertexToCamOS));
+ float2 uvBase2 = ClampUvInCell(VirtualPlaneUV(frameDir2, pivotToCamOS, vertexToCamOS));
+
+ float baseAlpha0 = SampleImpostorAlphaCell(cell0, uvBase0, gridRes);
+ float baseAlpha1 = SampleImpostorAlphaCell(cell1, uvBase1, gridRes);
+ float baseAlpha2 = SampleImpostorAlphaCell(cell2, uvBase2, gridRes);
+ float baseAlphaBlended = baseAlpha0 * bw.x + baseAlpha1 * bw.y + baseAlpha2 * bw.z;
+ float parallaxStrength = _Impostors_Parallax * smoothstep(_Impostors_Cutoff, 1.0, baseAlphaBlended);
+
+ float depth0 = SampleImpostorDepthCell(cell0, uvBase0, gridRes);
+ float depth1 = SampleImpostorDepthCell(cell1, uvBase1, gridRes);
+ float depth2 = SampleImpostorDepthCell(cell2, uvBase2, gridRes);
+ float depthBlended = depth0 * bw.x + depth1 * bw.y + depth2 * bw.z;
+
if (_Impostors_Debug_Depth > 0.5) {
- float2 uvBase0 = ClampUvInCell(VirtualPlaneUV(frameDir0, pivotToCamOS, vertexToCamOS));
- float2 uvBase1 = ClampUvInCell(VirtualPlaneUV(frameDir1, pivotToCamOS, vertexToCamOS));
- float2 uvBase2 = ClampUvInCell(VirtualPlaneUV(frameDir2, pivotToCamOS, vertexToCamOS));
-
- float depth0 = SampleImpostorDepthCell(cell0, uvBase0, gridRes);
- float depth1 = SampleImpostorDepthCell(cell1, uvBase1, gridRes);
- float depth2 = SampleImpostorDepthCell(cell2, uvBase2, gridRes);
-
- float depthBlended = depth0 * bw.x + depth1 * bw.y + depth2 * bw.z;
result.albedo = float4(depthBlended.xxx, 1);
return result;
}
- ImpostorSample s0 = SampleImpostorCellParallaxSafe(cell0, frameDir0, pivotToCamOS, vertexToCamOS, gridRes);
- ImpostorSample s1 = SampleImpostorCellParallaxSafe(cell1, frameDir1, pivotToCamOS, vertexToCamOS, gridRes);
- ImpostorSample s2 = SampleImpostorCellParallaxSafe(cell2, frameDir2, pivotToCamOS, vertexToCamOS, gridRes);
+ float2 uv0 = uvBase0;
+ float2 uv1 = uvBase1;
+ float2 uv2 = uvBase2;
+ if (parallaxStrength > 0.001) {
+ uv0 = uvBase0 + ImpostorParallaxOffsetForFrame(frameDir0, pivotToCamOS, uvBase0, depthBlended) * parallaxStrength;
+ uv1 = uvBase1 + ImpostorParallaxOffsetForFrame(frameDir1, pivotToCamOS, uvBase1, depthBlended) * parallaxStrength;
+ 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);
+
+ // 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);
+ }
// Blend 3 samples
ImpostorSample blended = BlendImpostorSamples(s0, s1, s2, bw);