yum-archive/2ner
A toon shader for Unity's BIRP.
git clone https://git.yummers.dev/yum-archive/2ner
715bf39
master
1#ifndef __CUSTOM30_INC 2#define __CUSTOM30_INC 3 4#include "globals.cginc" 5#include "math.cginc" 6#include "pema99.cginc" 7#include "quilez.cginc" 8#include "interpolators.cginc" 9#include "texture_utils.cginc" 10 11#if defined(_CUSTOM30) 12 13#if defined(_DEPTH_PREPASS) 14#define CUSTOM30_MAX_STEPS 10 15#else 16#define CUSTOM30_MAX_STEPS 30 17#endif 18 19struct Custom30Output { 20 float3 objPos; 21 float3 normal; 22 float depth; 23}; 24 25float3 GetFragToOrigin(v2f i) { 26 return (i.color * 2.0f - 1.0f) / i.color.a; 27} 28 29float4 GetRotation(v2f i, float2 uv_channels) { 30 float4 quat; 31 quat.xy = get_uv_by_channel(i, uv_channels.x); 32 quat.zw = get_uv_by_channel(i, uv_channels.y); 33 return quat; 34} 35 36float cut_with_box(float3 p, float d, float3 box_size) { 37 float2 pp_xy = p.xy; 38 float2 pp_xz = p.xz; 39 float2 pp_yz = p.yz; 40 41 // Rotate by 45 degrees 42 pp_xy = rot45(pp_xy); 43 d = max(d, distance_from_box(float3(pp_xy, p.z), box_size)); 44 45 pp_xz = rot45(pp_xz); 46 d = max(d, distance_from_box(float3(pp_xz, p.y), box_size)); 47 48 pp_yz = rot45(pp_yz); 49 d = max(d, distance_from_box(float3(pp_yz, p.x), box_size)); 50 51 return d; 52} 53 54float distance_from_hex_comb( 55 float3 p, 56 float3 period, 57 float hex_sc, 58 float zoff, 59 float count) { 60 float3 p_hex = cart_to_hex(p.xy); 61 62 float half_period = period * 0.5; 63 float3 which = abs(floor((p_hex + half_period) / period)); 64 65 // The original code here was this: 66 // p_hex = glsl_mod(p_hex + half_period, period) - half_period; 67 // 68 // But you can simplify it. Given the definition of glsl_mod: 69 // #define glsl_mod(x,y) (((x)-(y)*floor((x)/(y)))) 70 // 71 // You can plug in terms: 72 // (p_hex + half_period) - (period) * floor((p_hex + half_period) / period) 73 // = p_hex + half_period - period * floor(p_hex/period + 0.5) 74 // 75 // For all x, 76 // round(x) = floor(x + 0.5) 77 // 78 // Continuing to simplify: 79 // (p_hex + half_period - period * round(p_hex/period)) - half_period 80 // = p_hex - period * round(p_hex / period) 81 p_hex = p_hex - period * round(p_hex / period); 82 83 p.xy = hex_to_cart(p_hex); 84 85 float hex_d = distance_from_hex_prism(p - 86 float3(0, 0, zoff), hex_sc); 87 hex_d = any(which > count) ? 1E9 : hex_d; 88 return hex_d; 89} 90 91float distance_from_hex_grid( 92 float3 p, 93 float2 period, 94 float hex_sc, 95 float zoff, 96 float count) { 97 float half_period = period * 0.5; 98 float2 which = abs(floor((p.xy + half_period) / period)); 99 p.xy = glsl_mod(p.xy + half_period, period) - half_period; 100 101 float hex_d = distance_from_hex_prism(p - 102 float3(0, 0, zoff), hex_sc); 103 hex_d = any(which > count) ? 1E9 : hex_d; 104 hex_d = any(which % 2 == 0) ? 1E9 : hex_d; 105 return hex_d; 106} 107 108#if defined(_CUSTOM30_BASICCUBE) 109float BasicCube_map(float3 p) { 110 float box_d = distance_from_box_frame(p, .995, .15); 111 float core_dim = 0.95; 112 float core_d = distance_from_box(p, core_dim); 113 float d = min(box_d, core_d); 114 115#if defined(_CUSTOM30_BASICCUBE_CHAMFER) 116 d = cut_with_box(p, d, 1.3); 117#endif 118 119#if defined(_CUSTOM30_BASICCUBE_HEX_GRIP) 120 [branch] 121 { 122 float period = 0.1; 123 float hex_sc = period * 0.2; 124 float count = 13; 125 126 float zoff = core_dim - (hex_sc * 0.2); 127 128 float3 pp = abs(p); 129 pp = pp.z > pp.x && pp.z > pp.y ? pp.xyz : pp; 130 pp = pp.y > pp.x && pp.y > pp.z ? pp.zxy : pp; 131 pp = pp.x > pp.y && pp.x > pp.z ? pp.yzx : pp; 132 133 float hex_d = distance_from_hex_comb(pp, period, hex_sc, zoff, count); 134 hex_d = any(pp.xy > 0.85) ? 1E9 : hex_d; 135 d = min(d, hex_d); 136 } 137#endif 138 139#if defined(_CUSTOM30_BASICCUBE_HEX_BOLTS) 140 { 141 float period = 0.83; 142 float hex_sc = period * 0.1; 143 float count = 3; 144 145 float zoff = core_dim; 146 147 float3 pp = abs(p); 148 pp = pp.z > pp.x && pp.z > pp.y ? pp.xyz : pp; 149 pp = pp.y > pp.x && pp.y > pp.z ? pp.zxy : pp; 150 pp = pp.x > pp.y && pp.x > pp.z ? pp.yzx : pp; 151 d = min(d, distance_from_hex_grid(pp, period, hex_sc, zoff, count)); 152 } 153#endif 154 155 return d; 156} 157 158float3 BasicCube_normal(float3 p) { 159 float3 fw = fwidth(p); 160 float epsilon = length(fw) * 0.5f; 161 float center_d = BasicCube_map(p); 162 float3 n = float3( 163 BasicCube_map(p + float3(epsilon, 0, 0)) - center_d, 164 BasicCube_map(p + float3(0, epsilon, 0)) - center_d, 165 BasicCube_map(p + float3(0, 0, epsilon)) - center_d); 166 return normalize(n); 167} 168 169Custom30Output BasicCube(v2f i) { 170 float3 obj_space_camera_pos = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos, 1.0)); 171 float3 frag_to_origin = GetFragToOrigin(i); 172 173 float2 uv_channels = float2(_Custom30_Quaternion_UV_Channel_0, _Custom30_Quaternion_UV_Channel_1); 174 float4 quat = GetRotation(i, uv_channels); 175 float4 iquat = float4(-quat.xyz, quat.w); 176 177 float3 ro = -frag_to_origin; 178 float3 rd = normalize(i.objPos - obj_space_camera_pos); 179 rd = rotate_vector(rd, iquat); 180 181#if defined(_CUSTOM30_BASICCUBE_HEX_BOLTS) 182 float3 n = rotate_vector(normalize(mul(unity_WorldToObject, i.normal)), iquat); 183 // Get projected length of rd on normal. 184 float rd_proj_len = dot(rd, n); 185 // Move ray enough to give us `ro_Offset` gap. 186 ro += rd * _Custom30_ro_Offset / rd_proj_len; 187#endif 188 189 float epsilon = 5e-3f; 190 float d; 191 float d_acc = 0; 192 // 1.73... = sqrt(3) 193 // our cube has an edge length of 2, so mult by 2 194 float max_d = 1.73205081f * 2.0f; 195 196 uint ii = 0; 197 198 [loop] 199 for (; ii < CUSTOM30_MAX_STEPS; ++ii) { 200 float3 p = ro + rd * d_acc; 201 d = BasicCube_map(p); 202 d_acc += d; 203 if (d < epsilon) break; 204 if (d_acc > max_d) break; 205 } 206 207 float3 localHit = ro + rd * d_acc; 208 209 Custom30Output o; 210#if !defined(_DEPTH_PREPASS) 211 clip(epsilon - d); 212#endif 213 float3 objHit = rotate_vector(localHit, quat); 214 float3 objCenterOffset = rotate_vector(frag_to_origin, quat); 215 216 o.objPos = objHit + (i.objPos + objCenterOffset); 217 float4 clipPos = UnityObjectToClipPos(o.objPos); 218 o.depth = clipPos.z / clipPos.w; 219 220 float3 sdfNormal = BasicCube_normal(localHit); 221 float3 objNormal = rotate_vector(sdfNormal, quat); 222 o.normal = UnityObjectToWorldNormal(objNormal); 223 224 return o; 225} 226#endif 227 228#if defined(_CUSTOM30_BASICWEDGE) 229float BasicWedge_map(float3 p) { 230 float box_d = distance_from_box(p, float3(1, 1, 1)); 231 float cut_plane_d = distance_from_plane(p - float3(0, 0, 0), -normalize(float3(1, 0, 1)), 0); 232 233 float d = op_sub(box_d, cut_plane_d); 234 235 return d; 236} 237 238float3 BasicWedge_normal(float3 p) { 239 float3 fw = fwidth(p); 240 float epsilon = max((fw.x+fw.y+fw.z) * 0.5f, 5e-3f); 241 float center_d = BasicWedge_map(p); 242 float3 n = float3( 243 BasicWedge_map(p + float3(epsilon, 0, 0)) - center_d, 244 BasicWedge_map(p + float3(0, epsilon, 0)) - center_d, 245 BasicWedge_map(p + float3(0, 0, epsilon)) - center_d); 246 return normalize(n); 247} 248 249Custom30Output BasicWedge(v2f i) { 250 float3 obj_space_camera_pos = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos, 1.0)); 251 float3 frag_to_origin = GetFragToOrigin(i); 252 253 float2 uv_channels = float2(_Custom30_Quaternion_UV_Channel_0, _Custom30_Quaternion_UV_Channel_1); 254 float4 quat = GetRotation(i, uv_channels); 255 float4 iquat = float4(-quat.xyz, quat.w); 256 257 float3 frag_to_origin_obj = rotate_vector(frag_to_origin, iquat); 258 float3 origin = i.objPos + frag_to_origin_obj; 259 float3 objSpaceCameraPos = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos, 1.0)); 260 float distance_from_camera_obj = length(objSpaceCameraPos - origin); 261 262 float3 ro = -frag_to_origin; 263 float3 rd = normalize(i.objPos - obj_space_camera_pos); 264 rd = rotate_vector(rd, iquat); 265 266 ro -= rd * _Custom30_ro_Offset; 267 268 float d; 269 float d_acc = 0; 270 float epsilon = 5e-3f; 271 // 1.73... = sqrt(3) 272 // our cube has an edge length of 2, so mult by 2 273 float max_d = 1.73205081f * 2.0f; 274 275 uint ii = 0; 276 277 [loop] 278 for (; ii < CUSTOM30_MAX_STEPS; ++ii) { 279 float3 p = ro + rd * d_acc; 280 d = BasicWedge_map(p); 281 d_acc += d; 282 if (d < epsilon) break; 283 if (d_acc > max_d) break; 284 } 285 286 Custom30Output o; 287#if !defined(_DEPTH_PREPASS) 288 clip(epsilon - d); 289#endif 290 float3 localHit = ro + rd * d_acc; 291 float3 objHit = rotate_vector(localHit, quat); 292 float3 objCenterOffset = rotate_vector(frag_to_origin, quat); 293 294 o.objPos = objHit + (i.objPos + objCenterOffset); 295 float4 clipPos = UnityObjectToClipPos(o.objPos); 296 o.depth = clipPos.z / clipPos.w; 297 298 float3 sdfNormal = BasicWedge_normal(localHit); 299 float3 objNormal = rotate_vector(sdfNormal, quat); 300 o.normal = UnityObjectToWorldNormal(objNormal); 301 302 return o; 303} 304#endif 305 306#if defined(_CUSTOM30_BASICPLATFORM) 307float BasicPlatform_map(float3 p) { 308 p = abs(p.zyx); 309 310 float3 platform_size = _Custom30_BasicPlatform_Size; 311 float box_d = distance_from_box_frame(p, platform_size, _Custom30_BasicPlatform_Frame_D); 312 float core_d = distance_from_box(p, platform_size - _Custom30_BasicPlatform_Core_D); 313 float d = min(box_d, core_d); 314 315#if defined(_CUSTOM30_BASICPLATFORM_CHAMFER) 316 { 317 float3 pp = p; 318 pp.yz = float2(RCP_SQRT_2 * p.y - RCP_SQRT_2 * p.z, RCP_SQRT_2 * p.y + RCP_SQRT_2 * p.z); 319 float c = _Custom30_BasicPlatform_Chamfer_Size.x; 320 d = max(d, distance_from_box(pp, float3(1.0, c, c))); 321 } 322 { 323 float3 pp = p; 324 pp.xz = float2(RCP_SQRT_2 * p.x - RCP_SQRT_2 * p.z, RCP_SQRT_2 * p.x + RCP_SQRT_2 * p.z); 325 float c = _Custom30_BasicPlatform_Chamfer_Size.y; 326 d = max(d, distance_from_box(pp, float3(c, 1.0, c))); 327 } 328 { 329 float3 pp = p; 330 pp.xy = float2(RCP_SQRT_2 * p.x - RCP_SQRT_2 * p.y, RCP_SQRT_2 * p.x + RCP_SQRT_2 * p.y); 331 float c = _Custom30_BasicPlatform_Chamfer_Size.z; 332 d = max(d, distance_from_box(pp, float3(c, c, 1.0))); 333 } 334#endif 335 336 return d; 337} 338 339float3 BasicPlatform_normal(float3 p) { 340 float3 fw = fwidth(p); 341 float epsilon = max((fw.x+fw.y+fw.z) * 0.5f, 5e-3f); 342 float center_d = BasicPlatform_map(p); 343 float3 n = float3( 344 BasicPlatform_map(p + float3(epsilon, 0, 0)) - center_d, 345 BasicPlatform_map(p + float3(0, epsilon, 0)) - center_d, 346 BasicPlatform_map(p + float3(0, 0, epsilon)) - center_d); 347 return normalize(n); 348} 349 350Custom30Output BasicPlatform(v2f i) { 351 float3 obj_space_camera_pos = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos, 1.0)); 352 float3 frag_to_origin = GetFragToOrigin(i); 353 354 float2 uv_channels = float2(_Custom30_Quaternion_UV_Channel_0, _Custom30_Quaternion_UV_Channel_1); 355 float4 quat = GetRotation(i, uv_channels); 356 float4 iquat = float4(-quat.xyz, quat.w); 357 358 float3 ro = -frag_to_origin; 359 float3 rd = normalize(i.objPos - obj_space_camera_pos); 360 rd = rotate_vector(rd, iquat); 361 362 ro -= rd * _Custom30_ro_Offset; 363 364 float d; 365 float d_acc = 0; 366 float epsilon = 5e-3; 367 // Max distance for platform bounding sphere 368 float max_d = length(float3(1.0, 0.4, 0.2)) * 2.0f; 369 370 uint ii = 0; 371 372 [loop] 373 for (; ii < CUSTOM30_MAX_STEPS; ++ii) { 374 float3 p = ro + rd * d_acc; 375 d = BasicPlatform_map(p); 376 d_acc += d; 377 if (d < epsilon) break; 378 if (d_acc > max_d) break; 379 } 380 381 Custom30Output o; 382#if !defined(_DEPTH_PREPASS) 383 clip(epsilon - d); 384#endif 385 float3 localHit = ro + rd * d_acc; 386 float3 objHit = rotate_vector(localHit, quat); 387 float3 objCenterOffset = rotate_vector(frag_to_origin, quat); 388 389 o.objPos = objHit + (i.objPos + objCenterOffset); 390 float4 clipPos = UnityObjectToClipPos(o.objPos); 391 o.depth = clipPos.z / clipPos.w; 392 393 float3 sdfNormal = BasicPlatform_normal(localHit); 394 float3 objNormal = rotate_vector(sdfNormal, quat); 395 o.normal = UnityObjectToWorldNormal(objNormal); 396 397 return o; 398} 399#endif 400 401#endif // _CUSTOM30 402#endif // __CUSTOM30_INC