yum-archive/Tooner

A toon shader for Unity's BIRP.

git clone https://git.yummers.dev/yum-archive/Tooner

yumAdd new eye gimmick6e34fcb

master
7.7 KiB330 linesraw
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