yum-archive/2ner
A toon shader for Unity's BIRP.
git clone https://git.yummers.dev/yum-archive/2ner
d0c27e8
master
1#ifndef __YUM_PBR 2#define __YUM_PBR 3 4#include "cnlohr.cginc" 5#include "data.cginc" 6#include "decals.cginc" 7#include "features.cginc" 8#include "filamented.cginc" 9#include "glitter.cginc" 10#include "globals.cginc" 11#include "math.cginc" 12#include "oklab.cginc" 13#include "texture_utils.cginc" 14 15void propagateRoughness(in float smoothness, out float roughness_perceptual, out float roughness) { 16 roughness_perceptual = normalFiltering(1.0 - smoothness, float3(0, 0, 1)); 17 roughness = roughness_perceptual * roughness_perceptual; 18} 19 20// Shitty hacky filtering, not in any way robust or mathematically sound. 21void filterGradient(v2f i, inout float2 g) 22{ 23 float3 normal = normalize(float3(-g.x, 1.0f, -g.y)); 24 float dn = length(fwidth(normal)); 25 g *= saturate(0.05 / dn); 26} 27 28#if defined(_GRADIENT_NORMALS) 29void applyGradientNormals(v2f i, inout YumPbr pbr) { 30 float2 uv = i.uv01.xy; 31 32 // Math lifted from "Ocean waves simulation with Fast Fourier transform" by 33 // Jump Trajectory. 34 float2 gradient = 0; 35 36#if defined(_GRADIENT_NORMALS_0_VERTICAL) 37 float2 g0_uv = uv * _Gradient_Normals_0_Vertical_ST.xy; 38 float2 g0_dfy = _Gradient_Normals_0_Vertical.SampleLevel(bilinear_repeat_s, g0_uv, 0).rg; 39 float2 g0 = g0_dfy; 40#if defined(_GRADIENT_NORMALS_0_HORIZONTAL) 41 float2 g0_dfxz = _Gradient_Normals_0_Horizontal.SampleLevel(bilinear_repeat_s, g0_uv, 0).rg; 42 g0 = float2( 43 g0_dfy[0] / (1 + g0_dfxz[0]), 44 g0_dfy[1] / (1 + g0_dfxz[1]) 45 ); 46 filterGradient(i, g0); 47#endif // _GRADIENT_NORMALS_0_HORIZONTAL 48 gradient += g0; 49#endif // _GRADIENT_NORMALS_0_VERTICAL 50 51#if defined(_GRADIENT_NORMALS_1_VERTICAL) 52 float2 g1_uv = uv * _Gradient_Normals_1_Vertical_ST.xy; 53 float2 g1_dfy = _Gradient_Normals_1_Vertical.SampleLevel(bilinear_repeat_s, g1_uv, 0).rg; 54 float2 g1 = g1_dfy; 55#if defined(_GRADIENT_NORMALS_1_HORIZONTAL) 56 float2 g1_dfxz = _Gradient_Normals_1_Horizontal.SampleLevel(bilinear_repeat_s, g1_uv, 0).rg; 57 g1 = float2( 58 g1_dfy[0] / (1 + g1_dfxz[0]), 59 g1_dfy[1] / (1 + g1_dfxz[1]) 60 ); 61 filterGradient(i, g1); 62#endif // _GRADIENT_NORMALS_1_HORIZONTAL 63 gradient += g1; 64#endif // _GRADIENT_NORMALS_1_VERTICAL 65 66#if defined(_GRADIENT_NORMALS_2_VERTICAL) 67 float2 g2_uv = uv * _Gradient_Normals_2_Vertical_ST.xy; 68 float2 g2_dfy = _Gradient_Normals_2_Vertical.SampleLevel(bilinear_repeat_s, g2_uv, 0).rg; 69 float2 g2 = g2_dfy; 70#if defined(_GRADIENT_NORMALS_2_HORIZONTAL) 71 float2 g2_dfxz = _Gradient_Normals_2_Horizontal.SampleLevel(bilinear_repeat_s, g2_uv, 0).rg; 72 g2 = float2( 73 g2_dfy[0] / (1 + g2_dfxz[0]), 74 g2_dfy[1] / (1 + g2_dfxz[1]) 75 ); 76#endif // _GRADIENT_NORMALS_2_HORIZONTAL 77 gradient += g2; 78#endif // _GRADIENT_NORMALS_2_VERTICAL 79 80#if defined(_GRADIENT_NORMALS_3_VERTICAL) 81 float2 g3_uv = uv * _Gradient_Normals_3_Vertical_ST.xy; 82 float2 g3_dfy = _Gradient_Normals_3_Vertical.SampleLevel(bilinear_repeat_s, g3_uv, 0).rg; 83 float2 g3 = g3_dfy; 84#if defined(_GRADIENT_NORMALS_3_HORIZONTAL) 85 float2 g3_dfxz = _Gradient_Normals_3_Horizontal.SampleLevel(bilinear_repeat_s, g3_uv, 0).rg; 86 g3 = float2( 87 g3_dfy[0] / (1 + g3_dfxz[0]), 88 g3_dfy[1] / (1 + g3_dfxz[1]) 89 ); 90 filterGradient(i, g2); 91#endif // _GRADIENT_NORMALS_3_HORIZONTAL 92 93 gradient += g3; 94#endif // _GRADIENT_NORMALS_3_VERTICAL 95 96 float3 gradient_normal = normalize(float3(-gradient.x, 1.0f, -gradient.y)); 97 98 pbr.normal = gradient_normal; 99} 100#endif 101 102#if defined(_SEA_FOAM) 103void applySeaFoam(v2f i, inout YumPbr pbr) { 104 float2 uv = i.uv01.xy; 105 106 float4 slope = 0; 107 108 #if defined(_SEA_FOAM_0) 109 slope += _Sea_Foam_0_Slope.SampleLevel(bilinear_repeat_s, uv * _Sea_Foam_0_Slope_ST.xy, 0); 110 #endif 111 #if defined(_SEA_FOAM_1) 112 slope += _Sea_Foam_1_Slope.SampleLevel(bilinear_repeat_s, uv * _Sea_Foam_1_Slope_ST.xy, 0); 113 #endif 114 #if defined(_SEA_FOAM_2) 115 slope += _Sea_Foam_2_Slope.SampleLevel(bilinear_repeat_s, uv * _Sea_Foam_2_Slope_ST.xy, 0); 116 #endif 117 #if defined(_SEA_FOAM_3) 118 slope += _Sea_Foam_3_Slope.SampleLevel(bilinear_repeat_s, uv * _Sea_Foam_3_Slope_ST.xy, 0); 119 #endif 120 121 float dfx_dx = slope[0]; 122 float dfy_dy = slope[1]; 123 float dfx_dy = slope[3]; 124 125 float Jxx = 1 + dfx_dx * _Sea_Foam_Lambda; 126 float Jyy = 1 + dfy_dy * _Sea_Foam_Lambda; 127 float Jxy = dfx_dy * _Sea_Foam_Lambda; 128 129 float det = Jxx * Jyy - Jxy * Jxy; 130 float foam_contribution = det; 131 foam_contribution += _Sea_Foam_Bias; 132 foam_contribution = saturate(foam_contribution); 133 134 pbr.albedo.rgb = lerp(pbr.albedo.rgb, _Sea_Foam_Color.rgb, foam_contribution * _Sea_Foam_Color.a); 135 pbr.smoothness = lerp(pbr.smoothness, 1.0f - _Sea_Foam_Roughness, foam_contribution); 136 propagateRoughness(pbr.smoothness, pbr.roughness_perceptual, pbr.roughness); 137} 138#endif 139 140// Returns fur thickness on [0, 1], 0 = no fur, 1 = max fur. 141float FurClip(v2f i, f2f f, inout YumPbr result) { 142#if defined(_FUR) 143 float fur_layer = i.vertexLight.w; 144 float2 fur_uv = i.uv01.xy * _Fur_Heightmap_ST.xy; 145 146#if defined(_FUR_WARPING) 147 float2 vnoise = valueNoise3D(i.objPos * _Fur_Warping_Frequency) * 2 - 1; 148 float3 vnoise_tbn = mul(vnoise, f.tbn); 149 fur_uv += vnoise_tbn.xy * (_Fur_Warping_Strength / _Fur_Warping_Frequency); 150#endif 151 152 float fur_thickness = _Fur_Heightmap.SampleBias( 153 trilinear_aniso4_repeat_s, fur_uv, 154 _Fur_Heightmap_Mip_Bias).r; 155 fur_thickness = tone(fur_thickness, _Fur_Thickness_Power); 156 clip(fur_thickness - fur_layer); 157 return fur_thickness; 158#else 159 return 0; 160#endif 161} 162 163YumPbr GetYumPbr(v2f i, f2f f) { 164 YumPbr result = (YumPbr)0; 165 166 float fur_thickness = FurClip(i, f, result); 167 168 float2 raw_uv = i.uv01.xy; 169#if defined(_UV_DOMAIN_WARPING) 170 { 171 float2 warped_uv = raw_uv; 172 float amplitude = _UV_Domain_Warping_Spatial_Strength; 173 float frequency = _UV_Domain_Warping_Spatial_Scale; 174 175 float2 speed_direction = _UV_Domain_Warping_Spatial_Direction; 176 float2 time_offset = speed_direction * _Time.y * _UV_Domain_Warping_Spatial_Speed; 177 178 const float lacunarity = 2.0; 179 const float persistence = 0.5; 180 181 [loop] 182 for (uint ii = 0; ii < _UV_Domain_Warping_Spatial_Octaves; ii++) { 183 float2 noise_uv = warped_uv * frequency + time_offset; 184 float2 offset_sample = _UV_Domain_Warping_Noise.SampleLevel(trilinear_repeat_s, noise_uv, 0).rg; 185 offset_sample = (offset_sample * 2.0 - 1.0); 186 warped_uv += offset_sample * amplitude; 187 frequency *= lacunarity; 188 amplitude *= persistence; 189 } 190 i.uv01.xy = warped_uv; 191 } 192#endif 193 194#if defined(OUTLINE_PASS) 195 result.albedo = _Outline_Color; 196 result.albedo.a *= tex2D(_MainTex, 197 UV_SCOFF(i, _MainTex_ST, /*which_channel=*/0)).a; 198#else 199 result.albedo = tex2D(_MainTex, 200 UV_SCOFF(i, _MainTex_ST, /*which_channel=*/0)) * _Color; 201#endif 202 203#if defined(_3D_SDF) 204 { 205 float2 sdf_uv_raw = get_uv_by_channel(i, _3D_SDF_UV_Channel); 206 float3 sdf_uv = float3(sdf_uv_raw, _3D_SDF_Z + _Time.y * _3D_SDF_Z_Speed); 207 sdf_uv.xy = saturate((sdf_uv.xy - (_3D_SDF_ST.zw + 0.5)) * _3D_SDF_ST.xy + (_3D_SDF_ST.zw + 0.5)); 208 float sdf_value = _3D_SDF_Texture.SampleLevel(trilinear_repeat_s, sdf_uv, 0).r; 209 float eps = 1E-4; 210 float4 is_lit = sdf_value < _3D_SDF_Thresholds && sdf_uv.x > eps && sdf_uv.x < 1 - eps && sdf_uv.y > eps && sdf_uv.y < 1 - eps; 211 float4 skin_albedo = result.albedo; 212 result.albedo.rgb = lerp(result.albedo.rgb, lerp(skin_albedo.rgb, _3D_SDF_Color_3.rgb, _3D_SDF_Color_3.a), is_lit.w); 213 result.albedo.rgb = lerp(result.albedo.rgb, lerp(skin_albedo.rgb, _3D_SDF_Color_2.rgb, _3D_SDF_Color_2.a), is_lit.z); 214 result.albedo.rgb = lerp(result.albedo.rgb, lerp(skin_albedo.rgb, _3D_SDF_Color_1.rgb, _3D_SDF_Color_1.a), is_lit.y); 215 result.albedo.rgb = lerp(result.albedo.rgb, lerp(skin_albedo.rgb, _3D_SDF_Color_0.rgb, _3D_SDF_Color_0.a), is_lit.x); 216 } 217#endif 218 219 float3 normal_tangent = UnpackScaleNormal( 220 tex2D(_BumpMap, UV_SCOFF_IMPL(raw_uv, _BumpMap_ST)), _BumpScale); 221 222#if defined(_DETAIL_MAPS) 223 float2 detail_uv = get_uv_by_channel(i, _Detail_Maps_UV_Channel); 224 float detail_mask = _DetailMask.SampleLevel(point_repeat_s, detail_uv, 0); 225 float4 detail_albedo = tex2D(_DetailAlbedoMap, 226 UV_SCOFF_IMPL(detail_uv, _DetailAlbedoMap_ST)); 227 float3 detail_normal = UnpackScaleNormal( 228 tex2D(_DetailNormalMap, 229 UV_SCOFF_IMPL(detail_uv, _DetailNormalMap_ST)), 230 _DetailNormalMapScale); 231 result.albedo = lerp(result.albedo, result.albedo * detail_albedo, detail_mask); 232 //result.albedo.a *= detail_albedo.a; 233 normal_tangent = lerp(normal_tangent, blendNormalsHill12(normal_tangent, detail_normal), detail_mask); 234#endif 235 236#if defined(_ALPHA_MULTIPLIER) 237 result.albedo.a = saturate(result.albedo.a * _Alpha_Multiplier); 238#endif 239 240#if defined(FORWARD_BASE_PASS) 241#if defined(_EMISSION) 242 result.emission = tex2D(_EmissionMap, UV_SCOFF(i, _EmissionMap_ST, /*which_channel=*/0)) * _EmissionColor; 243#endif 244#if defined(OUTLINE_PASS) 245 result.emission += _Outline_Color * _Outline_Emission; 246#endif 247#endif // FORWARD_BASE_PASS 248 249#if defined(_METALLICS) 250 float4 metallic_gloss = tex2D(_MetallicGlossMap, UV_SCOFF(i, _MetallicGlossMap_ST, /*which_channel=*/0)); 251 float metallic = metallic_gloss.r * _Metallic; 252 float smoothness = metallic_gloss.a * _Smoothness; 253 254 result.smoothness = smoothness; 255 result.metallic = metallic; 256#else 257 result.smoothness = 0.2; 258 result.metallic = 0; 259#endif 260 261#if defined(_AMBIENT_OCCLUSION) 262 result.ao = lerp(1, tex2D(_OcclusionMap, i.uv01), _OcclusionStrength); 263 result.ao = saturate(result.ao); 264#else 265 result.ao = 1; 266#endif 267 268#if defined(_FUR) 269 result.ao = lerp(result.ao, result.ao * fur_thickness, _Fur_AO_Strength); 270#endif 271 272 applyDecals(i, result.albedo, normal_tangent, result.metallic, result.smoothness, result.emission); 273 const float min_roughness_perceptual = 0.045f; 274 result.smoothness = min(1.0f - min_roughness_perceptual, result.smoothness); 275 propagateRoughness(result.smoothness, result.roughness_perceptual, result.roughness); 276 277#if defined(_OKLCH_CORRECTION) 278 float3 lch = LRGBtoOKLCH(result.albedo.rgb); 279 lch.x = lch.x * _Oklch_Correction_L; 280 lch.y = lch.y * _Oklch_Correction_C; 281 lch.z = lch.z * _Oklch_Correction_H; 282 result.albedo.rgb = OKLCHtoLRGB(lch); 283#endif 284 285#if defined(_OKLAB_BRIGHTNESS_CLAMP) 286 float3 lab = LRGBtoOKLAB(result.albedo.rgb); 287 lab.x = clamp(lab.x, _Oklab_Brightness_Clamp_Min, _Oklab_Brightness_Clamp_Max); 288 result.albedo.rgb = OKLABtoLRGB(lab); 289#endif 290 291 result.normal = normalize(mul(normal_tangent, f.tbn)); 292 293#if defined(_GRADIENT_NORMALS) 294 applyGradientNormals(i, result); 295#endif 296#if defined(_SEA_FOAM) 297 applySeaFoam(i, result); 298#endif 299 300#if (defined(FORWARD_BASE_PASS) || defined(FORWARD_ADD_PASS)) && defined(_GLITTER) 301 GlitterParams glitter_p; 302 glitter_p.color = _Glitter_Color; 303 glitter_p.uv_channel = _Glitter_UV_Channel; 304 glitter_p.layers = _Glitter_Layers; 305 glitter_p.cell_size = _Glitter_Grid_Size; 306 glitter_p.size = _Glitter_Size; 307 glitter_p.major_minor_ratio = _Glitter_Major_Minor_Ratio; 308 glitter_p.angle_randomization_range = _Glitter_Angle_Randomization_Range; 309 glitter_p.center_randomization_range = _Glitter_Center_Randomization_Range; 310 glitter_p.size_randomization_range = _Glitter_Size_Randomization_Range; 311 glitter_p.existence_chance = _Glitter_Existence_Chance; 312#if defined(_FUR) 313 glitter_p.seed = floor(i.vertexLight.w * _Fur_Layers); 314#else 315 glitter_p.seed = 0; 316#endif 317#if defined(_GLITTER_ANGLE_LIMIT) 318 glitter_p.angle_limit = _Glitter_Angle_Limit; 319 glitter_p.angle_limit_transition_width = _Glitter_Angle_Limit_Transition_Width; 320#endif 321#if defined(_GLITTER_MASK) 322 glitter_p.mask = _Glitter_Mask.SampleLevel(linear_repeat_s, i.uv01.xy, 0); 323#endif 324 float4 glitter_albedo = getGlitter(i, f, glitter_p, result.normal); 325 result.albedo = alphaBlend(result.albedo, glitter_albedo); 326 327 result.emission += glitter_albedo.rgb * glitter_albedo.a * _Glitter_Emission; 328#endif 329 330#if defined(_ANISOTROPY) 331 result.binormal = normalize(cross(result.normal, i.tangent.xyz) * i.tangent.w); 332#endif 333 334 return result; 335} 336 337#endif 338