summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pbr.cginc60
1 files changed, 47 insertions, 13 deletions
diff --git a/pbr.cginc b/pbr.cginc
index 8501edc..9f56570 100644
--- a/pbr.cginc
+++ b/pbr.cginc
@@ -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)