yum-archive/Tooner

A toon shader for Unity's BIRP.

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

yumReimplement faceme gimmickccbf413

master
12.9 KiB402 linesraw
1#include "UnityCG.cginc"
2#include "AutoLight.cginc"
3#include "UnityPBSLighting.cginc"
4
5#include "audiolink.cginc"
6#include "clones.cginc"
7#include "cnlohr.cginc"
8#include "gerstner.cginc"
9#include "globals.cginc"
10#include "interpolators.cginc"
11#include "math.cginc"
12#include "pbr.cginc"
13#include "oklab.cginc"
14#include "trochoid_math.cginc"
15#include "tooner_scroll.cginc"
16#include "UnityCG.cginc"
17
18#ifndef __TOONER_OUTLINE_PASS
19#define __TOONER_OUTLINE_PASS
20
21#define _OUTLINE_INTERPOLATORS
22
23v2f vert(appdata v)
24{
25#if defined(_DISCARD)
26  if (_Discard_Enable_Dynamic) {
27    return (v2f) (0.0 / 0.0);
28  }
29#endif
30  v2f o;
31
32  UNITY_INITIALIZE_OUTPUT(v2f, o);
33  UNITY_SETUP_INSTANCE_ID(v);
34  UNITY_TRANSFER_INSTANCE_ID(v, o);
35  UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
36
37#if defined(_TROCHOID)
38  {
39    v.vertex.xyz = cyl2_to_troch_map(cyl_to_cyl2_map(cart_to_cyl_map(v.vertex.xyz)));
40  }
41#endif
42
43  float4 objPos = v.vertex;
44
45#if defined(_OUTLINES)
46#if !defined(_SCROLL) && defined(_GIMMICK_GERSTNER_WATER)
47  {
48    GerstnerParams p = getGerstnerParams();
49    objPos.xyz = gerstner_vert(objPos.xyz, p);
50    GerstnerFragResult r = gerstner_frag(objPos.xyz, p);
51    v.normal = r.normal;
52  }
53#endif
54#endif
55
56#if defined(_OUTLINES)
57  float outline_mask = _Outline_Mask.SampleLevel(linear_repeat_s, v.uv0.xy, /*lod=*/0);
58  outline_mask = _Outline_Mask_Invert > 1E-9 ? 1 - outline_mask : outline_mask;
59
60  objPos.xyz += v.normal * _Outline_Width * outline_mask * _Outline_Width_Multiplier;
61#endif
62
63#if defined(_FACE_ME_WORLD_Y)
64  [branch]
65  if (_FaceMeWorldY_Enable_Dynamic) {
66    float3 object_center = mul(unity_ObjectToWorld, float4(0, 0, 0, 1));
67    // Get forward axis of object coordinate system, i.e. the orientation of
68    // the hip bone.
69    // Then project it onto the xz plane.
70    float3 forward_axis = mul(unity_ObjectToWorld, float3(0, 0, 1));
71    forward_axis.y = 0;
72    forward_axis = normalize(forward_axis);
73    float4 worldPos = mul(unity_ObjectToWorld, objPos);
74    float3 rd = normalize((worldPos.xyz - object_center) - getCenterCamPos());
75    // We apply a factor of -1 to shift the result forward by a phase shift of pi.
76    float cos_t = -dot(normalize(rd.xz), forward_axis.xz);
77    // We want to get sin(t) using the identity:
78    //   || a x b || = || a || || b || sin(t)
79    // For normal vectors, this simplifies to:
80    //   || a x b || = sin(t)
81    // The issue is that the norm operator loses the sign.
82    // We can estimate the sign by assuming that `rd` and `forward_axis` are on
83    // the xz plane.
84    // If that's the case, then the cross product is necessarily constrained to
85    // the y axis.
86    float sin_t_sign = sign(cross(rd, forward_axis).y);
87    // Here we use the identity:
88    //   sin(t) = sqrt(1 - cos(t)^2)
89    // We simply apply the sign correction `sin_t_sign` to the result.
90    // We then invert it, since the goal is not to amplify the rotation, but
91    // to negate it.
92    // Finally, we add a phase correction to make the abomination face us.
93    float sin_t = -sqrt(1 - cos_t * cos_t) * sin_t_sign;
94    float2x2 face_me_rot = float2x2(cos_t, -sin_t, sin_t, cos_t);
95    float2x2 face_me_rot_inv = float2x2(cos_t, sin_t, -sin_t, cos_t);
96    worldPos.xz = mul(face_me_rot, (worldPos.xz - object_center.xz)) + object_center.xz;
97    objPos = mul(unity_WorldToObject, worldPos);
98    float3 world_normal = UnityObjectToWorldNormal(v.normal);
99    world_normal.xz = mul(face_me_rot_inv, world_normal.xz);
100    v.normal = normalize(mul(unity_WorldToObject, world_normal));
101  }
102#endif
103
104#if !defined(_SCROLL) && defined(_GIMMICK_SPHERIZE_LOCATION)
105  if (_Gimmick_Spherize_Location_Enable_Dynamic) {
106    float r = _Gimmick_Spherize_Location_Radius;
107    float s = _Gimmick_Spherize_Location_Strength;
108    float l = length(objPos.xyz);
109    objPos.xyz *= lerp(1, (r / l), s);
110  }
111#endif
112#if !defined(_SCROLL) && defined(_GIMMICK_SHEAR_LOCATION)
113  if (_Gimmick_Shear_Location_Enable_Dynamic) {
114     objPos = mul(float4x4(
115        _Gimmick_Shear_Location_Strength.x, 0, 0, 0,
116        0, _Gimmick_Shear_Location_Strength.y, 0, 0,
117        0, 0, _Gimmick_Shear_Location_Strength.z, 0,
118        0, 0, 0, _Gimmick_Shear_Location_Strength.w),
119        objPos);
120  }
121#endif
122
123  o.worldPos = mul(unity_ObjectToWorld, objPos);
124  o.objPos = objPos;
125  o.pos = UnityObjectToClipPos(objPos);
126  o.normal = UnityObjectToWorldNormal(v.normal);
127  o.uv0 = v.uv0;
128#if !defined(_OPTIMIZE_INTERPOLATORS)
129  o.uv1 = v.uv1;
130#if defined(LIGHTMAP_ON)
131  o.uv2 = v.uv2 * unity_LightmapST.xy + unity_LightmapST.zw;
132  UNITY_TRANSFER_LIGHTING(o, v.uv1);
133#else
134  o.uv2 = v.uv2;
135  o.uv3 = v.uv3;
136  o.uv4 = v.uv4;
137  o.uv5 = v.uv5;
138  o.uv6 = v.uv6;
139  o.uv7 = v.uv7;
140#endif
141#endif  // _OPTIMIZE_INTERPOLATORS
142
143  o.centerCamPos = getCenterCamPos();
144  return o;
145}
146
147// maxvertexcount == the number of vertices we create
148#if defined(_CLONES)
149[maxvertexcount(15)]
150#else
151[maxvertexcount(3)]
152#endif
153void geom(triangle v2f tri_in[3],
154  uint pid: SV_PrimitiveID,
155  inout TriangleStream<v2f> tri_out)
156{
157  v2f v0 = tri_in[0];
158  v2f v1 = tri_in[1];
159  v2f v2 = tri_in[2];
160
161  float3 v0_objPos;
162  float3 v1_objPos;
163  float3 v2_objPos;
164
165  const float pid_rand = rand((int) pid);
166  float explode_phase = 0;
167#if defined(_EXPLODE)
168  float3 n = normalize(cross(v1.worldPos - v0.worldPos, v2.worldPos - v0.worldPos));
169  float3 avg_pos;
170
171  float3 n0 = v0.normal;
172  float3 n1 = v1.normal;
173  float3 n2 = v2.normal;
174
175  explode_phase = _Explode_Phase;
176  explode_phase = smoothstep(0, 1, explode_phase);
177  explode_phase *= explode_phase;
178  explode_phase *= 4;
179
180  if (explode_phase > 1E-6) {
181    float3 axis = normalize(float3(
182          rand((int) ((v0.uv0.x + v0.uv0.y) * 1E9)) * 2 - 1,
183          rand((int) ((v1.uv0.x + v1.uv0.y) * 1E9)) * 2 - 1,
184          rand((int) ((v2.uv0.x + v2.uv0.y) * 1E9)) * 2 - 1));
185    float3 np = BlendNormals(n, axis * explode_phase);
186
187    v0.worldPos += np * explode_phase * pid_rand;
188    v1.worldPos += np * explode_phase * pid_rand;
189    v2.worldPos += np * explode_phase * pid_rand;
190
191    v0_objPos = mul(unity_WorldToObject, float4(v0.worldPos, 1));
192    v1_objPos = mul(unity_WorldToObject, float4(v1.worldPos, 1));
193    v2_objPos = mul(unity_WorldToObject, float4(v2.worldPos, 1));
194
195    float chrono = 0;
196#if defined(_AUDIOLINK)
197    if (AudioLinkIsAvailable()) {
198      chrono = (AudioLinkDecodeDataAsUInt( ALPASS_CHRONOTENSITY  + uint2( 2, 1 ) ) % 1000000) / 1000000.0;
199    }
200#endif
201    v0.worldPos += n * explode_phase * sin(_Time[2] + length(v0_objPos)*6 + chrono) * .01 + chrono * n * explode_phase * .2;
202    v1.worldPos += n * explode_phase * sin(_Time[2] + length(v1_objPos)*6 + chrono) * .01 + chrono * n * explode_phase * .2;
203    v2.worldPos += n * explode_phase * sin(_Time[2] + length(v2_objPos)*6 + chrono) * .01 + chrono * n * explode_phase * .2;
204
205    avg_pos = (v0.worldPos + v1.worldPos + v2.worldPos) / 3;
206    v0.worldPos -= avg_pos;
207    v1.worldPos -= avg_pos;
208    v2.worldPos -= avg_pos;
209
210    float theta = explode_phase * 3.14159 * 4 + explode_phase * (sin(_Time[1] * (1 + pid_rand) / 2.0 + pid_rand) + cos(_Time[1] * (1 + pid_rand) / 6.1 + pid_rand) * 2) * pid_rand * 2;
211    float4 quat = get_quaternion(axis, theta);
212    v0.worldPos = rotate_vector(v0.worldPos, quat);
213    v1.worldPos = rotate_vector(v1.worldPos, quat);
214    v2.worldPos = rotate_vector(v2.worldPos, quat);
215
216    v0.worldPos += avg_pos;
217    v1.worldPos += avg_pos;
218    v2.worldPos += avg_pos;
219
220    n = normalize(cross(v1.worldPos - v0.worldPos, v2.worldPos - v0.worldPos));
221    v0.normal = n;
222    v1.normal = n;
223    v2.normal = n;
224
225    // Omit geometry that's too close when exploded.
226    /*
227    if (_Explode_Phase > .05 && length(v0.worldPos - _WorldSpaceCameraPos) < .2) {
228      return;
229    }
230    */
231
232    v0_objPos = mul(unity_WorldToObject, float4(v0.worldPos, 1));
233    v1_objPos = mul(unity_WorldToObject, float4(v1.worldPos, 1));
234    v2_objPos = mul(unity_WorldToObject, float4(v2.worldPos, 1));
235
236    // Apply transformed worldPos to other coordinate systems.
237    if (_Explode_Phase > 1E-6) {
238      v0.pos = UnityObjectToClipPos(v0_objPos);
239      v1.pos = UnityObjectToClipPos(v1_objPos);
240      v2.pos = UnityObjectToClipPos(v2_objPos);
241    }
242  }
243#endif  // __EXPLODE
244#if defined(_SCROLL)
245  {
246    float3 n = normalize(cross(v1.worldPos - v0.worldPos, v2.worldPos - v0.worldPos));
247    float3 avg_pos = (v0.worldPos + v1.worldPos + v2.worldPos) / 3;
248    v0.worldPos = applyScroll(v0.worldPos, n, avg_pos);
249    v1.worldPos = applyScroll(v1.worldPos, n, avg_pos);
250    v2.worldPos = applyScroll(v2.worldPos, n, avg_pos);
251
252    float3 v0_objPos = mul(unity_WorldToObject, float4(v0.worldPos, 1));
253    float3 v1_objPos = mul(unity_WorldToObject, float4(v1.worldPos, 1));
254    float3 v2_objPos = mul(unity_WorldToObject, float4(v2.worldPos, 1));
255
256#if defined(_GIMMICK_SPHERIZE_LOCATION)
257  if (_Gimmick_Spherize_Location_Enable_Dynamic) {
258    float r = _Gimmick_Spherize_Location_Radius;
259    float s = _Gimmick_Spherize_Location_Strength;
260    float l0 = length(v0_objPos);
261    float l1 = length(v1_objPos);
262    float l2 = length(v2_objPos);
263    v0_objPos *= lerp(1, (r / l0), s);
264    v1_objPos *= lerp(1, (r / l1), s);
265    v2_objPos *= lerp(1, (r / l2), s);
266  }
267#endif
268#if defined(_GIMMICK_SHEAR_LOCATION)
269  if (_Gimmick_Shear_Location_Enable_Dynamic) {
270    v0_objPos = mul(float3x3(
271        _Gimmick_Shear_Location_Strength.x, 0, 0,
272        0, _Gimmick_Shear_Location_Strength.y, 0,
273        0, 0, _Gimmick_Shear_Location_Strength.z),
274        v0_objPos);
275    v1_objPos = mul(float3x3(
276        _Gimmick_Shear_Location_Strength.x, 0, 0,
277        0, _Gimmick_Shear_Location_Strength.y, 0,
278        0, 0, _Gimmick_Shear_Location_Strength.z),
279        v1_objPos);
280    v2_objPos = mul(float3x3(
281        _Gimmick_Shear_Location_Strength.x, 0, 0,
282        0, _Gimmick_Shear_Location_Strength.y, 0,
283        0, 0, _Gimmick_Shear_Location_Strength.z),
284        v2_objPos);
285  }
286#endif
287#if defined(_GIMMICK_SHEAR_LOCATION) || defined(_GIMMICK_SPHERIZE_LOCATION)
288    v0.worldPos.xyz = mul(unity_ObjectToWorld, v0_objPos);
289    v1.worldPos.xyz = mul(unity_ObjectToWorld, v1_objPos);
290    v2.worldPos.xyz = mul(unity_ObjectToWorld, v2_objPos);
291#endif
292
293    v0.pos = UnityObjectToClipPos(v0_objPos);
294    v1.pos = UnityObjectToClipPos(v1_objPos);
295    v2.pos = UnityObjectToClipPos(v2_objPos);
296  }
297#endif
298#if defined(_CLONES)
299  v2f clone_verts[3] = {v0, v1, v2};
300  add_clones(clone_verts, tri_out, pid_rand, explode_phase);
301#endif  // _CLONES
302
303  // Output transformed geometry.
304  tri_out.Append(v0);
305  tri_out.Append(v1);
306  tri_out.Append(v2);
307  tri_out.RestartStrip();
308}
309
310fixed4 frag (v2f i) : SV_Target
311{
312  ToonerData tdata;
313  {
314    float3 full_vec_eye_to_geometry = i.worldPos - _WorldSpaceCameraPos;
315    float3 world_dir = normalize(i.worldPos - _WorldSpaceCameraPos);
316    float perspective_divide = 1.0 / i.pos.w;
317    float perspective_factor = length(full_vec_eye_to_geometry * perspective_divide);
318    tdata.screen_uv = i.screenPos.xy * perspective_divide;
319    tdata.screen_uv_round = floor(tdata.screen_uv * _ScreenParams.xy);
320  }
321
322  i.normal = -normalize(i.normal);
323
324#if defined(_OUTLINES)
325#if defined(_BASECOLOR_MAP)
326  float4 albedo = _MainTex.SampleBias(linear_repeat_s, i.uv0, _Global_Sample_Bias);
327  albedo *= _Color;
328#else
329  float4 albedo = _Color;
330#endif  // _BASECOLOR_MAP
331
332#if defined(_RENDERING_CUTOUT)
333  clip(albedo.a - _Alpha_Cutoff);
334#endif
335
336  albedo = _Outline_Color;
337
338#if defined(_GIMMICK_AL_CHROMA_00)
339  float al_chroma_00_emission = 0;
340  if (_Gimmick_AL_Chroma_00_Outline_Pass && AudioLinkIsAvailable()) {
341    float3 c = AudioLinkData(ALPASS_CCSTRIP + uint2(0, 0)).rgb;
342#if defined(_GIMMICK_AL_CHROMA_00_HUE_SHIFT)
343    c = LRGBtoOKLCH(c);
344    c[2] += _Gimmick_AL_Chroma_00_Hue_Shift_Theta * 2.0 * 3.14159265;
345    c = OKLCHtoLRGB(c);
346#endif
347    albedo.rgb = lerp(albedo.rgb, c, _Gimmick_AL_Chroma_00_Outline_Blend);
348    al_chroma_00_emission = _Gimmick_AL_Chroma_00_Outline_Emission;
349  }
350#endif
351
352#if defined(_OKLAB)
353  // Do hue shift in perceptually uniform color space so it doesn't look like
354  // shit.
355 float oklab_mask = _OKLAB_Mask.SampleBias(linear_repeat_s, i.uv0, _Global_Sample_Bias);
356 if (oklab_mask > 0.01 &&
357     (_OKLAB_Hue_Shift > 1E-6 ||
358      abs(_OKLAB_Chroma_Shift) > 1E-6 ||
359      abs(_OKLAB_Lightness_Shift) > 1E-6)) {
360   float3 c = albedo.rgb;
361   c = LRGBtoOKLCH(c);
362   c.x += _OKLAB_Lightness_Shift;
363   c.y += _OKLAB_Chroma_Shift;
364   c.z += _OKLAB_Hue_Shift;
365   c = OKLCHtoLRGB(c);
366   albedo.rgb = c;
367 }
368#endif
369
370  float4 vertex_light_color = 0;
371  float ao = 1;
372  float4 result = getLitColor(
373      vertex_light_color,
374      albedo, i.worldPos, i.normal,
375      /*metallic=*/0, /*smoothness=*/0,
376      i.uv0, ao, /*enable_direct=*/false,
377      /*diffuse_contrib=*/0, i, tdata);
378
379  result += albedo * _Outline_Emission_Strength;
380#if defined(_GIMMICK_AL_CHROMA_00)
381  result += albedo * al_chroma_00_emission;
382#endif
383
384#if defined(_EXPLODE) && defined(_AUDIOLINK)
385  if (AudioLinkIsAvailable() && _Explode_Phase > 1E-6) {
386    float4 al_color =
387      AudioLinkData(
388          ALPASS_CCLIGHTS +
389          uint2(uint(i.uv0.x * 8) + uint(i.uv0.y * 16) * 8, 0 )).rgba;
390    result = lerp(result, al_color, _Explode_Phase * _Explode_Phase);
391  }
392#endif
393
394  return result;
395#else
396  discard;
397  return 0;
398#endif  // _OUTLINES
399}
400
401#endif  // __TOONER_OUTLINE_PASS
402