Is the CanvasPixelArray image directly accessible to the WebGL canvas context?

I use Three.js to draw 3D models on a webgl canvas renderer over simple DOM elements, and I need to do collision detection between them. My working method is to use renderer.domElement.toDataURL (), load it as an imageData object, then draw it on a separate 2D canvas, then pull out the array of pixels getImageData () and iterate using this amazing pixel collision function .

This is incredibly slow, and this frame rate drops to an almost unplayable ~ 5-8 FPS. Without starting this hit detection, I get about 40-50 FPS.

My best guess is that slowdown is incredibly cumbersome toDataURL () -> load image-> drawImage () -> getImageData ().

My question becomes: Is there a better way to access flattened 2D pixel data available on WebGL canvas? or perhaps the best method for extrapolating the coordinates of a 3D object without parallax? Honestly, any way to get some kind of collision definition faster than I'm doing right now would be very helpful.

EDIT : WebGL context.readPixels () works great for me and very fast compared to my previous kludge. Although it should be noted that the data array is mirrored from top to bottom compared to a data array with a normal image size. I just flipped over my routine check of the cost of Y and decided that it would work, although others might run into more complex ways. Good luck

+4
source share
2 answers

You can use gl.readPixels :

 // Render your scene first then... var left = 0; var top = 0; var width = canvas.width; var height = canvas.height; var pixelData = new Uint8Array(width * height * 4); gl.readPixels(left, top, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixelData); 

pixelData now contains scene pixel data as unsigned bytes (0-255) laid out as [R, G, B, A, R, G, B, A...] There should be the same data as getImageData , but with much lower cost.

[ EDIT: ]

I forgot to mention that if you are going to do this, you need to create your WebGL context using the preserveDrawingBuffer parameter, for example:

 var gl = canvas.getContext("experimental-webgl", {preserveDrawingBuffer: true}); 

This prevents WebGL from internally clearing the buffer before you reach it (which will result in a large number of empty pixels being read). Enabling this option may slow down the rendering, but it will still load faster than 5-8 FPS! :)

+4
source
  renderer = new THREE.WebGLRenderer({ antialias: true, preserveDrawingBuffer:true }); var gl = renderer.getContext() var buf = new Uint8Array(200 * 200 * 4); gl.readPixels(0, 0, 200, 200, gl.RGBA, gl.UNSIGNED_BYTE, buf); console.log(buf); 

it works great.

0
source

Source: https://habr.com/ru/post/1398660/


All Articles