diff options
| -rw-r--r-- | pbr.cginc | 60 |
1 files changed, 47 insertions, 13 deletions
@@ -30,14 +30,21 @@ struct Pbr { #if defined(_PARALLAX_HEIGHTMAP) float2 parallax_offset(float2 uv, float3 view_dir_world, float3x3 tbn) { float3 view_dir_tangent = mul(tbn, view_dir_world); - float2 uv_step = view_dir_tangent.xy / max(view_dir_tangent.z, 1e-3f) * _Parallax_Heightmap_Scale; + float view_z = max(view_dir_tangent.z, 1e-3f); + float2 uv_step = view_dir_tangent.xy / view_z * _Parallax_Heightmap_Scale; #if defined(_PARALLAX_HEIGHTMAP_RAY_MARCHING) - float step_count = _Parallax_Heightmap_Ray_Marching_Steps; + // Adapt steps by angle to keep cost down while preserving glancing detail. + float angle = saturate(view_z); + float base_steps = _Parallax_Heightmap_Ray_Marching_Steps; + float step_count = lerp(base_steps * 1.5, base_steps * 0.75, angle); + step_count = clamp(step_count, 2.0, max(base_steps, 2.0)); + float2 delta_uv = uv_step / step_count; float delta_depth = 1.0 / step_count; float2 cur_uv = uv; + float2 prev_uv = uv; float cur_depth = 0.0; float cur_height = 1.0 - _Parallax_Heightmap.Sample(linear_repeat_s, cur_uv * _Parallax_Heightmap_ST.xy + _Parallax_Heightmap_ST.zw).r; @@ -60,6 +67,7 @@ float2 parallax_offset(float2 uv, float3 view_dir_world, float3x3 tbn) { prev_depth = cur_depth; prev_height = cur_height; + prev_uv = cur_uv; cur_uv += delta_uv; cur_depth += delta_depth; @@ -68,16 +76,37 @@ float2 parallax_offset(float2 uv, float3 view_dir_world, float3x3 tbn) { cur_height = (cur_height - (1.0 - _Parallax_Heightmap_Bias)); } - // Linear interpolation between last two samples - float after = cur_height - cur_depth; + // Short binary refine between last two samples to tighten the hit float before = prev_height - prev_depth; - float t = after / (after - before); + float2 low_uv = prev_uv; + float low_depth = prev_depth; + float low_sign = before; + float2 high_uv = cur_uv; + float high_depth = cur_depth; + + [unroll(2)] + for (int j = 0; j < 2; j++) { + float mid_height = 1.0 - _Parallax_Heightmap.Sample(linear_repeat_s, + 0.5 * (low_uv + high_uv) * _Parallax_Heightmap_ST.xy + _Parallax_Heightmap_ST.zw).r; + mid_height = (mid_height - (1.0 - _Parallax_Heightmap_Bias)); + float mid_depth = 0.5 * (low_depth + high_depth); + float mid_sign = mid_height - mid_depth; + if (mid_sign == 0.0 || sign(mid_sign) == sign(low_sign)) { + low_uv = 0.5 * (low_uv + high_uv); + low_depth = mid_depth; + low_sign = mid_sign; + } else { + high_uv = 0.5 * (low_uv + high_uv); + high_depth = mid_depth; + } + } - return cur_uv - uv - delta_uv * t; + float2 refine_uv = 0.5 * (low_uv + high_uv); + return refine_uv - uv; #else float2 heightmap_uv = uv * _Parallax_Heightmap_ST.xy + _Parallax_Heightmap_ST.zw; float height = _Parallax_Heightmap.Sample(linear_repeat_s, heightmap_uv).r; - height = height - _Parallax_Heightmap_Bias; + height = saturate(height - _Parallax_Heightmap_Bias); return uv_step * height; #endif @@ -111,22 +140,27 @@ void apply_marble(float3 world_pos, inout float3 albedo) { Pbr getPbr(v2f i) { Pbr pbr = (Pbr) 0; - float3 bitangent = cross(i.normal, i.tangent.xyz) * i.tangent.w; - pbr.tbn = float3x3(i.tangent.xyz, bitangent, i.normal); + float3 n = normalize(i.normal); + float3 t = normalize(i.tangent.xyz); + t = normalize(t - n * dot(n, t)); // Gram-Schmidt to avoid skew + float3 b = normalize(cross(n, t)) * i.tangent.w; + pbr.tbn = float3x3(t, b, n); #if defined(_UV_SCROLL) i.uv01.xy += getTime() * _UV_Scroll_Speed; #endif // _UV_SCROLL #if defined(_PARALLAX_HEIGHTMAP) - i.uv01.xy += parallax_offset(i.uv01.xy, normalize(i.eyeVec.xyz), pbr.tbn); + float2 uv_parallax = i.uv01.xy + parallax_offset(i.uv01.xy, normalize(i.eyeVec.xyz), pbr.tbn); +#else + float2 uv_parallax = i.uv01.xy; #endif // _PARALLAX_HEIGHTMAP - pbr.albedo = _MainTex.Sample(aniso16_trilinear_repeat_s, i.uv01.xy * _MainTex_ST.xy + _MainTex_ST.zw); + pbr.albedo = _MainTex.Sample(aniso16_trilinear_repeat_s, uv_parallax * _MainTex_ST.xy + _MainTex_ST.zw); pbr.albedo *= _Color; apply_marble(i.worldPos, pbr.albedo.xyz); - float3 normal_tangent = UnpackNormal(_BumpMap.Sample(aniso16_trilinear_repeat_s, i.uv01.xy * _BumpMap_ST.xy)); + float3 normal_tangent = UnpackNormal(_BumpMap.Sample(aniso16_trilinear_repeat_s, uv_parallax * _BumpMap_ST.xy)); normal_tangent.xy *= _BumpScale; #if defined(_DETAILS) @@ -140,7 +174,7 @@ Pbr getPbr(v2f i) { pbr.normal = normalize(mul(normal_tangent, pbr.tbn)); - float4 metallic_gloss = _MetallicGlossMap.Sample(aniso16_trilinear_repeat_s, i.uv01.xy * _MetallicGlossMap_ST.xy); + float4 metallic_gloss = _MetallicGlossMap.Sample(aniso16_trilinear_repeat_s, uv_parallax * _MetallicGlossMap_ST.xy); pbr.smoothness = metallic_gloss.a * _Glossiness; pbr.metallic = metallic_gloss.r * _Metallic; #if defined(_CLEARCOAT) |
