yum/3ner

A toon shader for Unity's BIRP.

git clone https://git.yummers.dev/yum/3ner

yumImplement mixed-radix computationdf08b1f

master
4.1 KiB140 linesraw
1#ifndef __FOURIER_WATER_COMPUTE_INC
2#define __FOURIER_WATER_COMPUTE_INC
3
4#include "UnityCG.cginc"
5#include "UnityCustomRenderTexture.cginc"
6#include "fourier_water_twiddles.cginc"
7
8#define DIR_HORIZONTAL 0
9#define DIR_VERTICAL   1
10
11uniform uint _Stage;
12uniform uint _Big_N;
13uniform float _Size_M;
14uniform uint _Stride;
15uniform uint _Direction;
16uniform Texture2D _Signal;
17uniform float4 _Signal_TexelSize;
18
19#if defined(_RADIX_8)
20#define FFT_RADIX 8
21#elif defined(_RADIX_4)
22#define FFT_RADIX 4
23#else
24#define FFT_RADIX 2
25#endif
26
27float2 cmul(float2 x, float2 y) {
28  return float2(x[0] * y[0] - x[1] * y[1], x[0] * y[1] + x[1] * y[0]);
29}
30
31float4 mul_ni(float4 x) {
32  return x.yxwz * float4(1, -1, 1, -1);
33}
34
35float4 rot_45(float4 x) {
36  return (x - mul_ni(x)) * 0.7071067811865475;
37}
38
39// Factored butterflies from https://yummers.dev/a-fast-cpu-fft.html.
40float4 fft_radix_2(float4 a, float4 b, uint lane) {
41  return lane == 0 ? a + b : a - b;
42}
43
44float4 fft_radix_4(float4 a, float4 b, float4 c, float4 d, uint lane) {
45  float4 even = (lane & 1) == 0 ? a + c : a - c;
46  float4 odd = (lane & 1) == 0 ? b + d : mul_ni(b - d);
47  return lane < 2 ? even + odd : even - odd;
48}
49
50float4 fft_radix_8(float4 a, float4 b, float4 c, float4 d,
51    float4 e, float4 f, float4 g, float4 h, uint lane) {
52  float4 even, odd;
53  switch (lane & 3) {
54    case 0:
55      even = (a + e) + (c + g);
56      odd = (b + f) + (d + h);
57      break;
58    case 1:
59      even = (a - e) + mul_ni(c - g);
60      odd = rot_45(mul_ni(b - f) - (d - h));
61      break;
62    case 2:
63      even = (a + e) - (c + g);
64      odd = mul_ni((b + f) - (d + h));
65      break;
66    default:
67      even = (a - e) - mul_ni(c - g);
68      odd = rot_45(-(b - f) + mul_ni(d - h));
69      break;
70  }
71  return lane < 4 ? even + odd : even - odd;
72}
73
74float4 fft_stage(uint x, uint y) {
75  uint main_coord = _Direction == DIR_HORIZONTAL ? x : y;
76  uint alt_coord = _Direction == DIR_HORIZONTAL ? y : x;
77  uint start_idx = main_coord % _Stride;
78  uint group_size = _Big_N / FFT_RADIX;
79  uint k = (main_coord / _Stride) % group_size;
80  uint lane = (main_coord / _Stride) / group_size;
81  float4 v[FFT_RADIX];
82  [unroll]
83  for (uint j = 0; j < FFT_RADIX; j++) {
84    uint2 coords = uint2(start_idx + (FFT_RADIX * k + j) * _Stride, alt_coord);
85    if (_Direction == DIR_VERTICAL) {
86      coords = coords.yx;
87    }
88    v[j] = _Signal.Load(uint3(coords, 0));
89    if (j != 0 && k != 0) {
90      float2 factor = kTwiddles[j * k * _Stride];
91      v[j] = float4(cmul(v[j].rg, factor), cmul(v[j].ba, factor));
92    }
93  }
94#if defined(_RADIX_8)
95  return fft_radix_8(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], lane);
96#elif defined(_RADIX_4)
97  return fft_radix_4(v[0], v[1], v[2], v[3], lane);
98#else
99  return fft_radix_2(v[0], v[1], lane);
100#endif
101}
102
103float4 frag(v2f_customrendertexture i) : SV_Target {
104  float2 px_sz = float2(_CustomRenderTextureWidth, _CustomRenderTextureHeight);
105  uint2 px_pos = i.globalTexcoord.xy * px_sz;
106#if defined(_TIME_EVOLVE) || defined(_DERIVATIVE) || defined(_DISPLACEMENT) || defined(_DISPLACEMENT_DERIVATIVE)
107  float2 input = _Signal.Load(uint3(px_pos, 0));
108  float2 k2 = px_pos;
109  k2.x = k2.x < px_sz.x / 2 ? k2.x : k2.x - px_sz.x;
110  k2.y = k2.y < px_sz.y / 2 ? k2.y : k2.y - px_sz.y;
111  k2 *= 2.0f * 3.14159265f / _Size_M;
112  float k = length(k2);
113  float omega = sqrt(9.81f * k + 0.076f * k * k * k / 1000.0f);
114  float omega_s, omega_c;
115  sincos(omega * _Time[1], omega_s, omega_c);
116  float2 H = cmul(input, float2(omega_c, omega_s));
117  // Negative-exponent FFT: -i k/|k| moves points toward height crests.
118  float inv_k = k > 0.0 ? rcp(k) : 0.0;
119#if defined(_DERIVATIVE)
120  float2 slopeX = cmul(H, float2(0, -k2.x));
121  float2 slopeY = cmul(H, float2(0, -k2.y));
122  return float4(slopeX, slopeY);
123#elif defined(_DISPLACEMENT)
124  return float4(cmul(H, float2(0, -k2.x * inv_k)),
125      cmul(H, float2(0, -k2.y * inv_k)));
126#elif defined(_DISPLACEMENT_DERIVATIVE)
127  // RG: dDx/dy = dDy/dx; BA: dDy/dy.
128  return float4(-H * (k2.x * k2.y * inv_k),
129      -H * (k2.y * k2.y * inv_k));
130#else
131  // RG: height; BA: dDx/dx.
132  return float4(H, -H * (k2.x * k2.x * inv_k));
133#endif
134
135#else
136  return fft_stage(px_pos.x, px_pos.y);
137#endif
138}
139
140#endif  // __FOURIER_WATER_COMPUTE_INC