yum/3ner
A toon shader for Unity's BIRP.
git clone https://git.yummers.dev/yum/3ner
df08b1f
master
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