glslwebglfftifft

WebGL inverse FFT implementation


I am trying to implement an FFT and associated inverse FFT in WebGL using fragment shaders. I am using shader code from this github site. I believe that I am doing the FFT correctly as I am getting results that seem correct however my implementation for the inverse FFT is not giving me the initial result back like it should. My understanding for the inverse FFT is just to change the sign on the twiddle Factor argument:

FFT twiddleArgument = -2.0 * PI * (index / u_subtransformSize)
iFFT twiddleArgument = 2.0 * PI * (index / u_subtransformSize)

Is there anything conceptually that I am doing wrong here?

FFT Shader code:

//GPU FFT using a Stockham formulation
#define HORIZONTAL
precision mediump float;
const float PI = 3.14159265359;
uniform sampler2D u_input_complex;
uniform float u_transformSize;
uniform float u_subtransformSize;

varying vec2 vUV;

vec2 multiplyComplex (vec2 a, vec2 b) {
    return vec2(a[0] * b[0] - a[1] * b[1], a[1] * b[0] + a[0] * b[1]);
}

void main(void){
    #ifdef HORIZONTAL
        float index = vUV.x * u_transformSize - 0.5;
    #else
        float index = vUV.y * u_transformSize - 0.5;
    #endif

    float evenIndex = floor(index / u_subtransformSize) * (u_subtransformSize * 0.5) + mod(index, u_subtransformSize * 0.5);

    //transform two complex sequences simultaneously
    #ifdef HORIZONTAL
        vec4 even = texture2D(u_input_complex, vec2(evenIndex + 0.5, gl_FragCoord.y) / u_transformSize).rgba;
        vec4 odd = texture2D(u_input_complex, vec2(evenIndex + u_transformSize * 0.5 + 0.5, gl_FragCoord.y) / u_transformSize).rgba;
    #else
        vec4 even = texture2D(u_input_complex, vec2(gl_FragCoord.x, evenIndex + 0.5) / u_transformSize).rgba;
        vec4 odd = texture2D(u_input_complex, vec2(gl_FragCoord.x, evenIndex + u_transformSize * 0.5 + 0.5) / u_transformSize).rgba;
    #endif

    float twiddleArgument1D = -2.0 * PI * (index / u_subtransformSize);
    vec2 twiddle1D = vec2(cos(twiddleArgument1D), sin(twiddleArgument1D));

    vec2 outputA = even.xy + multiplyComplex(twiddle1D, odd.xy);  //even.xy
    vec2 outputB = even.zw + multiplyComplex(twiddle1D, odd.zw); //even.zw

    gl_FragColor = vec4(outputA,outputB);
}

Inverse FFT Shader Code:

precision mediump float;
const float PI = 3.14159265359;
uniform sampler2D u_input;
uniform float u_transformSize;
uniform float u_subtransformSize;

varying vec2 vUV;

vec2 multiplyComplex (vec2 a, vec2 b) {
    return vec2(a[0] * b[0] - a[1] * b[1], a[1] * b[0] + a[0] * b[1]);
}

void main(void){
    #ifdef HORIZONTAL
        float index = vUV.x * u_transformSize - 0.5;
    #else
        float index = vUV.y * u_transformSize - 0.5;
    #endif

    float evenIndex = floor(index / u_subtransformSize) * (u_subtransformSize * 0.5) + mod(index, u_subtransformSize * 0.5);

    //transform two complex sequences simultaneously
    #ifdef HORIZONTAL
        vec4 even = texture2D(u_input, vec2(evenIndex + 0.5, gl_FragCoord.y) / u_transformSize).rgba;
        vec4 odd = texture2D(u_input, vec2(evenIndex + u_transformSize * 0.5 + 0.5, gl_FragCoord.y) / u_transformSize).rgba;
    #else
        vec4 even = texture2D(u_input, vec2(gl_FragCoord.x, evenIndex + 0.5) / u_transformSize).rgba;
        vec4 odd = texture2D(u_input, vec2(gl_FragCoord.x, evenIndex + u_transformSize * 0.5 + 0.5) / u_transformSize).rgba;
    #endif

    float twiddleArgument1D = 2.0 * PI * (index / u_subtransformSize);
    vec2 twiddle1D = vec2(cos(twiddleArgument1D), sin(twiddleArgument1D));

    vec2 outputA = even.xy + multiplyComplex(twiddle1D, odd.xy);
    vec2 outputB = even.zw + multiplyComplex(twiddle1D, odd.zw); //even.zw

    gl_FragColor = vec4(outputA, outputB);
}

Solution

  • The error that I was seeing was related to a typo in another shader program that I was running (not the shader programs posted in the question). I have it working now. The shaders in the question work for FFT and iFFT.