Reading Pixels in WebGL 2 as Float values - opengl-es

I need to read the pixels of my framebuffer as float values.
My goal is to get a fast transfer of lots of particles between CPU and GPU and process them in realtime. For that I store the particle properties in a floating point texture.
Whenever a new particle is added, I want to get the current particle array back from the texture, add the new particle properties and then fit it back into the texture (this is the only way I could think of to dynamically add particles and process them GPU-wise).
I am using WebGL 2 since it supports reading back pixels to a PIXEL_PACK_BUFFER target. I test my code in Firefox Nightly. The code in question looks like this:
// Initialize the WebGLBuffer
this.m_particlePosBuffer = gl.createBuffer();
gl.bindBuffer(gl.PIXEL_PACK_BUFFER, this.m_particlePosBuffer);
gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);
...
// In the renderloop, bind the buffer and read back the pixels
gl.bindBuffer(gl.PIXEL_PACK_BUFFER, this.m_particlePosBuffer);
gl.readBuffer(gl.COLOR_ATTACHMENT0); // Framebuffer texture is bound to this attachment
gl.readPixels(0, 0, _texSize, _texSize, gl.RGBA, gl.FLOAT, 0);
I get this error in my console:
TypeError: Argument 7 of WebGLRenderingContext.readPixels could not be converted to any of: ArrayBufferView, SharedArrayBufferView.
But looking at the current WebGL 2 Specification, this function call should be possible. Using the type gl.UNSIGNED_BYTE also returns this error.
When I try to read the pixels in an ArrayBufferView (which I want to avoid since it seems to be way slower) it works with the format/type combination of gl.RGBA and gl.UNSIGNED_BYTE for a Uint8Array() but not with gl.RGBA and gl.FLOAT for a Float32Array() - this is as expected since it's documented in the WebGL Specification.
I am thankful for any suggestions on how to get my float pixel values from my framebuffer or on how to otherwise get this particle pipeline going.

Did you try using this extension?
var ext = gl.getExtension('EXT_color_buffer_float');

The gl you have is webgl1,not webgl2.Try:
var gl = document.getElementById("canvas").getContext('webgl2');

In WebGL2 the syntax for glReadPixel is
void gl.readPixels(x, y, width, height, format, type, ArrayBufferView pixels, GLuint dstOffset);
so
let data = new Uint8Array(gl.drawingBufferWidth * gl.drawingBufferHeight * 4);
gl.readPixels(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight, gl.RGBA, gl.UNSIGNED_BYTE, pixels, 0);
https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/readPixels

Related

Is there a way to modify alpha in a texture without affecting the RGB values?

I need to sample the RGBA values of a texture, and I'm using the alpha channel to store custom data, not really to as opacity. The problem is that as alpha approaches 0, my RGB values also get multiplied towards 0, but I need them to remain independent.
My first render pass gets rendered into a WebGLRenderTarget, and this is how I'm storing data in GLSL into the alpha channel:
gl_FragColor.rgb = mainColor;
gl_FragColor.a = depthData;
the result shows Alpha fading to white as expected:
My second render pass gets rendered to the canvas, so I read the RGB values from from the first texture in GLSL, with alpha as 1:
gl_FragColor.rgb = texture2D(tColor, vUv).rgb;
gl_FragColor.a = 1.0;
The result should be the regular RGB values of the spheres, but it seems that the RGB values fade to black when Alpha approaches 0.
Is there a way to use the alpha channel as data storage without affecting the RGB values? I've tried setting the target texture's premultiplyAlpha = false as follows, but it doesn't change anything:
var target = new THREE.WebGLRenderTarget(
window.innerWidth,
window.innerHeight, {
format: THREE.RGBAFormat,
type: THREE.UnsignedByteType
});
target.texture.premultiplyAlpha = false;
Update:
I was building a working demo here, and I was unable to reproduce the bug. It looks like I'm going to have to rip apart my entire project until I get to the bottom of this...

Does webgl drawArray() empty/discard the buffers?

Trying to speed up the display of many near-identical objects in WebGL, I tried (naively, I guess), to re-use the buffers content. In the drawing routine of each object, I have (somewhat simplified):
if (! dataBuffered) {
dataBuffered = true;
:
: gl stuff here: texture loading, buffer binding and filling
:
}
// set projection and model-view matrices
gl.uniformMatrix4fv (shaderProgram.uPMatrix, false, pMatrix);
gl.uniformMatrix4fv (shaderProgram.uMVMatrix, false, mvMatrix);
// draw rectangle filled with texture
gl.drawArrays(gl.TRIANGLE_STRIP, 0, starVertexPositionBuffer.numItems);
My idea was that the texture, vertex, and texture coordinates buffer are the same, but the model-view matrix changes (same object in different places). But, alas, nothing shows up. When I comment the dataBuffered = true, it's visible.
So my question is, does drawArray() discard or empty the buffers? What else is happening? (I'm working along the lessons at learningwebgl.com, if that matters.)
Short answer is, Yes, you can reuse all the state you've set up for more than one gl.drawArrays().
http://omino.com/experiments/webgl/simplestWebGlReuseBuffers.html is a little example where it just changes one uniform float (Y-scale) and redraws, twice for every tick.
(In this case there's no textures, but some other state stays sticky.)
Hope that helps!
uniformSetFloat(gl,prog,"scaleY",1.0);
gl.drawArrays(gl.TRIANGLES, 0, posPoints.length / 3);
uniformSetFloat(gl,prog,"scaleY",0.2);
gl.drawArrays(gl.TRIANGLES, 0, posPoints.length / 3);

android OpenGLES 1.x CameraPreview to Surfacetexture

I am trying to send the camera preview to a surfacetexture object and render it on a square. I have running code for GLES20 but didnt find anything for 1.x.
Basically it should work like this, right?
// setup texture
gl.glActiveTexture(GL10.GL_TEXTURE0);
gl.glGenTextures(1, textures, 0);
gl.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textures[0]);
gl.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, ...);
...
// setup surfacetexture object
surface = new SurfaceTexture(textures[0]);
surface.setOnFrameAvailableListener(this);
// setup camera
mCamera = Camera.open(0);
Camera.Parameters param = mCamera.getParameters();
List<Size> psize = param.getSupportedPreviewSizes();
//find previewsize to match glsurface from renderer
param.setPreviewSize(psize.get(i).width, psize.get(i).height);
mCamera.setParameters(param);
// set the texture and start preview
mCamera.setPreviewTexture(surface);
mCamera.startPreview();
// in the "onFrameAvailable" handler, i switch a flag to mark a new frame
updateSurface = true;
// and in the renderloop i update and redraw
if (updateSurface) {
surface.updateTexImage();
updateSurface = false;
}
gl.glActiveTexture(GL10.GL_TEXTURE0);
gl.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textures[0]);
// Draw square
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBufferFloor);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, vertices.length / 3);
The square gets drawn but is completely white. I dont receive glErrors or other exceptions. The "onFrameAvailable" handler gets called too.
If i use glTeximage with a loaded bitmap, it is correctly drawn on the square.
ANY ideas? Thank you!
I'm facing the same problem. Maybe I'm wrong, but it seems that SurfaceTexture is not compatible with GLES10. Surface texture uses GL_TEXTURE_EXTERNAL_OES, thereby it a custom fragment shader that is able to use this texture ("#extension GL_OES_EGL_image_external : require ").
As glUseProgram(...), etc are not avaible in GLES10, we cannot use custom shaders.
As I said, maybe I'm wrong... Good luck
EDIT : I finaly get it to work. You should use "gl.glEnable(GLES11Ext.GL_TEXTURE_EXTERNAL_OES);"

OpenGL ES 2.x: Bind both `GL_TEXTURE_2D` and `GL_TEXTURE_CUBE_MAP` in the same texture image unit?

What happens if you bind (different textures) to both GL_TEXTURE_2D and GL_TEXTURE_CUBE_MAP in the same texture image unit?
For example, suppose I bind one texture to GL_TEXTURE0's GL_TEXTURE_2D target and another texture to the same texture unit's GL_TEXTURE_CUBE_MAP target. Can I then have two uniform variables, one a sampler2D and the other a samplerCube and set both to 0 (to refer to GL_TEXTURE0)?
I suspect the answer is "no" (or that the result is undefined) but I haven't found anything in the spec that specifically prohibits using multiple texture targets in the same texture image unit.
I haven't found anything that describes if you can bind a 2D texture and a cube map texture in the same texture unit, but (or so) I guess this is perfectly possible. It makes sense to allow it, since all texture modification functions require you to specify the texture target to operate on, anyway.
But the OpenGL ES 2 spec explicitly disallows to use both at the same time in a shader, as chapter 2.10 says:
It is not allowed to have variables of different sampler types
pointing to the same texture image unit within a program object. This
situation can only be detected at the next rendering command issued,
and an INVALID_OPERATION error will then be generated.
So you cannot use both a sampler2D and a samplerCube referring to the same texture unit to bend your implementation's texture unit limits.
For Chrome, I'm getting an error trying to perform such an operation.
var gl = document.getElementById("canv00").getContext("webgl");
const texture = gl.createTexture()
gl.bindTexture(gl.TEXTURE_2D, texture)
gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture)
gl.getParameter(gl.TEXTURE_BINDING_2D) // texture
gl.getParameter(gl.TEXTURE_BINDING_CUBE_MAP) // null
gl.getError() // returns 1282 error
var gl = document.getElementById("canv00").getContext("webgl");
const texture = gl.createTexture()
gl.bindTexture(gl.TEXTURE_2D, texture)
// gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture)
gl.getParameter(gl.TEXTURE_BINDING_2D) // texture
gl.getParameter(gl.TEXTURE_BINDING_CUBE_MAP) // null
gl.getError() // no error
var gl = document.getElementById("canv00").getContext("webgl");
const texture = gl.createTexture()
// gl.bindTexture(gl.TEXTURE_2D, texture)
gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture)
gl.getParameter(gl.TEXTURE_BINDING_2D) // null
gl.getParameter(gl.TEXTURE_BINDING_CUBE_MAP) // texture
gl.getError() // no error

Open GL ES texture: Set a transparent color || alpha of a color to zero

I've got a texture in which I want to set the alpha for a single color (e.g. (255,255,255)) to 0.
I use this calls at the moment (self.texture is a CCTexture2D from cocos2d)
glBindTexture(GL_TEXTURE_2D, self.texture.name);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, baseAddress);
The texture displays perfectly. I hope you can help me.
Im not sure if i understood this and I'm fairly new to opengl but i think you want just one colour to be transparent can't you over lay two textures making one transeparent using the
gl.glblendfunc()
boolean SEE_THRU = true;
if (SEE_THRU) {
gl.glDisable(GL10.GL_DEPTH_TEST);
gl.glEnable(GL10.GL_BLEND);
gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE);
}
There's no way to do this with OpenGL commands. You'll have to either use a shader to filter for pixels of a certain color, or modify the pixel data at baseAddress in a pixel-by-pixel loop before uploading it to glTexImage2D.

Resources