yum-archive/Tooner
A toon shader for Unity's BIRP.
git clone https://git.yummers.dev/yum-archive/Tooner
6e34fcb
master
1#include "globals.cginc" 2#include "interpolators.cginc" 3#include "iq_sdf.cginc" 4#include "math.cginc" 5 6#ifndef __EYES_INC 7#define __EYES_INC 8 9#if defined(_GIMMICK_EYES_00) 10 11float eyes00_distance_from_sphere(float3 p, float3 c, float r) 12{ 13 return length(p - c) - r; 14} 15 16float eyes00_map(float3 p) 17{ 18 float t = _Time.y; 19 float theta = sin(_Time[0]) / 2; 20 float2x2 rot = float2x2( 21 cos(theta), -sin(theta), 22 sin(theta), cos(theta)); 23 24 float dist = 1000 * 1000 * 1000; 25 #define Y_STEPS 5 26 for (int y = 0; y < Y_STEPS; y++) 27 { 28 const int yy = y - Y_STEPS/2; 29 #define X_STEPS 5 30 for (int x = 0; x < X_STEPS; x++) 31 { 32 const int xx = x - X_STEPS/2; 33 float2 pp = float2(xx * 2, yy * 2); 34 pp = mul(rot, pp); 35 float radius = cos((x + y + _Time[0]) * 3.14159) * 0.5 + 1; 36 float sphere = eyes00_distance_from_sphere(p, float3(pp.x, pp.y, 0.0), radius); 37 dist = min(dist, sphere); 38 dist += sin(5.0 * pp.x) * sin(5.0 * pp.y) * 0.5; 39 } 40 } 41 42 return dist; 43} 44 45float3 eyes00_calc_normal(in float3 p) 46{ 47 const float3 small_step = float3(0.0001, 0.0, 0.0); 48 49 float gradient_x = eyes00_map(p + small_step.xyy) - eyes00_map(p - small_step.xyy); 50 float gradient_y = eyes00_map(p + small_step.yxy) - eyes00_map(p - small_step.yxy); 51 float gradient_z = eyes00_map(p + small_step.yyx) - eyes00_map(p - small_step.yyx); 52 53 float3 normal = float3(gradient_x, gradient_y, gradient_z); 54 55 return normalize(normal); 56} 57 58float3 __eyes00_march(float3 ro, float3 rd, inout float3 normal) 59{ 60 float total_distance_traveled = 0.0; 61 const float MINIMUM_HIT_DISTANCE = 0.001; 62 const float MAXIMUM_TRACE_DISTANCE = 1000.0; 63 64 #define EYES00_MARCH_STEPS 10 65 float distance_to_closest; 66 float3 current_position; 67 for (int i = 0; i < EYES00_MARCH_STEPS; i++) 68 { 69 current_position = ro + total_distance_traveled * rd; 70 71 distance_to_closest = eyes00_map(current_position); 72 73 if (distance_to_closest < MINIMUM_HIT_DISTANCE) 74 { 75 break; 76 } 77 78 if (total_distance_traveled > MAXIMUM_TRACE_DISTANCE) 79 { 80 break; 81 } 82 total_distance_traveled += distance_to_closest; 83 } 84 85 if (distance_to_closest < MINIMUM_HIT_DISTANCE) { 86 normal = eyes00_calc_normal(current_position); 87 return float3(1.0, 1.0, 1.0); 88 } 89 90 return float3(0, 0, 0); 91} 92 93float4 eyes00_march(float2 uv, inout float3 normal) 94{ 95 uv = uv * 2.0 - 1.0; 96 97 float3 camera_position = float3(0.0, 0.0, -5.0); 98 float3 ro = camera_position; 99 float3 rd = float3(uv.x, uv.y, 1.0); 100 101 float3 shaded_color = __eyes00_march(ro, rd, normal); 102 103 return float4(shaded_color, 1.0); 104} 105 106#endif // _GIMMICK_EYES_00 107 108#if defined(_GIMMICK_EYES_01) 109 110struct Eyes01PBR { 111 float4 albedo; 112 float3 normal; 113}; 114 115float eyes01_map(float3 p) 116{ 117 return length(p) - .01; 118} 119 120float3 eyes01_calc_normal(in float3 p) 121{ 122 const float3 small_step = float3(0.0001, 0.0, 0.0); 123 124 float gradient_x = eyes01_map(p + small_step.xyy) - eyes01_map(p - small_step.xyy); 125 float gradient_y = eyes01_map(p + small_step.yxy) - eyes01_map(p - small_step.yxy); 126 float gradient_z = eyes01_map(p + small_step.yyx) - eyes01_map(p - small_step.yyx); 127 128 float3 normal = float3(gradient_x, gradient_y, gradient_z); 129 130 return normalize(normal); 131} 132 133void __eyes01_march(float3 ro, float3 rd, inout Eyes01PBR result) 134{ 135 float total_distance_traveled = 0.0; 136 const float MINIMUM_HIT_DISTANCE = 0.001; 137 const float MAXIMUM_TRACE_DISTANCE = 1000.0; 138 139#define EYES01_MARCH_STEPS 50 140 float distance_to_closest; 141 float3 current_position; 142 for (int i = 0; i < EYES01_MARCH_STEPS; i++) 143 { 144 current_position = ro + total_distance_traveled * rd; 145 146 distance_to_closest = eyes01_map(current_position); 147 148 if (distance_to_closest < MINIMUM_HIT_DISTANCE) 149 { 150 break; 151 } 152 153 if (total_distance_traveled > MAXIMUM_TRACE_DISTANCE) 154 { 155 break; 156 } 157 total_distance_traveled += distance_to_closest; 158 } 159 160 if (distance_to_closest < MINIMUM_HIT_DISTANCE) { 161 result.normal = eyes01_calc_normal(current_position); 162 result.albedo = 1; 163 } 164 165 result.normal = float3(0, 0, 1); // doesn't matter 166 result.albedo = 0; 167} 168 169Eyes01PBR eyes01_march(v2f i) 170{ 171 Eyes01PBR result; 172 173 float3 cam_pos = _WorldSpaceCameraPos; 174 float3 ro = cam_pos; 175 float3 rd = normalize(i.worldPos - cam_pos); 176 177 float r_world = _Gimmick_Eyes01_Radius; 178 float3 o = -i.normal * r_world; 179 180 ro -= o; 181 182 __eyes01_march(ro, rd, result); 183 184 return result; 185} 186 187#endif // _GIMMICK_EYES_01 188 189#if defined(_GIMMICK_EYES_02) 190 191struct chaos_data 192{ 193 uint n; // degrees of symmetry 194 int p; 195 float a0; 196 float a1; 197 float a2; 198 float a3; 199 float a4; 200 complex z; 201}; 202 203void iterate0(inout struct chaos_data d) 204{ 205 complex z_conj = cconjugate(d.z); 206 complex z_conj_n_1 = cpow(z_conj, d.n); 207 complex z_n = cpow(d.z, d.n); 208 209 complex next = 210 cmul(( 211 complex(d.a0, 0) + 212 d.a1 * cmul(d.z, cconjugate(d.z)) + 213 complex(d.a2 * creal(z_n), 0) + 214 complex(0, d.a3) 215 ), 216 d.z) + 217 d.a4 * z_conj_n_1; 218 219 d.z = next; 220} 221 222void iterate1(inout struct chaos_data d) 223{ 224 complex z_conj = cconjugate(d.z); 225 complex z_conj_n_1 = cpow(z_conj, d.n - 1); 226 complex z_n = cpow(d.z, d.n); 227 228 complex next = 229 (d.a0 + 230 d.a1 * (d.z.x * d.z.x - d.z.y * d.z.y) + 231 d.a2 * creal(z_n) + 232 d.a3 * creal(cmul(cpow((cdiv(d.z, abs(d.z))), d.n * d.p), abs(d.z)))) * 233 d.z + 234 d.a4 * (z_conj_n_1); 235 236 d.z = next; 237} 238 239// Return a number on (0, inf) 240float get_chaos(in float2 uv, inout chaos_data d) 241{ 242 complex z = uv; 243 // Remap onto [-1, 1] 244 float scale = 2.0; 245 z = z * scale * 2 - scale; 246 d.z = z; 247 248 for (int i = 0; i < 6; i++) { 249 iterate0(d); 250 } 251 252 float l = d.z.x * d.z.x - d.z.y * d.z.y; 253 if (l < 1) { 254 float b = .1; 255 return b/l; 256 } else { 257 return 0; 258 } 259} 260 261float3 get_chaos_normal(in float2 uv, inout chaos_data d) 262{ 263 float2 small_step = float2(.0001, 0); 264 float dx = get_chaos(uv + small_step.xy, d) - get_chaos(uv, d); 265 float dz = get_chaos(uv + small_step.yx, d) - get_chaos(uv, d); 266 float dy = small_step.x; 267 268 float3 normal = float3(dx, dy, dz); 269 return UnityObjectToWorldNormal(normalize(normal)); 270} 271 272bool eyes02_march(float2 uv, inout float3 normal) 273{ 274 float2 uv_scale = _Gimmick_Eyes02_UV_Adjust.xy; 275 float2 uv_center = _Gimmick_Eyes02_UV_Adjust.zw; 276 uv -= 0.5; 277 278 if (_Gimmick_Eyes02_UV_X_Symmetry) { 279 uv.x = abs(uv.x); 280 } 281 282 uv -= (uv_center - 0.5); 283 uv /= uv_scale; 284 285 uv += 0.5; 286 287 float t20 = _Time[0] * _Gimmick_Eyes02_Animate_Speed; 288 float t = _Time[1] * _Gimmick_Eyes02_Animate_Speed; 289 290 struct chaos_data d; 291 d.n = _Gimmick_Eyes02_N; 292 d.p = _Gimmick_Eyes02_N; 293 d.a0 = _Gimmick_Eyes02_A0; 294 d.a1 = _Gimmick_Eyes02_A1; 295 d.a2 = _Gimmick_Eyes02_A2; 296 d.a3 = _Gimmick_Eyes02_A3; 297 d.a4 = _Gimmick_Eyes02_A4; 298 299 if (_Gimmick_Eyes02_Animate) { 300 float effect = 1; 301 float e = _Gimmick_Eyes02_Animate_Strength; 302 if (round(effect) == 0) { 303 d.a0 += (sin(t * 1.1) * .01 + sin(t20 * 1.1) * .75) * e; 304 d.a1 += (sin(t * 1.3) * .01 + sin(t20 * 1.3) * .75) * e; 305 d.a2 += (sin(t * 1.7) * .01 + sin(t20 * 1.7) * 1) * e; 306 d.a3 += (sin(t * 1.9) * .01 + sin(t20 * 1.9) * .75) * e; 307 d.a4 += (sin(t * 2.3) * .02 + sin(t20 * 2.3) * .4) * e; 308 } else if (round(effect) == 1) { 309 d.a0 += (sin(t * 1.1) * .01 + sin(t20 * 1.1) * .75) * e; 310 d.a1 += (sin(t * 1.3) * .01 + sin(t20 * 1.3) * .75) * e; 311 d.a2 += (sin(t * 1.7) * .01 + sin(t20 * 1.7) * 1) * e; 312 d.a3 += (sin(t * 1.9) * .0005 + sin(t20 * 1.9) * .05) * e; 313 d.a4 += (sin(t * 2.3) * .02 + sin(t20 * 2.3) * 1) * e; 314 } 315 } 316 317 float c = get_chaos(uv, d); 318 c = exp(-c); 319 320 if (c < 1) { 321 normal = get_chaos_normal(uv, d); 322 } 323 bool is_ray_hit = (c < 1); 324 return is_ray_hit; 325} 326 327#endif // _GIMMICK_EYES_02 328 329#endif // __EYES_INC 330