LWJGL 2 - glReadPixel and Pbo Asynchronous read

Started by Thiird, July 08, 2018, 13:45:45

Previous topic - Next topic

Thiird

So I've been trying to implement the Pbo asynchronous read in order to pick objects in 3d space by first rendering an Id pass and then the normal color pass, to do that I used the last section of this article http://www.songho.ca/opengl/gl_pbo.html#pack
I implement the code as follows:

Main class:
PBOManager PBOManager = new PBOManager();

// Main game loop
while (!Display.isCloseRequested())
{
	// Capturing inputs to move the camera
	viewMat = camera.move();

	//Render with id shader
	MasterRenderer.renderIdView = true;
	renderer.renderScene(light, viewMat, camera.getPosition());
	PBOManager.readPixelData();

	MasterRenderer.renderIdView = false;

	//Render with normal shader
	renderer.renderScene(light, viewMat, camera.getPosition());
	PBOManager.readPixelData();

        //Display the normal shader
	display.update();
}

PBOManager.cleanUp();



And the PBOManager class looks like this:

package Render_engine;

import java.nio.ByteBuffer;

import org.lwjgl.BufferUtils;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL21;

public class PBOManager
{
	private static final int BYTES_PER_PIXEL = 4;
	private int pbos[];
	private int index = 0;
	private int nextIndex = 1;

	public static ByteBuffer buffer;

	public PBOManager()
	{
		buffer = BufferUtils.createByteBuffer(BYTES_PER_PIXEL);

		initPbos(2);
	}

	private void initPbos(int count)
	{
		this.pbos = new int[count];

		for (int i = 0; i < pbos.length; i++)
		{
			this.pbos[i] = createPbo();
		}
	}

	private int createPbo()
	{
		int pbo = GL15.glGenBuffers();

		GL15.glBindBuffer(GL21.GL_PIXEL_PACK_BUFFER, pbo);

		GL15.glBufferData(GL21.GL_PIXEL_PACK_BUFFER, BYTES_PER_PIXEL, GL15.GL_STREAM_READ);

		GL15.glBindBuffer(GL21.GL_PIXEL_PACK_BUFFER, 0);

		return pbo;
	}

	public void readPixelData()
	{
		// "index" is used to read pixels from framebuffer to a PBO
		// "nextIndex" is used to update pixels in the other PBO

		// set the target framebuffer to read
		GL11.glReadBuffer(GL11.GL_FRONT);

		// read pixels from framebuffer to PBO
		// glReadPixels() should return immediately.
		GL15.glBindBuffer(GL21.GL_PIXEL_PACK_BUFFER, this.pbos[this.index]);

		GL11.glReadPixels(Mouse.getX(), Mouse.getY(), 1, 1, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, 0);

		// map the PBO to process its data by CPU
		GL15.glBindBuffer(GL21.GL_PIXEL_PACK_BUFFER, this.pbos[this.nextIndex]);
		buffer = GL15.glMapBuffer(GL21.GL_PIXEL_PACK_BUFFER, GL15.GL_READ_ONLY, buffer);

		//If buffer not empty (will be empty only on first frame)
		if (buffer != null && buffer.hasRemaining())
		{
			this.printCurrentPixelColor();

			GL15.glUnmapBuffer(GL21.GL_PIXEL_PACK_BUFFER);
		}

		// back to conventional pixel operation
		GL15.glBindBuffer(GL21.GL_PIXEL_PACK_BUFFER, 0);

		this.index = (this.index + 1) % 2;
		this.nextIndex = (this.index + 1) % 2;
	}

	private void printCurrentPixelColor()
	{
		while (buffer.hasRemaining())
		{
			System.out.print(((int) buffer.get() & 0xFF) + ":");
		}

		System.out.println();
	}

	public void cleanUp()
	{
		GL15.glBindBuffer(GL21.GL_PIXEL_PACK_BUFFER, 0);

		for (int pbo : this.pbos)
		{
			GL15.glDeleteBuffers(pbo);
		}
	}
}


As you can see the readPixelData() method is the same snippet of code at the bottom of the article, just translated to java.

With this setup I see the normal colors, which is what I want, but the colors detected are not from the id pass but from the normal color pass:
http://prntscr.com/k3x9wm

And if comment out the second render call in the main method I see the Id pass (of course) and the color detected is correct: http://prntscr.com/k3x9cm

So from what I can see I did some error in the code for which instead of, render the id, read the color and render the normal color, and process the previosuly read color, Im only able to read and process the pixel color of the last render call.

Is my diagnosis right?


CoDi


Thiird

Quote[edit] never mind, misread

Is my post unclear?

spasi

OpenGL rendering is double-buffered. Afaict, with your current setup you end up reading the color pass of the previous frame. Try changing glReadBuffer(GL_FRONT) to glReadBuffer(GL_BACK), it should let you read the ID pass of the current frame.