yum-archive/2ner

A toon shader for Unity's BIRP.

git clone https://git.yummers.dev/yum-archive/2ner

yumRemove worldPos interpolator4885fb4

master
10.5 KiB369 linesraw
1#ifndef __MATH_INC
2#define __MATH_INC
3
4#include "pema99.cginc"
5
6#define PI              3.14159265358979323846264f
7#define TAU             (2.0f * PI)
8#define HALF_PI         (PI * 0.5f)
9#define RCP_PI          (1.0f / PI)
10#define RCP_TAU         (1.0f / TAU)
11#define PHI             1.618033989f
12#define RCP_PHI         0.618033989f
13#define SQRT_2          1.414213562f
14#define SQRT_2_RCP      0.707106781f
15#define RCP_SQRT_2      0.707106781f
16#define RCP_SQRT_3      0.577350269f
17#define TWO_OVER_THREE  0.6666666666666666f
18#define SQRT_3_OVER_2   0.8660254037844386f
19#define EULERS_CONSTANT 2.718281828f
20
21
22float pow5(float x)
23{
24  float tmp = x * x;
25  return (tmp * tmp) * x;
26}
27
28// Wrap NoL. Assume it's already clamped.
29// At k=0, you get standard lambertian shading.
30// At k=0.5, you get half-lambertian shading.
31// At k=1.0, you get flat shading.
32// k must be on [0, 1].
33// Energy preserving, within some small bound.
34float wrapNoL(float NoL, float k) {
35  float lambertian = NoL;
36  float half_lambertian = pow(max(1e-4, (NoL + 0.5f) / (1.0f + 0.5f)), 2);
37  float flat = RCP_PI;
38
39  if (k < 0.5) {
40    return lerp(lambertian, half_lambertian, k * 2.0f);
41  } else {
42    return lerp(half_lambertian, flat, k * 2.0f - 1.0f);
43  }
44}
45
46float halfLambertianNoL(float NoL) {
47		// https://www.iro.umontreal.ca/~derek/files/jgt_wrap_final.pdf
48    float tmp = (NoL + 1)  * 0.5;
49    return tmp * tmp;
50}
51
52float rand1(float p)
53{
54  return frac(sin(p) * 43758.5453123);
55}
56
57float rand2(float2 p)
58{
59  return frac(sin(dot(p, float2(12.9898, 78.233))) * 43758.5453123);
60}
61
62inline float rand3_dot(float3 p)
63{
64  return dot(p, float3(151.0, 157.0, 163.0));
65}
66
67float3 rand3_hash(float3 p)
68{
69    // Improved Murmurhash3 by Squirrel Eiserloh (GDC 2017)
70    p = float3(dot(p, float3(127.1, 311.7, 74.7)),
71               dot(p, float3(269.5, 183.3, 246.1)),
72               dot(p, float3(113.5, 271.9, 124.6)));
73    return -1.0 + 2.0 * frac(sin(p) * 43758.5453123);
74}
75
76float rand3(float3 p)
77{
78    return frac(rand3_hash(p).x);
79}
80
81float2 domainWarp1(float x, uint octaves, float strength, float scale, float speed)
82{
83  [loop]
84  for (uint i = 0; i < octaves; i++) {
85    x += strength * frac(sin(float2(
86      dot(x * scale, float2(12.9898, 78.233)),
87      dot(x * scale + 1, float2(12.9898, 78.233))) * 43758.5453123));
88  }
89  return x;
90}
91
92float2 domainWarp2(float2 uv, uint octaves, float strength, float scale, float speed)
93{
94  uv *= 0.001;
95  [loop]
96  for (uint i = 0; i < octaves; i++) {
97    uv += strength * frac(sin(float2(
98      dot(uv * scale, float2(12.9898, 78.233)),
99      dot(uv * scale, float2(36.7539, 50.3658)))) * 43758.5453123);
100  }
101  uv *= 1000;
102  return uv;
103}
104
105float determinant(float3x3 m)
106{
107  return (m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1])
108            - m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0]))
109            + m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0]);
110}
111
112float3x3 inverse(float3x3 m)
113{
114  float det = determinant(m);
115
116  float3x3 adj;
117  adj[0][0] =  (m[1][1] * m[2][2] - m[1][2] * m[2][1]);
118  adj[0][1] = -(m[0][1] * m[2][2] - m[0][2] * m[2][1]);
119  adj[0][2] =  (m[0][1] * m[1][2] - m[0][2] * m[1][1]);
120  
121  adj[1][0] = -(m[1][0] * m[2][2] - m[1][2] * m[2][0]);
122  adj[1][1] =  (m[0][0] * m[2][2] - m[0][2] * m[2][0]);
123  adj[1][2] = -(m[0][0] * m[1][2] - m[0][2] * m[1][0]);
124  
125  adj[2][0] =  (m[1][0] * m[2][1] - m[1][1] * m[2][0]);
126  adj[2][1] = -(m[0][0] * m[2][1] - m[0][1] * m[2][0]);
127  adj[2][2] =  (m[0][0] * m[1][1] - m[0][1] * m[1][0]);
128
129  return adj * (1.0 / det);
130}
131
132float3 domainWarp3(float3 pos, uint octaves, float strength, float scale, float offset)
133{
134  [loop]
135  for (uint i = 0; i < octaves; i++) {
136    pos += strength * frac(sin(float3(
137      rand3_dot(pos * scale + offset),
138      rand3_dot(pos * scale + offset + 1),
139      rand3_dot(pos * scale + offset + 2)) * 43758.5453123));
140  }
141  return pos;
142}
143
144void domainWarp3Normals(inout float3 normal, inout float3 tangent, float3 basePos, uint octaves, float strength, float scale, float offset)
145{
146    // Use the actual vertex position for correct derivative evaluation.
147    float3 p = basePos;
148    
149    // Start with the identity matrix for the total Jacobian.
150    float3x3 J = float3x3(
151        1.0, 0.0, 0.0,
152        0.0, 1.0, 0.0,
153        0.0, 0.0, 1.0
154    );
155    
156    const float k = 43758.5453123;
157    // Updated constant vector to match that of rand3_dot (used in domainWarp3)
158    const float3 c = float3(151.0, 157.0, 163.0);
159    
160    for (uint i = 0; i < octaves; i++)
161    {
162        // Compute the vector v using the same offsetting as in domainWarp3.
163        float3 v = float3(
164            dot(p * scale + float3(offset, offset, offset), c),
165            dot(p * scale + float3(offset + 1.0, offset + 1.0, offset + 1.0), c),
166            dot(p * scale + float3(offset + 2.0, offset + 2.0, offset + 2.0), c)
167        );
168        
169        // Compute the warp offset with frac.
170        float3 f_val = frac(sin(v) * k);
171        float3 warpOffset = strength * f_val;
172        
173        // Compute the derivative (Jacobian) of the offset.
174        float3 cos_v = cos(v);
175        float3x3 D = float3x3(
176            strength * k * scale * cos_v.x * c.x, strength * k * scale * cos_v.x * c.y, strength * k * scale * cos_v.x * c.z,
177            strength * k * scale * cos_v.y * c.x, strength * k * scale * cos_v.y * c.y, strength * k * scale * cos_v.y * c.z,
178            strength * k * scale * cos_v.z * c.x, strength * k * scale * cos_v.z * c.y, strength * k * scale * cos_v.z * c.z
179        );
180        
181        // The per–octave Jacobian is I + D.
182        float3x3 iterJacobian = float3x3(
183            1.0 + D[0][0],        D[0][1],        D[0][2],
184                   D[1][0], 1.0 + D[1][1],        D[1][2],
185                   D[2][0],        D[2][1], 1.0 + D[2][2]
186        );
187        
188        // Chain this iteration's Jacobian.
189        J = mul(iterJacobian, J);
190        
191        // Update p for the next iteration.
192        p += warpOffset;
193    }
194    
195    // Transform the normal via the inverse-transpose of the total Jacobian.
196    float3x3 invTransJ = transpose(inverse(J));
197    normal = normalize(mul(invTransJ, normal));
198    
199    // Transform the tangent via the forward total Jacobian.
200    tangent = normalize(mul(J, tangent));
201}
202
203// Alpha blend `dst` onto `src`.
204// Imagine two transparent planes. We're rendering a situation where you're
205// looking through `front` at `behind`.
206float4 alphaBlend(float4 behind, float4 front) {
207  return float4(front.rgb * front.a + behind.rgb * (1 - front.a), front.a + behind.a * (1 - front.a));
208}
209
210// Reoriented normal mapping
211// https://blog.selfshadow.com/publications/blending-in-detail/
212// Inputs are in tangent space.
213float3 blendNormalsHill12(float3 n0, float3 n1) {
214  n0.z += 1.0;
215  n1.xy = -n1.xy;
216  
217  return normalize(n0 * dot(n0, n1) - n1 * n0.z);
218}
219
220float luminance(float3 color) {
221  return dot(color, float3(0.2126, 0.7152, 0.0722));
222}
223
224float median(float3 x) {
225  // Get the min and max.
226  float x_min= min(min(x.r, x.g), x.b);
227  float x_max = max(max(x.r, x.g), x.b);
228  
229  // Compute (x.r + x.g + x.b) - (x_min + x_max). This gives us the median.
230  return (x.r + x.g + x.b) - (x_min + x_max);
231}
232
233// Quaternions
234float4 qmul(float4 q1, float4 q2)
235{
236  return float4(
237      q2.xyz * q1.w + q1.xyz * q2.w + cross(q1.xyz, q2.xyz),
238      q1.w * q2.w - dot(q1.xyz, q2.xyz));
239}
240
241// Vector rotation with a quaternion
242// https://blog.molecular-matters.com/2013/05/24/a-faster-quaternion-vector-multiplication/
243float3 rotate_vector(float3 v, float4 q)
244{
245  float3 t = 2.0 * cross(q.xyz, v);
246  return v + q.w * t + cross(q.xyz, t);
247}
248
249float4 get_quaternion(float3 axis_normal, float theta) {
250  return float4(axis_normal * sin(theta / 2), cos(theta / 2));
251}
252
253void calcNormalInScreenSpace(inout float3 normal, float3 objPos) {
254  normal = normalize(cross(ddy(objPos), ddx(objPos)));
255}
256
257// Formulae from here: https://www.rapidtables.com/convert/color/rgb-to-cmyk.html
258float4 rgbToCmyk(float3 rgb) {
259  float4 cmyk;
260  cmyk[3] = 1 - max(rgb.r, max(rgb.g, rgb.b));
261  cmyk[0] = (1 - rgb.r - cmyk[3]) / (1 - cmyk[3]);
262  cmyk[1] = (1 - rgb.g - cmyk[3]) / (1 - cmyk[3]);
263  cmyk[2] = (1 - rgb.b - cmyk[3]) / (1 - cmyk[3]);
264  return cmyk;
265}
266
267float rgbToCmyk_C(float3 rgb) {
268  float k = 1 - max(rgb.r, max(rgb.g, rgb.b));
269  float c = (1 - rgb.r - k) / (1 - k);
270  return c;
271}
272float rgbToCmyk_M(float3 rgb) {
273  float k = 1 - max(rgb.r, max(rgb.g, rgb.b));
274  float m = (1 - rgb.g - k) / (1 - k);
275  return m;
276}
277float rgbToCmyk_Y(float3 rgb) {
278  float k = 1 - max(rgb.r, max(rgb.g, rgb.b));
279  float y = (1 - rgb.b - k) / (1 - k);
280  return y;
281}
282float rgbToCmyk_K(float3 rgb) {
283  float k = 1 - max(rgb.r, max(rgb.g, rgb.b));
284  return k;
285}
286
287float3 cmykToRgb(float4 cmyk) {
288  return float3(
289    (1 - cmyk[0]) * (1 - cmyk[3]),
290    (1 - cmyk[1]) * (1 - cmyk[3]),
291    (1 - cmyk[2]) * (1 - cmyk[3]));
292}
293
294// Cartesian to cube hexagonal coordinates.
295// Based on this: https://backdrifting.net/post/064_hex_grids
296float3 cart_to_hex(float2 cart) {
297  float p = cart.x;
298  float q = dot(cart, float2(0.5f, SQRT_3_OVER_2));
299  float r = dot(cart, float2(0.5f, -SQRT_3_OVER_2));
300
301  return float3(p, q, r) * TWO_OVER_THREE;
302}
303
304float2 hex_to_cart(float3 cart) {
305  return float2(
306      cart[0] + (cart[1] + cart[2]) * 0.5f,
307      (cart[1] - cart[2]) * SQRT_3_OVER_2);
308}
309
310// Rotate 45 degrees.
311float2 rot45(float2 v) { return float2(v.x - v.y, v.x + v.y) * RCP_SQRT_2; }
312
313// p = point to get noise for
314float valueNoise2D(
315    float2 p) {
316  // quantized part
317  float2 q = floor(p);
318  // fractional part
319  float2 f = frac(p);
320
321  float l00 = rand2(q);
322  float l01 = rand2(q + float2(0, 1));
323  float l10 = rand2(q + float2(1, 0));
324  float l11 = rand2(q + float2(1, 1));
325
326  // Cubic interpolation.
327  f = f * f * (3.0f - 2.0f * f);
328
329  float l0 = lerp(l00, l01, f.y);
330  float l1 = lerp(l10, l11, f.y);
331  return lerp(l0, l1, f.x);
332}
333
334// p = point to get noise for
335float valueNoise3D(
336    float3 p) {
337  // quantized part
338  float3 q = floor(p);
339  // fractional part
340  float3 f = frac(p);
341
342  float l000 = rand3(q);
343  float l001 = rand3(q + float3(0, 0, 1));
344  float l010 = rand3(q + float3(0, 1, 0));
345  float l011 = rand3(q + float3(0, 1, 1));
346  float l100 = rand3(q + float3(1, 0, 0));
347  float l101 = rand3(q + float3(1, 0, 1));
348  float l110 = rand3(q + float3(1, 1, 0));
349  float l111 = rand3(q + float3(1, 1, 1));
350
351  // Cubic interpolation.
352  f = f * f * (3.0f - 2.0f * f);
353
354  float l00 = lerp(l000, l001, f.z);
355  float l01 = lerp(l010, l011, f.z);
356  float l10 = lerp(l100, l101, f.z);
357  float l11 = lerp(l110, l111, f.z);
358  float l0 = lerp(l00, l01, f.y);
359  float l1 = lerp(l10, l11, f.y);
360  return lerp(l0, l1, f.x);
361}
362
363// Fixed version of quilez's `tone` here:
364// https://iquilezles.org/articles/functions/
365float tone(float x, float k) {
366  return (x * (k + 1)) / (k * x + 1);
367}
368
369#endif  // __MATH_INC