yum-archive/Tooner

A toon shader for Unity's BIRP.

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

yumReimplement faceme gimmickccbf413

master
12.3 KiB303 linesraw
1#include "UnityCG.cginc"
2
3#include "globals.cginc"
4#include "iq_sdf.cginc"
5#include "interpolators.cginc"
6
7#ifndef __ZWRITE_ABOMINATION_INC
8#define __ZWRITE_ABOMINATION_INC
9
10#if defined(_GIMMICK_ZWRITE_ABOMINATION)
11
12struct ZWriteAbominationPBR {
13  float3 worldPos;
14  float3 normal;
15  float4 albedo;
16  float metallic;
17  float roughness;
18  float depth;
19};
20
21#define BODY_PART_BODY 0
22#define BODY_PART_LENS 1
23#define BODY_PART_EYE_WHITE 2
24#define BODY_PART_PUPIL 3
25#define BODY_PART_ARM 4
26#define BODY_PART_LEG 5
27#define BODY_PART_MOUTH 6
28#define BODY_PART_DENIM 7
29#define BODY_PART_DENIM_STRAP 7
30#define BODY_PART_EYE_STRAP 8
31
32float zwrite_abomination_map(float3 p, out uint body_part) {
33    float epsilon = 1E-4;
34    float d;
35    float s = _Gimmick_ZWrite_Abomination_Global_Scale;
36    p = p / s;  // Scale all positions first
37
38    // Capsule representing body
39    {
40        float body_half_height = _Gimmick_ZWrite_Abomination_Body_Half_Height;
41        float body_radius = _Gimmick_ZWrite_Abomination_Body_Radius;
42        float body_d = distance_from_capsule(p, float3(0, -body_half_height, 0), float3(0, body_half_height, 0), body_radius);
43        body_part = BODY_PART_BODY;
44        d = body_d;
45    }
46
47    // Capsule representing denim
48    {
49        float3 denim_center = _Gimmick_ZWrite_Abomination_Denim_Center;
50        float3 pp = p - denim_center;
51        float denim_half_height = _Gimmick_ZWrite_Abomination_Denim_Half_Height;
52        float denim_radius = _Gimmick_ZWrite_Abomination_Denim_Radius;
53        float denim_d = distance_from_capsule(pp, float3(0, -denim_half_height, 0), float3(0, denim_half_height, 0), denim_radius);
54        body_part = denim_d < d ? BODY_PART_DENIM : body_part;
55        d = min(d, denim_d);
56    }
57
58    // Torus representing denim strap
59    {
60        float3 strap_center = _Gimmick_ZWrite_Abomination_Denim_Strap_Center;
61        float3 pp = p;
62        pp.x = abs(pp.x);
63        pp -= strap_center;
64        float theta = _Gimmick_ZWrite_Abomination_Denim_Strap_Z_Theta;
65        float2x2 rot = float2x2(float2(cos(theta), -sin(theta)), float2(sin(theta), cos(theta)));
66        pp.xy = mul(rot, pp.xy);
67        pp = pp.zyx;
68
69        float strap_theta = _Gimmick_ZWrite_Abomination_Denim_Strap_Theta;
70        float strap_ra = _Gimmick_ZWrite_Abomination_Denim_Strap_RA;
71        float strap_rb = _Gimmick_ZWrite_Abomination_Denim_Strap_RB;
72        float strap_d = distance_from_capped_torus(pp, float2(sin(strap_theta), cos(strap_theta)), strap_ra, strap_rb);
73        body_part = strap_d < d ? BODY_PART_DENIM_STRAP : body_part;
74        d = min(d, strap_d);
75    }
76
77    // Metal ring around the eye
78    {
79        float3 eye_center = _Gimmick_ZWrite_Abomination_Eye_Center;
80        float3 pp = (p - eye_center).xzy;
81        float lens_radius = _Gimmick_ZWrite_Abomination_Lens_Radius;
82        float lens_depth = _Gimmick_ZWrite_Abomination_Lens_Depth;
83        float lens_thickness = _Gimmick_ZWrite_Abomination_Lens_Thickness;
84        float lens_d0 = distance_from_capped_cylinder(pp, lens_depth, lens_radius);
85        float lens_d1 = distance_from_capped_cylinder(pp, lens_depth + 0.1, lens_radius - lens_thickness);
86        float lens_d = op_sub(lens_d1, lens_d0);
87        body_part = lens_d < d ? BODY_PART_LENS : body_part;
88        d = min(d, lens_d);
89
90        // White of eye
91        float eye_white_d = distance_from_capped_cylinder(pp, lens_depth * 0.5, lens_radius - lens_thickness * 0.5);
92        body_part = eye_white_d < d ? BODY_PART_EYE_WHITE : body_part;
93        d = min(d, eye_white_d);
94
95        // Pupil
96        float pupil_d = length(pp) - _Gimmick_ZWrite_Abomination_Pupil_Radius;
97        body_part = pupil_d < d ? BODY_PART_PUPIL : body_part;
98        d = min(d, pupil_d);
99    }
100
101    // Strap holding metal ring to head
102    {
103        float3 pp = p;
104        pp.y -= _Gimmick_ZWrite_Abomination_Eye_Center.y;
105        float strap_d = distance_from_capped_cylinder(pp, _Gimmick_ZWrite_Abomination_Lens_Strap_Height, _Gimmick_ZWrite_Abomination_Body_Radius * 1.001);
106        body_part = strap_d < d ? BODY_PART_EYE_STRAP : body_part;
107        d = min(d, strap_d);
108    }
109
110    // Mouth
111    {
112        float3 mouth_center = _Gimmick_ZWrite_Abomination_Mouth_Center;
113        float3 pp = p;
114        pp -= mouth_center;
115        pp.y = -pp.y;
116        float theta = _Gimmick_ZWrite_Abomination_Mouth_Theta;
117        float ra = _Gimmick_ZWrite_Abomination_Mouth_RA;
118        float rb = _Gimmick_ZWrite_Abomination_Mouth_RB;
119        float mouth_d = distance_from_capped_torus(pp, float2(sin(theta), cos(theta)), ra, rb);
120        body_part = mouth_d < d ? BODY_PART_MOUTH : body_part;
121        d = min(d, mouth_d);
122    }
123
124    // Arms
125    {
126        float3 arm_center = _Gimmick_ZWrite_Abomination_Arm_Center;
127        float3 pp = p;
128        pp.x = abs(pp.x);  // Symmetrize along x axis
129        pp -= arm_center;
130        float arm_radius = _Gimmick_ZWrite_Abomination_Arm_Radius;
131        float arm_half_length = _Gimmick_ZWrite_Abomination_Arm_Half_Length;
132        float arm_d = distance_from_capsule(pp, float3(-arm_half_length, 0, 0), float3(arm_half_length, 0, 0), arm_radius);
133        body_part = arm_d < d ? BODY_PART_ARM : body_part;
134        d = min(d, arm_d);
135    }
136
137    // Legs
138    {
139        float3 leg_center = _Gimmick_ZWrite_Abomination_Leg_Center;
140        float3 pp = p.yxz;
141        pp.y = abs(pp.y);  // Symmetrize
142        pp -= leg_center;
143        float leg_radius = _Gimmick_ZWrite_Abomination_Leg_Radius;
144        float leg_half_length = _Gimmick_ZWrite_Abomination_Leg_Half_Length;
145        float leg_d = distance_from_capsule(pp, float3(-leg_half_length, 0, 0), float3(leg_half_length, 0, 0), leg_radius);
146        body_part = leg_d < d ? BODY_PART_LEG : body_part;
147        d = min(d, leg_d);
148    }
149
150    return d * s;
151}
152
153// TODO tetrahedral normals
154float3 zwrite_abomination_normal(float3 p) {
155    float3 epsilon = float3(1, 0, 0) * _Gimmick_ZWrite_Abomination_Normal_Epsilon;
156    uint body_part;
157    return normalize(float3(
158        zwrite_abomination_map(p + epsilon.xyy, body_part) - zwrite_abomination_map(p - epsilon.xyy, body_part),
159        zwrite_abomination_map(p + epsilon.yxy, body_part) - zwrite_abomination_map(p - epsilon.yxy, body_part),
160        zwrite_abomination_map(p + epsilon.yyx, body_part) - zwrite_abomination_map(p - epsilon.yyx, body_part)
161    ));
162}
163
164ZWriteAbominationPBR zwrite_abomination(in v2f i)
165{
166  float3 cam_pos = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos, 1));
167  float3 rd = normalize(i.objPos - cam_pos);
168  float3 ro = cam_pos + rd * _Gimmick_ZWrite_Abomination_Initial_Step_Size;
169  float l = length(ro);
170  float scale_factor = pow(l, 1.5);
171  ro /= scale_factor;
172  ro += _Gimmick_ZWrite_Abomination_Global_Offset;
173
174  float3 forward_axis = float3(0, 0, 1);
175  // We apply a factor of -1 to shift the result forward by a phase shift of pi.
176  float cos_t = -dot(normalize(rd.xz), forward_axis.xz);
177  // We want to get sin(t) using the identity:
178  //   || a x b || = || a || || b || sin(t)
179  // For normal vectors, this simplifies to:
180  //   || a x b || = sin(t)
181  // The issue is that the norm operator loses the sign.
182  // We can estimate the sign by assuming that `rd` and `forward_axis` are on
183  // the xz plane.
184  // If that's the case, then the cross product is necessarily constrained to
185  // the y axis.
186  float sin_t_sign = sign(cross(rd, forward_axis).y);
187  // Here we use the identity:
188  //   sin(t) = sqrt(1 - cos(t)^2)
189  // We simply apply the sign correction `sin_t_sign` to the result.
190  // We then invert it, since the goal is not to amplify the rotation, but
191  // to negate it.
192  // Finally, we add a phase correction to make the abomination face us.
193  float sin_t = sqrt(1 - cos_t * cos_t) * sin_t_sign;
194  float2x2 face_me_rot = float2x2(cos_t, -sin_t, sin_t, cos_t);
195  float2x2 face_me_rot_inv = float2x2(cos_t, sin_t, -sin_t, cos_t);
196  ro.xz = mul(face_me_rot, ro.xz);
197  rd.xz = mul(face_me_rot, rd.xz);
198
199  // Raytrace ro onto sphere containing sim
200
201#if 1
202  {
203    bool no_intersection = false;
204    float distance_to_sphere = 1E6;
205    float circle_radius = 0.5 * scale_factor;
206    {
207      float3 l = ro;
208      float a = 1;
209      float b = 2 * dot(rd, l);
210      float c = dot(l, l) - circle_radius * circle_radius;
211      float t0, t1;
212      if (solveQuadratic(a, b, c, t0, t1)) {
213        no_intersection = (t0 < 0) * (t1 < 0);
214        const bool inside_sphere = (t0 < 0) * (t1 > 0);
215        if (!inside_sphere) {
216          distance_to_sphere = no_intersection ? distance_to_sphere : min(max(t0, 0), max(t1, 0));
217          ro += distance_to_sphere * rd;
218        }
219      }
220    }
221    clip(no_intersection ? -1 : 1);
222  }
223#endif
224
225  const float MIN_HIT_DIST = _Gimmick_ZWrite_Abomination_Min_Hit_Dist;
226  const float MAX_DIST = 1;
227  const uint MARCH_STEPS = _Gimmick_ZWrite_Abomination_March_Steps;
228  float total_dist = 0;
229  float d;
230  uint body_part;
231  for (uint ii = 0; ii < MARCH_STEPS; ++ii) {
232    float3 p = ro + rd * total_dist;
233    d = zwrite_abomination_map(p, body_part);
234    if (d < MIN_HIT_DIST) {
235      break;
236    }
237    total_dist += d;
238  }
239
240  ZWriteAbominationPBR pbr;
241  if (d < MIN_HIT_DIST) {
242    float3 p = ro + rd * total_dist;
243    pbr.worldPos = mul(unity_ObjectToWorld, float4(p, 1.0)).xyz;
244
245    float3 c = 1;
246    c = (body_part == BODY_PART_BODY) ? _Gimmick_ZWrite_Abomination_Skin_Color : c;
247    c = (body_part == BODY_PART_ARM) ? _Gimmick_ZWrite_Abomination_Skin_Color : c;
248    c = (body_part == BODY_PART_LEG) ? _Gimmick_ZWrite_Abomination_Skin_Color : c;
249    c = (body_part == BODY_PART_LENS) ? _Gimmick_ZWrite_Abomination_Lens_Color : c;
250    c = (body_part == BODY_PART_EYE_WHITE) ? 1 : c;
251    c = (body_part == BODY_PART_PUPIL) ? 0 : c;
252    c = (body_part == BODY_PART_MOUTH) ? 0 : c;
253    c = (body_part == BODY_PART_DENIM) ? _Gimmick_ZWrite_Abomination_Denim_Color : c;
254    c = (body_part == BODY_PART_DENIM_STRAP) ? _Gimmick_ZWrite_Abomination_Denim_Color : c;
255    c = (body_part == BODY_PART_EYE_STRAP) ? _Gimmick_ZWrite_Abomination_Lens_Strap_Color : c;
256
257    float metallic = 0;
258    metallic = (body_part == BODY_PART_BODY) ? _Gimmick_ZWrite_Abomination_Skin_Metallic : metallic;
259    metallic = (body_part == BODY_PART_ARM) ? _Gimmick_ZWrite_Abomination_Skin_Metallic : metallic;
260    metallic = (body_part == BODY_PART_LEG) ? _Gimmick_ZWrite_Abomination_Skin_Metallic : metallic;
261    metallic = (body_part == BODY_PART_LENS) ? _Gimmick_ZWrite_Abomination_Lens_Metallic : metallic;
262    metallic = (body_part == BODY_PART_EYE_WHITE) ? 0 : metallic;
263    metallic = (body_part == BODY_PART_PUPIL) ? 0 : metallic;
264    metallic = (body_part == BODY_PART_MOUTH) ? 0 : metallic;
265    metallic = (body_part == BODY_PART_DENIM) ? _Gimmick_ZWrite_Abomination_Denim_Metallic : metallic;
266    metallic = (body_part == BODY_PART_DENIM_STRAP) ? _Gimmick_ZWrite_Abomination_Denim_Metallic : metallic;
267    metallic = (body_part == BODY_PART_EYE_STRAP) ? _Gimmick_ZWrite_Abomination_Lens_Strap_Metallic : metallic;
268
269    float roughness = 0;
270    roughness = (body_part == BODY_PART_BODY) ? _Gimmick_ZWrite_Abomination_Skin_Roughness : roughness;
271    roughness = (body_part == BODY_PART_ARM) ? _Gimmick_ZWrite_Abomination_Skin_Roughness : roughness;
272    roughness = (body_part == BODY_PART_LEG) ? _Gimmick_ZWrite_Abomination_Skin_Roughness : roughness;
273    roughness = (body_part == BODY_PART_LENS) ? _Gimmick_ZWrite_Abomination_Lens_Roughness : roughness;
274    roughness = (body_part == BODY_PART_EYE_WHITE) ? 0 : roughness;
275    roughness = (body_part == BODY_PART_PUPIL) ? 0 : roughness;
276    roughness = (body_part == BODY_PART_MOUTH) ? 1 : roughness;
277    roughness = (body_part == BODY_PART_DENIM) ? _Gimmick_ZWrite_Abomination_Denim_Roughness : roughness;
278    roughness = (body_part == BODY_PART_DENIM_STRAP) ? _Gimmick_ZWrite_Abomination_Denim_Roughness : roughness;
279    roughness = (body_part == BODY_PART_EYE_STRAP) ? _Gimmick_ZWrite_Abomination_Lens_Strap_Roughness : roughness;
280
281    pbr.albedo = float4(c, 1);
282    pbr.metallic = metallic;
283    pbr.roughness = roughness;
284    float3 normal = zwrite_abomination_normal(p);
285    // TODO inverse of this matrix?
286    normal.xz = mul(face_me_rot_inv, normal.xz);
287    pbr.normal = UnityObjectToWorldNormal(normal);
288    float4 clip_pos = mul(UNITY_MATRIX_VP, float4(mul(unity_ObjectToWorld, float4(p, 1.0))));
289    pbr.depth = clip_pos.z / clip_pos.w;
290  } else {
291    pbr.worldPos = i.worldPos;
292    pbr.albedo = 0;
293    pbr.metallic = 0;
294    pbr.roughness = 1;
295    pbr.normal = i.normal;
296    pbr.depth = -1E6;
297  }
298
299  return pbr;
300}
301
302#endif  // _GIMMICK_ZWRITE_ABOMINATION
303#endif  // __ZWRITE_ABOMINATION_INC