Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Page 1 of 2 12 LastLast
Results 1 to 10 of 25

Thread: Problem with glReadPixels using FBO

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Intern Contributor
    Join Date
    Nov 2017
    Posts
    80

    Smile Problem with glReadPixels using FBO

    Hi, All!

    I have a problem with glReadPixels function.
    There is an empty result.


    My code:
    Code :
     
        // initialization
        depthMapFBO = glGenBuffers();
        glBindBuffer(GL_PIXEL_PACK_BUFFER, depthMapFBO);
        glBufferData(GL_PIXEL_PACK_BUFFER, display.getWidth() * display.getHeight() * 4, GL_DYNAMIC_DRAW);
        glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
        ....
     
        // using after moment when scene become rendered
        glBindBuffer(GL_PIXEL_PACK_BUFFER, depthMapFBO);
        ByteBuffer buffer = BufferUtils.createByteBuffer(display.getWidth() * display.getHeight() * 4);
        glReadPixels(0, 0, display.getWidth(), display.getHeight(), GL_DEPTH_COMPONENT, GL_FLOAT, buffer);
        ByteBuffer glMapBuffer = glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_WRITE, buffer); // is not null. it seems buffer initialized ok.
        makeScreenShot(display.getWidth(), display.getHeight(), glMapBuffer);
        glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);


    But if I make screenshot like this, all is ok:
    Code :
          ByteBuffer buffer = BufferUtils.createByteBuffer(display.getWidth() * display.getHeight() * 4);
          glReadPixels(0, 0, display.getWidth(), display.getHeight(), GL_DEPTH_COMPONENT, GL_FLOAT, buffer);
          makeScreenShot(display.getWidth(), display.getHeight(), buffer);


    What is wrong with depthMapFBO's variant?


    Thanks for answer!

  2. #2
    Senior Member OpenGL Guru
    Join Date
    Jun 2013
    Posts
    2,928
    Whatever the problem is, it's probably in makeScreenShot(). In particular, I can't see how it would make sense to pass a function pointer (glMapBuffer) in one case and a ByteBuffer object in the other case.

  3. #3
    Senior Member OpenGL Guru Dark Photon's Avatar
    Join Date
    Oct 2004
    Location
    Druidia
    Posts
    4,480
    Quote Originally Posted by nimelord View Post
    My code:
    If this is supposed to be C++, it's not valid, and it shouldn't even compile.

    You should include GL prototypes and compile with a type-checking C++ compiler. That may help you clear up some of your problems.

  4. #4
    Intern Contributor
    Join Date
    Nov 2017
    Posts
    80
    Quote Originally Posted by Dark Photon View Post
    If this is supposed to be C++, it's not valid, and it shouldn't even compile.

    You should include GL prototypes and compile with a type-checking C++ compiler. That may help you clear up some of your problems.
    It is not C++, it is a java library. LWJGL - thin wrapper on the native OpenGl calls.
    GL function signatures is almost the same.

    I already implemented scene with cascade shadow mapping for the directional light, point light shadows via 'texture cube', and spot light shadow maps. And see smallest difference in signatures between C++ and LWJGL - it is glGenBuffers signature and VBO references as int, without GLunit type.

    I do not know why, but I solved all my problems by reading this forum and most of them was explaned for other OpenGl juniors.
    So, I mean this forum is much more effective place for solutions for me than others.

    I'm sorry for the difference between yous platform and my one.

    Maybe you see other problems than the wrong syntax?
    I'm sure I'm using gl calls incorrectly, but all examples I could find didn't help me find where is problem.
    Last edited by nimelord; 01-09-2018 at 02:44 AM.

  5. #5
    Senior Member OpenGL Pro
    Join Date
    Jan 2007
    Posts
    1,789
    OK, quite a few problems with your code.

    First of all, you are not actually using an FBO - you're using a PBO - a Pixel Buffer Object. That's not a code problem, it's terminology, but it's important to get it correct because if you go looking for help with FBOs you won't actually find any useful help.

    Secondly, you're using the PBO incorrectly, in that you're setting up as if you wish to glReadPixels into a PBO, then you do the actual glReadPixels as if you were reading it into a system memory pointer, then you continue as if you were reading into a PBO.

    The last argument of your glReadPixels call, if a buffer object is currently bound to GL_PIXEL_PACK_BUFFER, is not a system memory pointer but is instead interpreted as an offset into the buffer object's data store. So what you probably actually intend to use here is 0.

    The buffer's data store may then be accessed via glMapBuffer or glGetBufferSubData.

  6. #6
    Intern Contributor
    Join Date
    Nov 2017
    Posts
    80
    Quote Originally Posted by mhagain View Post
    The last argument of your glReadPixels call, if a buffer object is currently bound to GL_PIXEL_PACK_BUFFER, is not a system memory pointer but is instead interpreted as an offset into the buffer object's data store. So what you probably actually intend to use here is 0.
    You are right, it is working fine, now.
    It was rude mistake.

    Thank you a lot!

  7. #7
    Senior Member OpenGL Pro
    Join Date
    Jan 2007
    Posts
    1,789
    The other thing to watch out for with glReadPixels is that if it needs to do a format conversion during the read it will kill your performance (not that glReadPixels is fast to begin with). We typically see this when people attempt to read GL_RGB or GL_BGR data, which will always require a format conversion.

    With reading the depth buffer you might get better performance by first checking if you actually have a 32-bit floating point depth buffer to begin with, then adjusting the call to match the format you actually do have. If you really need it as floating point it can often be faster to convert in code yourself than it is to let GL do it for you.

    With PBOs the idea is not to read to a PBO then map and access it immediately after. Instead you should wait some arbitrary amount of time - one frame is good to start with - between the read and the map. This is to give the read sufficient time to complete asynchronously before you map. If you absolutely must have the data immediately then not using a PBO at all might be faster (but watch that format conversion).

    I mention these because it seems possible that you're trying to optimize this, but going down the wrong route to do so.

  8. #8
    Intern Contributor
    Join Date
    Nov 2017
    Posts
    80

    Smile Reprojection of depth map on the GPU side.

    Try to reproject depth map from previous camera position to current camera position.


    There are steps I should do for that:
    1) In the end of render cycle I save 'projection view matrix' and depth buffer to the texture.
    2) On the start of next render cycle I restore world positions with inverted 'prejection view matrix' from previous scene frame and project it for current camera position
    3) use result data for something....

    How can I do reprojection on GPU side?
    I mean I don't have positions for vertex shader and I just have depth texture and two 'prejection view matrixes' for prev and current frames.


    Thanks for answer.

  9. #9
    Senior Member OpenGL Guru Dark Photon's Avatar
    Join Date
    Oct 2004
    Location
    Druidia
    Posts
    4,480
    There's no need to start a new thread here as this is just a continuation of the same topic.

    Realizing that this technique is going to leave you with artifacts due to using one-frame-late occlusion data...

    The first of these two URLs on "Coverage Buffer Occlusion Culling" describes one way to handle this (see reconstructPos):

    Last edited by Dark Photon; 01-22-2018 at 05:52 AM.

  10. #10
    Intern Contributor
    Join Date
    Nov 2017
    Posts
    80
    Quote Originally Posted by Dark Photon View Post
    There's no need to start a new thread here as this is just a continuation of the same topic.
    Ok.

    I try to understand this one: http://rastergrid.com/blog/2010/10/h...usion-culling/

    Full source code here: http://rastergrid.com/blog/downloads/mountains-demo/


    Code :
    void MountainsDemo::renderScene(float dtime) {
     
    	this->drawCallCount = 0;
     
    	// update camera data to uniform buffer
    	this->transform.ModelViewMatrix = mat4(1.0f);
        this->transform.ModelViewMatrix = rotate(this->transform.ModelViewMatrix, this->camera.rotation.x, vec3(1.0f, 0.0f, 0.0f));
        this->transform.ModelViewMatrix = rotate(this->transform.ModelViewMatrix, this->camera.rotation.y, vec3(0.0f, 1.0f, 0.0f));
        this->transform.ModelViewMatrix = rotate(this->transform.ModelViewMatrix, this->camera.rotation.z, vec3(0.0f, 0.0f, 1.0f));
    	this->transform.ModelViewMatrix = translate(this->transform.ModelViewMatrix, -this->camera.position);
    	this->transform.MVPMatrix = this->transform.ProjectionMatrix * this->transform.ModelViewMatrix;
    	glBindBuffer(GL_UNIFORM_BUFFER, this->transformUB);
    	glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(this->transform), &this->transform);
     
    	// bind offscreen framebuffer
    	glBindFramebuffer(GL_FRAMEBUFFER, this->framebuffer);
        glClear(GL_DEPTH_BUFFER_BIT);
     
    	// draw terrain
    	glUseProgram(this->terrainPO);
     
    	glBindVertexArray(this->terrainVA);
     
    	glActiveTexture(GL_TEXTURE0);
    	glBindTexture(GL_TEXTURE_2D, this->heightmap);
    	glActiveTexture(GL_TEXTURE1);
    	glBindTexture(GL_TEXTURE_2D, this->terrainTex);
    	glActiveTexture(GL_TEXTURE2);
    	glBindTexture(GL_TEXTURE_2D, this->detailTex);
     
    	bool visible[7][7] = { false };
    	this->visibleBlocks = 0;
    	// terrain elements will be drawn only in a 7x7 grid around the camera
    	float x = roundf(-this->camera.position.x / TERRAIN_OBJECT_SIZE);
    	float z = roundf(-this->camera.position.z / TERRAIN_OBJECT_SIZE);
    	for (int i=-3; i<=3; i++)
    		for (int j=-3; j<=3; j++)
    			// perform view frustum culling for the terrain elements
    			if ( cullTerrain( vec4( TERRAIN_OBJECT_SIZE*(i-x), 0.f, TERRAIN_OBJECT_SIZE*(j-z), 1.f ) ) ) {
    				glUniform2f(glGetUniformLocation(this->terrainPO, "Offset"), TERRAIN_OBJECT_SIZE*(i-x), TERRAIN_OBJECT_SIZE*(j-z));
    				glDrawElements(terrainDraw.prim_type, terrainDraw.indexCount, GL_UNSIGNED_INT, (void*)terrainDraw.indexOffset);
    				this->drawCallCount++;
    				// store visibility so we can use it during the tree instance rendering
    				visible[i+3][j+3] = true;
    				this->visibleBlocks++;
    			}
     
    	// create Hi-Z map if necessary
    	if ( this->cullMode == HI_Z_OCCLUSION_CULL ) {
    		glUseProgram(this->hizPO);
    		// disable color buffer as we will render only a depth image
    		glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
    		glActiveTexture(GL_TEXTURE0);
    		glBindTexture(GL_TEXTURE_2D, this->depthTex);
    		// we have to disable depth testing but allow depth writes
    		glDepthFunc(GL_ALWAYS);
    		// calculate the number of mipmap levels for NPOT texture
    		int numLevels = 1 + (int)floorf(log2f(fmaxf(SCREEN_WIDTH, SCREEN_HEIGHT)));
    		int currentWidth = SCREEN_WIDTH;
    		int currentHeight = SCREEN_HEIGHT;
    		for (int i=1; i<numLevels; i++) {
    			glUniform2i(glGetUniformLocation(this->hizPO, "LastMipSize"), currentWidth, currentHeight);
    			// calculate next viewport size
    			currentWidth /= 2;
    			currentHeight /= 2;
    			// ensure that the viewport size is always at least 1x1
    			currentWidth = currentWidth > 0 ? currentWidth : 1;
    			currentHeight = currentHeight > 0 ? currentHeight : 1;
    			glViewport(0, 0, currentWidth, currentHeight);
    			// bind next level for rendering but first restrict fetches only to previous level
    			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, i-1);
    			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, i-1);
    			glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, this->depthTex, i);
    			// dummy draw command as the full screen quad is generated completely by a geometry shader
    			glDrawArrays(GL_POINTS, 0, 1);
    			this->drawCallCount++;
    		}
    		// reset mipmap level range for the depth image
    		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
    		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, numLevels-1);
    		// reset the framebuffer configuration
    		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, this->colorTex, 0);
    		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, this->depthTex, 0);
    		// reenable color buffer writes, reset viewport and reenable depth test
    		glDepthFunc(GL_LEQUAL);
    		glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
    		glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
    	}
     
    	if ( !this->showDepthTex ) {
    		// render tree instances and apply culling
    		glUseProgram(this->cullPO);
    		glUniformSubroutinesuiv(GL_VERTEX_SHADER, 1, &this->subIndexVS[this->cullMode]);
    		glUniformSubroutinesuiv(GL_GEOMETRY_SHADER, 1, &this->subIndexGS[this->LODMode ? 1 : 0]);
     
    		glEnable(GL_RASTERIZER_DISCARD);
    		glBindVertexArray(this->cullVA);
     
    		for (int i=0; i<NUM_LOD; i++)
    			glBeginQueryIndexed(GL_PRIMITIVES_GENERATED, i, this->cullQuery[i]);
     
    		glBeginTransformFeedback(GL_POINTS);
    		for (int i=-3; i<=3; i++)
    			for (int j=-3; j<=3; j++)
    				if ( visible[i+3][j+3] ) {
    					glUniform2f(glGetUniformLocation(this->cullPO, "Offset"), TERRAIN_OBJECT_SIZE*(i-x), TERRAIN_OBJECT_SIZE*(j-z));
    					glDrawArrays(GL_POINTS, 0, this->instanceCount);
    					this->drawCallCount++;
    				}
    		glEndTransformFeedback();
     
    		for (int i=0; i<NUM_LOD; i++)
    			glEndQueryIndexed(GL_PRIMITIVES_GENERATED, i);
     
    		glDisable(GL_RASTERIZER_DISCARD);
     
    		glBindVertexArray(this->terrainVA);
    		// draw skybox
    		glUseProgram(this->skyboxPO);
    		glActiveTexture(GL_TEXTURE0);
    		glBindTexture(GL_TEXTURE_2D_ARRAY, this->skyboxTex);
    		// dummy draw command as the skybox itself is generated completely by a geometry shader
    		glDrawArrays(GL_POINTS, 0, 1);
    		this->drawCallCount++;
     
    		// draw trees
    		glUseProgram(this->treePO);
    		glActiveTexture(GL_TEXTURE0);
    		glBindTexture(GL_TEXTURE_2D_ARRAY, this->treeTex);
    		glActiveTexture(GL_TEXTURE1);
    		glBindTexture(GL_TEXTURE_2D, this->terrainTex);
     
    		// get the number of instances from the query object
    		for (int i=0; i<NUM_LOD; i++) {
    			if ( this->showLODColor ) {
    				switch ( i ) {
    				case 0: glUniform4f(glGetUniformLocation(this->treePO, "ColorMask"), 1.0, 0.0, 0.0, 1.0); break;
    				case 1: glUniform4f(glGetUniformLocation(this->treePO, "ColorMask"), 0.0, 1.0, 0.0, 1.0); break;
    				case 2: glUniform4f(glGetUniformLocation(this->treePO, "ColorMask"), 0.0, 0.0, 1.0, 1.0); break;
    				}
    			}
    			glBindVertexArray(this->treeVA[i]);
    			glGetQueryObjectiv(this->cullQuery[i], GL_QUERY_RESULT, &this->visibleTrees[i]);
    			if ( this->visibleTrees[i] > 0 ) {
    				// draw the trees
    				glDrawElementsInstanced(treeDraw[i].prim_type, treeDraw[i].indexCount, GL_UNSIGNED_INT, (void*)(treeDraw[i].indexOffset*sizeof(uint)), this->visibleTrees[i]);
    				this->drawCallCount++;
    			}
    		}
    		if ( this->showLODColor ) {
    			glUniform4f(glGetUniformLocation(this->treePO, "ColorMask"), 1.0, 1.0, 1.0, 1.0);
    		}
    	}
     
    	// bind default framebuffer and render post processing
    	glBindFramebuffer(GL_FRAMEBUFFER, 0);
    	glUseProgram(this->postPO);
     
    	// visualize depth buffer texture if needed
    	if ( this->showDepthTex ) {
    		glUseProgram(this->depthPO);
    		glUniform1f(glGetUniformLocation(this->depthPO, "LOD"), this->LOD);
    	}
     
    	glActiveTexture(GL_TEXTURE0);
    	glBindTexture(GL_TEXTURE_2D, this->colorTex);
    	glActiveTexture(GL_TEXTURE1);
    	glBindTexture(GL_TEXTURE_2D, this->depthTex);
    	glDisable(GL_DEPTH_TEST);
    	// dummy draw command as the full screen quad is generated completely by a geometry shader
    	glDrawArrays(GL_POINTS, 0, 1);
    	this->drawCallCount++;
    	glEnable(GL_DEPTH_TEST);
     
    	GLenum glError;
    	if ((glError = glGetError()) != GL_NO_ERROR) {
    		cout << "Warning: OpenGL error code: " << glError << endl;
    	}
     
    }

    Where is the rendering of first depth map?
    It must be ready before building of mipmap as I think.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •