yum/3ner
A toon shader for Unity's BIRP.
git clone https://git.yummers.dev/yum/3ner
ecd59e8
master
1#ifndef __PBR_INC 2#define __PBR_INC 3 4#include "aperiodic_tiling.cginc" 5#include "burley.cginc" 6#include "custom31.cginc" 7#include "data.cginc" 8#include "decal.cginc" 9#include "filamented.cginc" 10#include "instancing.cginc" 11#include "interpolators.cginc" 12#include "letter_grid.cginc" 13#include "texture_utils.cginc" 14#include "triplanar.cginc" 15 16#if defined(_PARALLAX_HEIGHTMAP_TEXTURE) || defined(_BURLEY_TILING_HEIGHTMAP) 17float heightmap_sample(float2 uv) { 18 #if defined(_BURLEY_TILING_HEIGHTMAP) 19 float2 delta = (uv - _burley_ctx.base_uv) * _burley_ctx.uv_scale; 20 float4 s0 = _Burley_Tiling_Heightmap.SampleGrad(aniso4_trilinear_repeat_s, 21 _burley_ctx.patch_0.uv + mul(_burley_ctx.patch_0.uv_to_patch, delta), 22 _burley_ctx.patch_0.dx, _burley_ctx.patch_0.dy); 23 float4 s1 = _Burley_Tiling_Heightmap.SampleGrad(aniso4_trilinear_repeat_s, 24 _burley_ctx.patch_1.uv + mul(_burley_ctx.patch_1.uv_to_patch, delta), 25 _burley_ctx.patch_1.dx, _burley_ctx.patch_1.dy); 26 float4 s2 = _Burley_Tiling_Heightmap.SampleGrad(aniso4_trilinear_repeat_s, 27 _burley_ctx.patch_2.uv + mul(_burley_ctx.patch_2.uv_to_patch, delta), 28 _burley_ctx.patch_2.dx, _burley_ctx.patch_2.dy); 29 float4 blend = s0 * _burley_ctx.weights.x + s1 * _burley_ctx.weights.y + s2 * _burley_ctx.weights.z; 30 return burley_degaussianize( 31 _Burley_Tiling_Heightmap_LUT, 32 burley_apply_soft_clipping(blend.rgb, _burley_ctx.weights), 33 false).r; 34 #elif defined(_PARALLAX_HEIGHTMAP_TEXTURE) 35 return _Parallax_Heightmap.Sample(linear_repeat_s, uv * _Parallax_Heightmap_ST.xy + _Parallax_Heightmap_ST.zw).r; 36 #endif 37} 38#endif // _PARALLAX_HEIGHTMAP_TEXTURE || _BURLEY_TILING_HEIGHTMAP 39 40#if defined(_PARALLAX_HEIGHTMAP) 41float2 parallax_offset(float2 uv, float3 view_dir_world, float3x3 tbn) { 42 float3 view_dir_tangent = mul(tbn, view_dir_world); 43 float view_z = max(view_dir_tangent.z, 1e-3f); 44 float2 uv_step = view_dir_tangent.xy / view_z * _Parallax_Heightmap_Scale; 45 46#if defined(_PARALLAX_HEIGHTMAP_RAY_MARCHING) 47 // Adapt steps by angle to keep cost down while preserving glancing detail. 48 float angle = saturate(view_z); 49 float base_steps = _Parallax_Heightmap_Ray_Marching_Steps; 50 float step_count = lerp(base_steps * 1.5, base_steps * 0.75, angle); 51 int step_count_i = (int)ceil(clamp(step_count, 2.0, max(base_steps, 2.0))); 52 float inv_step_count = rcp((float)step_count_i); 53 54 float2 delta_uv = uv_step * inv_step_count; 55 float delta_layer = inv_step_count; 56 57 float2 cur_uv = uv - uv_step * _Parallax_Heightmap_Bias; 58 float2 prev_uv = cur_uv; 59 float cur_layer = 0.0; 60 float sampled_height = heightmap_sample(cur_uv); 61 62 float prev_layer = cur_layer; 63 64 [loop] 65 for (int i = 0; i < step_count_i; i++) { 66 if (cur_layer >= sampled_height) break; 67 68 prev_layer = cur_layer; 69 prev_uv = cur_uv; 70 71 cur_uv += delta_uv; 72 cur_layer += delta_layer; 73 sampled_height = heightmap_sample(cur_uv); 74 } 75 76 // Short binary refine between last two samples to tighten the hit 77 float2 low_uv = prev_uv; 78 float low_layer = prev_layer; 79 float2 high_uv = cur_uv; 80 float high_layer = cur_layer; 81 82 [unroll(2)] 83 for (int j = 0; j < 2; j++) { 84 float2 mid_uv = 0.5 * (low_uv + high_uv); 85 float mid_layer = 0.5 * (low_layer + high_layer); 86 float mid_height = heightmap_sample(mid_uv); 87 if (mid_layer < mid_height) { 88 low_uv = mid_uv; 89 low_layer = mid_layer; 90 } else { 91 high_uv = mid_uv; 92 high_layer = mid_layer; 93 } 94 } 95 96 float2 refine_uv = 0.5 * (low_uv + high_uv); 97 return refine_uv - uv; 98#else 99 float height = heightmap_sample(uv) - _Parallax_Heightmap_Bias; 100 return uv_step * height; 101#endif 102} 103#endif // _PARALLAX_HEIGHTMAP 104 105// Tokuyoshi and Kaplanyan 2019 "Improved Geometric Specular Antialiasing" 106float normalFiltering(float3 geometric_normal, float perceptual_roughness) { 107 float3 du = ddx(geometric_normal); 108 float3 dv = ddy(geometric_normal); 109 110 float variance = _Specular_AA_Variance * (dot(du, du) + dot(dv, dv)); 111 float roughness = perceptual_roughness * perceptual_roughness; 112 float kernel_roughness = min(2.0f * variance, _Specular_AA_Threshold); 113 float square_roughness = saturate(roughness * roughness + kernel_roughness); 114 115 return saturate(sqrt(sqrt(square_roughness))); 116} 117 118void propagateSmoothness(inout Pbr pbr) { 119 pbr.smoothness = 1.0f - normalFiltering(pbr.normal, 1.0f - pbr.smoothness); 120 121 pbr.roughness_perceptual = clamp(1.0f - pbr.smoothness, MIN_PERCEPTUAL_ROUGHNESS, 1); 122 pbr.roughness = clamp(pbr.roughness_perceptual * pbr.roughness_perceptual, MIN_ROUGHNESS, 1); 123#if defined(_CLEARCOAT) 124 pbr.cc_roughness_perceptual = clamp(pbr.cc_roughness_perceptual, MIN_PERCEPTUAL_ROUGHNESS, 1); 125 pbr.cc_roughness_perceptual = normalFiltering(pbr.geometric_normal, pbr.cc_roughness_perceptual); 126 pbr.cc_roughness = max(MIN_ROUGHNESS, pbr.cc_roughness_perceptual * pbr.cc_roughness_perceptual); 127#endif 128} 129 130void apply_marble(float3 world_pos, inout float3 albedo) { 131#if defined(_MARBLE) 132 float3 uvw = world_pos * _Marble_Scale; 133 134 float3 offset = 0; 135#if defined(_MARBLE_TIME) 136 offset += _Time[0] * _Marble_Speed * _Marble_Direction; 137#endif 138#if defined(_MARBLE_OFFSET) 139 offset += _Marble_Offset; 140#endif 141 142 uvw += offset; 143 144 float3 noise = domain_warp_procedural(uvw, _Marble_Strength, 145 _Marble_Octaves, _Marble_Lacunarity, _Marble_Gain); 146 147 noise = _Marble_Post_Ramp.Sample(linear_clamp_s, float2(noise.x, 0)); 148 149 albedo = noise; 150#endif 151} 152 153void apply_kintsugi(float3 world_pos, inout float3 albedo, inout float smoothness, inout float metallic) { 154#if defined(_KINTSUGI) 155 float3 uvw = world_pos * _Kintsugi_Scale; 156 157#if defined(_KINTSUGI_DOMAIN_WARPING) 158 float3 warp = domain_warp_procedural( 159 world_pos * _Kintsugi_Domain_Warping_Scale, 160 _Kintsugi_Domain_Warping_Strength, _Kintsugi_Domain_Warping_Octaves, 161 _Kintsugi_Domain_Warping_Lacunarity, _Kintsugi_Domain_Warping_Gain); 162 uvw += warp; 163#endif 164 165 float mask = 1.0f - voronoi_d_3d(uvw); 166 float width = max(fwidth(mask) * 0.5f, _Kintsugi_Width); 167 float threshold = _Kintsugi_Threshold; 168 mask = smoothstep(threshold - width, threshold + width, mask); 169 170#if defined(_KINTSUGI_NOISE_INVERT) 171 mask = 1.0f - mask; 172#endif // _KINTSUGI_NOISE_INVERT 173 174 albedo = lerp(albedo, _Kintsugi_Color, mask); 175 smoothness = lerp(smoothness, _Kintsugi_Smoothness, mask); 176 metallic = lerp(metallic, _Kintsugi_Metallic, mask); 177#endif // _KINTSUGI 178} 179 180void apply_letter_grid(v2f i, inout Pbr pbr) { 181#if defined(_LETTER_GRID) 182 LetterGridOutput lg = LetterGrid(i); 183 pbr.albedo.rgb = lerp(pbr.albedo.rgb, lg.albedo, lg.albedo.a); 184 pbr.metallic = lerp(pbr.metallic, lg.metallic, lg.albedo.a); 185 pbr.roughness = lerp(pbr.roughness, lg.roughness, lg.albedo.a); 186#if defined(FORWARD_BASE_PASS) 187 pbr.emission += lg.emission * lg.albedo.a; 188#endif 189#endif 190} 191 192void apply_burley_tiling(inout Pbr pbr, inout float3 normal_tangent) { 193#if defined(_BURLEY_TILING) 194 float3 weights = _burley_ctx.weights; 195 196#if defined(_BURLEY_TILING_MAINTEX) 197 float4 patch_0 = burley_sample_patch(_Burley_Tiling_Maintex, _burley_ctx.patch_0); 198 float4 patch_1 = burley_sample_patch(_Burley_Tiling_Maintex, _burley_ctx.patch_1); 199 float4 patch_2 = burley_sample_patch(_Burley_Tiling_Maintex, _burley_ctx.patch_2); 200 float4 gaussian_blend = patch_0 * weights.x + patch_1 * weights.y + patch_2 * weights.z; 201 pbr.albedo.xyz = burley_degaussianize(_Burley_Tiling_Maintex_LUT, burley_apply_soft_clipping(gaussian_blend.rgb, weights)); 202#endif // _BURLEY_TILING_MAINTEX 203 204#if defined(_BURLEY_TILING_SMOOTHNESS) 205 float4 patch_0_smoothness = burley_sample_patch(_Burley_Tiling_Smoothness_Map, _burley_ctx.patch_0); 206 float4 patch_1_smoothness = burley_sample_patch(_Burley_Tiling_Smoothness_Map, _burley_ctx.patch_1); 207 float4 patch_2_smoothness = burley_sample_patch(_Burley_Tiling_Smoothness_Map, _burley_ctx.patch_2); 208 float4 smoothness_blend = patch_0_smoothness * weights.x + patch_1_smoothness * weights.y + patch_2_smoothness * weights.z; 209 pbr.smoothness = burley_degaussianize(_Burley_Tiling_Smoothness_Map_LUT, burley_apply_soft_clipping(smoothness_blend, weights)).r; 210#if defined(_BURLEY_TILING_SMOOTHNESS_INVERT) 211 pbr.smoothness = 1.0f - pbr.smoothness; 212#endif // _BURLEY_TILING_SMOOTHNESS_INVERT 213#endif // _BURLEY_TILING_SMOOTHNESS 214 215#if defined(_BURLEY_TILING_NORMAL) 216 // TODO whiteout blending? 217 float4 patch_0_normal = burley_sample_patch(_Burley_Tiling_Normal_Map, _burley_ctx.patch_0); 218 float4 patch_1_normal = burley_sample_patch(_Burley_Tiling_Normal_Map, _burley_ctx.patch_1); 219 float4 patch_2_normal = burley_sample_patch(_Burley_Tiling_Normal_Map, _burley_ctx.patch_2); 220 float4 normal_blend = patch_0_normal * weights.x + patch_1_normal * weights.y + patch_2_normal * weights.z; 221 normal_tangent = burley_degaussianize(_Burley_Tiling_Normal_Map_LUT, burley_apply_soft_clipping(normal_blend.rgb, weights), false); 222 normal_tangent.xy = normal_tangent.xy * 2 - 1; 223 normal_tangent.xy *= _Burley_Tiling_Normal_Strength; 224 normal_tangent = normalize(normal_tangent); 225#endif // _BURLEY_TILING_NORMAL 226#endif // _BURLEY_TILING 227} 228 229void apply_zebra(float2 uv, inout float3 albedo, inout float3 normal_tangent) { 230#if defined(_ZEBRA) 231 //float theta = 0.25 * PI; 232 float theta = _Time[0] * 4; 233 //float theta = _Zebra_Angle * TAU; 234 uv.x *= _Zebra_X_Scale; 235 float st, ct; 236 sincos(theta, st, ct); 237 float4 phacelle = phacelle_noise_2d(uv * _Zebra_Scale, float2(ct, st)); 238 float2 dir = phacelle.xy; 239 float mask = dot(dir, float2(0, 1)); 240 float mask_fw = fwidth(mask); 241 albedo = smoothstep(-mask_fw * 0.5, mask_fw * 0.5, mask); 242 normal_tangent = normalize(float3( 243 mask * phacelle.zw * _Zebra_Normal_Strength, 1.0)); 244#endif 245} 246 247Pbr getPbr(v2f i) { 248 Pbr pbr = (Pbr) 0; 249 250 float3 n = i.normal; 251 pbr.geometric_normal = n; 252 float3 t = i.tangent.xyz; 253 t = normalize(t - n * dot(n, t)); // Gram-Schmidt to avoid skew 254 float3 b = normalize(cross(n, t)) * i.tangent.w; 255 pbr.tbn = float3x3(t, b, n); 256 257#if defined(_UV_SCROLL) 258 i.uv01.xy += getTime() * _UV_Scroll_Speed; 259#endif // _UV_SCROLL 260 261#if defined(_BURLEY_TILING) 262 burley_tiling_setup(i.uv01.xy); 263#endif 264 265#if defined(_PARALLAX_HEIGHTMAP) 266 float2 uv_parallax = i.uv01.xy + parallax_offset(i.uv01.xy, normalize(-i.eyeVec.xyz), pbr.tbn); 267#else 268 float2 uv_parallax = i.uv01.xy; 269#endif // _PARALLAX_HEIGHTMAP 270 271#if defined(_BURLEY_TILING) 272 burley_tiling_setup(uv_parallax); 273#endif 274 275#if defined(_PARALLAX_HEIGHTMAP) || defined(_BURLEY_TILING_HEIGHTMAP) 276 pbr.height = heightmap_sample(uv_parallax); 277#endif 278 279#if defined(OUTLINES_PASS) && defined(_OUTLINES) 280 pbr.albedo = _Outlines_Color; 281#else 282 pbr.albedo = _MainTex.Sample(aniso4_trilinear_repeat_s, uv_parallax * _MainTex_ST.xy + _MainTex_ST.zw); 283 pbr.albedo *= _Color; 284#endif 285 286 float3 normal_tangent = UnpackNormal(_BumpMap.Sample(aniso4_trilinear_repeat_s, uv_parallax * _BumpMap_ST.xy)); 287 normal_tangent.xy *= _BumpScale; 288 289#if defined(_DETAILS) 290 float2 detail_uv = get_uv_by_channel(i, _Details_UV_Channel); 291 float3 detail_normal = UnpackNormal(_DetailNormalMap.Sample(aniso4_trilinear_repeat_s, detail_uv * _DetailNormalMap_ST.xy)); 292 detail_normal.xy *= _DetailNormalMapScale; 293 float detail_mask = _DetailMask.Sample(aniso4_trilinear_repeat_s, detail_uv * _DetailMask_ST.xy).r; 294 detail_normal.xy *= detail_mask; 295 normal_tangent = blendNormalsHill12(normal_tangent, detail_normal); 296#endif 297 298 float4 metallic_gloss = _MetallicGlossMap.Sample(aniso4_trilinear_repeat_s, uv_parallax * _MetallicGlossMap_ST.xy); 299 pbr.smoothness = metallic_gloss.a * _Glossiness; 300 pbr.metallic = metallic_gloss.r * _Metallic; 301 302 apply_marble(i.worldPos, pbr.albedo.xyz); 303 apply_kintsugi(i.worldPos, pbr.albedo.xyz, pbr.smoothness, pbr.metallic); 304 apply_letter_grid(i, pbr); 305 apply_burley_tiling(pbr, normal_tangent); 306 apply_triplanar_layers(i.worldPos, i.normal, pbr, normal_tangent); 307 apply_custom31_world(i, pbr, normal_tangent); 308 apply_aperiodic_tiling(i.uv01.xy, pbr.albedo.xyz, pbr.smoothness, normal_tangent); 309 apply_zebra(i.uv01.xy, pbr.albedo.xyz, normal_tangent); 310 311 applyDecals(i, pbr, normal_tangent); 312 313 pbr.normal = normalize(mul(normal_tangent, pbr.tbn)); 314 315#if defined(_DEBUG_VIEW_TANGENT_SPACE_NORMALS) 316 pbr.tangent_normal = normal_tangent; 317#endif 318 319#if defined(_BENT_NORMALS) 320 float3 bent_ts = UnpackNormal(_Bent_Normals_Map.Sample( 321 aniso4_trilinear_repeat_s, uv_parallax * _Bent_Normals_Map_ST.xy + 322 _Bent_Normals_Map_ST.zw)); 323 pbr.bent_normal = normalize(mul(bent_ts, pbr.tbn)); 324#endif 325 326#if defined(_CLEARCOAT) 327 pbr.cc_roughness = _Clearcoat_Roughness; 328 pbr.cc_roughness_perceptual = sqrt(pbr.cc_roughness); 329 pbr.cc_strength = _Clearcoat_Strength; 330#if defined(_CLEARCOAT_NORMALS) 331 float3 cc_normal_ts = UnpackNormal(_Clearcoat_Normals.Sample( 332 aniso4_trilinear_repeat_s, uv_parallax * _Clearcoat_Normals_ST.xy + 333 _Clearcoat_Normals_ST.zw)); 334 cc_normal_ts.xy *= _Clearcoat_Normals_Strength; 335 pbr.cc_normal = normalize(mul(cc_normal_ts, pbr.tbn)); 336#else 337 pbr.cc_normal = i.normal; 338#endif // _CLEARCOAT_NORMALS 339#endif // _CLEARCOAT 340 propagateSmoothness(pbr); 341 342#if defined(_EMISSIONS) && defined(FORWARD_BASE_PASS) 343 float3 emission_tint = _EmissionColor; 344 float3 emission_color = _EmissionMap.Sample(trilinear_repeat_s, 345 i.uv01.xy * _EmissionMap_ST.xy + _EmissionMap_ST.zw); 346 float emission_mask = _EmissionMask.Sample(trilinear_repeat_s, 347 i.uv01.xy * _EmissionMask_ST.xy + _EmissionMask_ST.zw).r; 348 pbr.emission = emission_tint * emission_color * emission_mask; 349#endif 350 351 return pbr; 352} 353 354#endif // __PBR_INC