WebGL Read pixels from floating point render target

前端 未结 3 1232
没有蜡笔的小新
没有蜡笔的小新 2020-12-01 07:09

There is some confusion e.g. in terms of support levels for rendering to floating point textures in WebGL. The OES_texture_float extension does not seem to mandate

相关标签:
3条回答
  • 2020-12-01 07:33

    Unfortunately it still seems that reading out RGBA components as bytes is the only way for WebGL. If you need to encode a float into a pixel value you can use the following:

    In your fractal shader (GLSL/HLSL):

    float shift_right (float v, float amt) { 
        v = floor(v) + 0.5; 
        return floor(v / exp2(amt)); 
    }
    float shift_left (float v, float amt) { 
        return floor(v * exp2(amt) + 0.5); 
    }
    float mask_last (float v, float bits) { 
        return mod(v, shift_left(1.0, bits)); 
    }
    float extract_bits (float num, float from, float to) { 
        from = floor(from + 0.5); to = floor(to + 0.5); 
        return mask_last(shift_right(num, from), to - from); 
    }
    vec4 encode_float (float val) { 
        if (val == 0.0) return vec4(0, 0, 0, 0); 
        float sign = val > 0.0 ? 0.0 : 1.0; 
        val = abs(val); 
        float exponent = floor(log2(val)); 
        float biased_exponent = exponent + 127.0; 
        float fraction = ((val / exp2(exponent)) - 1.0) * 8388608.0; 
        float t = biased_exponent / 2.0; 
        float last_bit_of_biased_exponent = fract(t) * 2.0; 
        float remaining_bits_of_biased_exponent = floor(t); 
        float byte4 = extract_bits(fraction, 0.0, 8.0) / 255.0; 
        float byte3 = extract_bits(fraction, 8.0, 16.0) / 255.0; 
        float byte2 = (last_bit_of_biased_exponent * 128.0 + extract_bits(fraction, 16.0, 23.0)) / 255.0; 
        float byte1 = (sign * 128.0 + remaining_bits_of_biased_exponent) / 255.0; 
        return vec4(byte4, byte3, byte2, byte1); 
    }
    
     // (the following inside main(){}) return your float as the fragment color
     float myFloat = 420.420;
     gl_FragColor = encode_float(myFloat);
    

    Then back on the JavaScript side, after your draw call has been made you can extract the encoded float value of each pixel with the following:

    var pixels = new Uint8Array(CANVAS.width * CANVAS.height * 4);
    gl.readPixels(0, 0, CANVAS.width, CANVAS.height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
    pixels = new Float32Array(pixels.buffer);
    
    // pixels now contains an array of floats, 1 float for each pixel
    
    0 讨论(0)
  • 2020-12-01 07:43

    I'm adding my recent discoveries: Chrome will let you read floats, as part of the implementation defined format (search for "readPixels" in the spec), Firefox implements the WEBGL_color_buffer_float extension, so you can just load the extension and read your floats, I have not been able to read floats with Safari.

    0 讨论(0)
  • 2020-12-01 07:48

    The readPixels is limited to the RGBA format and the UNSIGNED_BYTE type (WebGL specification). However there are some methods for "packing" floats into RGBA/UNSIGNED_BYTE described here:

    http://concord-consortium.github.io/lab/experiments/webgl-gpgpu/webgl.html

    0 讨论(0)
提交回复
热议问题