2013-07-31 29 views
9

Có một số nhầm lẫn e.g. về mức hỗ trợ cho việc hiển thị đối với kết cấu dấu chấm động trong WebGL. Phần mở rộng OES_texture_float dường như không ủy quyền cho nó, theo như Optional support for FLOAT textures as FBO attachments (deprecated), nhưng có vẻ như một số nhà cung cấp đã đi trước và triển khai nó. Do đó, sự hiểu biết cơ bản của tôi là việc kết xuất với các kết cấu dấu chấm động thực sự hoạt động trong môi trường máy tính để bàn không phải ES. Tuy nhiên, tôi đã không thể đọc từ mục tiêu hiển thị điểm nổi trực tiếp.WebGL Đọc pixel từ điểm nổi hiển thị mục tiêu

Câu hỏi của tôi là liệu có cách nào để đọc từ kết cấu điểm nổi bằng cách sử dụng cuộc gọi WebGLContext :: readPixels() và điểm đến Float32Array không? Cảm ơn trước.

Kèm theo là một kịch bản mà thành công đọc từ một kết cấu byte, nhưng không cho một kết cấu float:

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

Trả lời

11

Đáng tiếc là nó vẫn có vẻ như đọc to thành phần RGBA như byte là cách duy nhất cho WebGL. Nếu bạn cần để mã hóa một phao thành một giá trị điểm ảnh bạn có thể sử dụng như sau:

Trong shader fractal của bạn (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); 

Sau đó trở lại ở phía bên JavaScript, sau khi lệnh gọi vẽ của bạn có được thực hiện, bạn có thể trích xuất các giá trị float mã hóa của mỗi điểm ảnh với những điều sau:

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

Cảm ơn Adrian. Tôi có thể xác minh rằng điều này hoạt động tốt. Tôi đã sử dụng giải pháp của bạn trong công việc này: https://github.com/stharding/function-plotter – Stephen

+0

Không vấn đề gì Stephen, công việc tuyệt vời bằng cách này; vui lòng liên hệ trực tiếp nếu bạn có thêm bất kỳ câu hỏi nào: adrian [at] gatosomina [dot] com –

+1

cảm ơn rất nhiều về điều này, nó hoạt động như một sự quyến rũ và cho tôi độ chính xác mà tôi cần cho mô phỏng + Tôi không biết Float32Array (ArrayBuffer) sẽ chuyển đổi Ints thành float, rất tiện dụng :) cảm ơn! – nicoptere

7

tôi thêm những khám phá gần đây của tôi: Chrome sẽ cho phép bạn đọc nổi, như một phần của định dạng thực hiện được xác định (search for "readPixels" in the spec), Firefox triển khai WEBGL_color_buffer_float mở rộng, vì vậy bạn chỉ có thể tải phần mở rộng và đọc nổi của bạn, tôi đã không thể đọc nổi với Safari.

+0

Bạn có biết điều này có nghĩa là chức năng này được mong đợi trong webgl 2 không? – pailhead

+1

https://www.khronos.org/registry/webgl/specs/latest/2.0/#readpixels vâng, tôi nghĩ vậy. – nraynaud

+2

Cảm ơn rất nhiều vì nhận xét này. Tôi thấy trong chrome tôi có thể gọi 'gl.getContext (" thử nghiệm-webgl ")' và sau đó gọi 'gl.readPixels (0,0, chiều rộng, chiều cao, gl.RGB, gl.FLOAT, buf)' trong khi tôi có một điểm nổi FBO bị ràng buộc, trong đó 'buf' là một' Float32Array'. Nhưng làm thế nào để sử dụng phần mở rộng trong firefox? Tôi có thể gọi 'gl.getExtension (" WEBGL_color_buffer_float ")', và nó trả về một 'WEBGL_color_buffer_float {}' nhưng tôi phải làm gì với nó? – matth

Các vấn đề liên quan