2013-07-31 70 views
9

WebGL'de kayan nokta dokuları için görüntülemesi görüntülenme düzeylerinde e.g. karışıklık var. OES_texture_float eklentisi, Optional support for FLOAT textures as FBO attachments (deprecated) uyarınca, kendi başına yetkisiz gibi görünmüyor, ancak bazı satıcıların öne çıkıp uygulamaya koyduğu anlaşılıyor. Bu nedenle benim temel anlayışım, kayan nokta dokularına işlenmenin aslında ES olmayan masaüstü ortamlarında çalıştığıdır. Kayan nokta render hedefinden okumayı başaramadım.WebGL Kayan nokta işlem hedefinden piksel okuma

Sorum, bir WebGLContext :: readPixels() çağrısı ve Float32Array hedefi kullanılarak kayan nokta yapısından okunmanın bir yolu olup olmadığıdır. Şimdiden teşekkürler. Ekli

bir bayt doku okuma başarır bir komut dosyası, ancak bir yüzdürme doku için başarısız:

<html> 
<head> 
<script> 
function run_test(use_float) { 
    // Create canvas and context 
    var canvas = document.createElement('canvas'); 
    document.body.appendChild(canvas); 
    var gl = canvas.getContext("experimental-webgl"); 

    // Decide on types to user for texture 
    var texType, bufferFmt; 
    if (use_float) { 
     texType = gl.FLOAT; 
     bufferFmt = Float32Array; 
    } else { 
     texType = gl.UNSIGNED_BYTE; 
     bufferFmt = Uint8Array; 
    } 

    // Query extension 
    var OES_texture_float = gl.getExtension('OES_texture_float'); 
    if (!OES_texture_float) { 
     throw new Error("No support for OES_texture_float"); 
    } 

    // Clear 
    gl.viewport(0, 0, canvas.width, canvas.height); 
    gl.clearColor(1.0, 0.0, 0.0, 1.0); 
    gl.clear(gl.COLOR_BUFFER_BIT); 

    // Create texture 
    var texture = gl.createTexture(); 
    gl.bindTexture(gl.TEXTURE_2D, texture); 
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); 
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); 
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); 
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 512, 512, 0, gl.RGBA, texType, null); 

    // Create and attach frame buffer 
    var fbo = gl.createFramebuffer(); 
    gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); 
    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0); 
    gl.bindTexture(gl.TEXTURE_2D, null); 
    if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) { 
     throw new Error("gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE"); 
    } 

    // Clear 
    gl.viewport(0, 0, 512, 512); 
    gl.clear(gl.COLOR_BUFFER_BIT); 
    var pixels = new bufferFmt(4 * 512 * 512); 
    gl.readPixels(0, 0, 512, 512, gl.RGBA, texType, pixels); 

    if (pixels[0] !== (use_float ? 1.0 : 255)) { 
     throw new Error("pixels[0] === " + pixels[0].toString()); 
    } 
} 

function main() { 
    run_test(false); 
    console.log('Test passed using GL_UNSIGNED_BYTE'); 
    run_test(true); 
    console.log('Test passed using GL_FLOAT'); 
} 
</script> 
</head> 
<body onload='main()'> 
</body> 
</html> 

cevap

11

Ne yazık ki hala bayt olarak RGBA bileşenlerini dışarı okuma WebGL için tek yol gibi görünüyor. senin fraktal shader olarak

(GLSL/HLSL): Eğer bir piksel değerinde bir float kodlamak gerekiyorsa aşağıdaki kullanabilirsiniz

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); 

Sonra geri JavaScript tarafında, sizin beraberlik çağrısı vardır sonra yapılmış aşağıdaki her pikselin kodlanmış şamandıra değerini çıkarabilir:

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 
+1

Teşekkürler Adrian. Bunun iyi çalıştığını doğrulayabilirim. Bu çalışmada çözümünüzü kullandım: https://github.com/stharding/function-plotter – Stephen

+0

Sorun yok Stephen, bu arada harika işler; Başka sorularınız varsa doğrudan ulaşmaktan çekinmeyin: adrian [at] gatosomina [nokta] com –

+1

bunun için çok teşekkürler, bir cazibe gibi çalıştı ve bana bir simülasyon için gereken hassaslığı verdi + Bilmiyordum Float32Array (ArrayBuffer), Ints'ı floatlara dönüştürecek, bu çok kullanışlı :) teşekkürler! – nicoptere

7

benim son keşifler ekliyorum: Chrome uygulama tanımlı biçimi (search for "readPixels" in the spec), Firefox bir parçası olarak, yüzen okuyalım olacak'yi uygulareklentisi, bu yüzden sadece uzantıyı yükleyebilir ve şamandıralarınızı okuyabilir, Safari ile şamandıraları okuyamadım.

+0

Bu, webgl 2'de bu işlevin bekleneceği anlamına mı geliyor? – pailhead

+1

https://www.khronos.org/registry/webgl/specs/latest/2.0/#readpixels evet, öyle düşünüyorum. – nraynaud

+2

Bu yorum için çok teşekkürler. Ben chrome 'gl.getContext ("experimental-webgl")' diyebilirim ve sonra "gl.readPixels (0,0, width, height, gl.RGB, gl.FLOAT, buf)" diyebilirim. kayan nokta FBO bağlı, burada 'buf' bir Float32Array 'dir. Ancak uzantıyı firefox'ta nasıl kullanırım? 'Gl.getExtension (" WEBGL_color_buffer_float ")' ı çağırabilir ve 'WEBGL_color_buffer_float {}' döndürür, ancak bununla ne yaparım? – matth