Any way to improve fps with color picking?

Started by Daslee, January 24, 2013, 19:14:24

Previous topic - Next topic

Daslee

Hello. I added color picking in my game, looks good, but one problem... FPS too low.

Now game renders all objects two times, first time only color and checking for color picking, then clears graphics and renders normal objects with textures. Is there any way to increase fps with color picking? Here is the code where it renders all world:

glDisable(GL_TEXTURE_2D);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	//clear the screen
		//draw everything to the screen
		for(Object obj : world.visibleCollidingObjects) obj.renderColor();
		glFlush();//might be important, in order, for the drawing to finish, alternatively glFinish(), to ensure that
		ByteBuffer rgb = BufferUtils.createByteBuffer(3);
		//and read the current color (where the cursor is), without lighting or texturing, just the original color
		glReadPixels(x, y, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, rgb);
		
		for(Object obj : world.visibleCollidingObjects) obj.selected = false;
		for(Object obj : world.visibleCollidingObjects){
			for(int i=0; i<obj.sides.length; i++){
				if(obj.sides[i] == null) continue;
				if(obj.sides[i].r == (rgb.get(0) & 0xFF) &&
						obj.sides[i].g == (rgb.get(1) & 0xFF) &&
						obj.sides[i].b == (rgb.get(2) & 0xFF)){
					obj.selected = true;
					selectedObjectIndex = world.objects.indexOf(obj);
					selectedSide = i;
					break;
				}
			}
		}
		glEnable(GL_TEXTURE_2D);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	//clear the screen
		for(Object obj : world.visibleCollidingObjects) obj.render();


Any ideas for increasing fps? Now it's around 40-58. If I'm looking to the place where are no objects, then fps is as before 70, but when looking to the rendering objects, then lagg and fps around 40-58..

Mickelukas

The best way to do color picking is to... not do it ;) Look into ray picking instead as it is way quicker and, if done correctly, almost just as easy to maintain.

The code you posted looks correct to me, color picking is quite slow. The only few things could be to create the byte buffer once and reuse it instead of creating it at each frame, store the objects in a map with the color as key to improve the time it takes to find the correct color code (if you have a lot of objects) as well as store the currently selected object somewhere globally instead of on each object.

Mike

Fool Running

A couple things would help.
1) The biggest thing is to not use color picking to determine what has been clicked. If this is an option (i.e. you don't *need* the color-picking functionality), then it's better to use ray picking instead of drawing everything twice.
2) If you need this functionality, then the next thing is to not create a new ByteBuffer each frame. It's better to create one earlier (like in the constructor or initialization) and just keep reusing it.
3) I don't know how many objects you have on-screen, but getting values out of a ByteBuffer using get() is also fairly slow so you should store the values before you loop through the objects to see if they have been picked.
4) Using "foreach" versions of "for" is not recommended for games since it creates extra objects that need to be garbage collected (the enumerator). It probably won't be causing much of a slowdown, but it will cause hiccups in the smoothness of the game.

Also, looking at your object rendering code might help. You might be rendering them using immediate-mode - which is slow.

EDIT: Mickelukas beat me.  :P
Programmers will, one day, rule the world... and the world won't notice until its too late.Just testing the marquee option ;D

Daslee

Quote from: Fool Running on January 25, 2013, 13:50:48
A couple things would help.
1) The biggest thing is to not use color picking to determine what has been clicked. If this is an option (i.e. you don't *need* the color-picking functionality), then it's better to use ray picking instead of drawing everything twice.
2) If you need this functionality, then the next thing is to not create a new ByteBuffer each frame. It's better to create one earlier (like in the constructor or initialization) and just keep reusing it.
3) I don't know how many objects you have on-screen, but getting values out of a ByteBuffer using get() is also fairly slow so you should store the values before you loop through the objects to see if they have been picked.
4) Using "foreach" versions of "for" is not recommended for games since it creates extra objects that need to be garbage collected (the enumerator). It probably won't be causing much of a slowdown, but it will cause hiccups in the smoothness of the game.

Also, looking at your object rendering code might help. You might be rendering them using immediate-mode - which is slow.

EDIT: Mickelukas beat me.  :P

1) I do not wanna to do ray picking, because it's too hard for me.
2) Done
3) Still reading and trying to understand how to do that..
4) So now I should do it like this:
for(int i=0; i<world.visibleCollidingObjects.size(); i++){
			world.visibleCollidingObjects.get(i)...
		}


or I can do like this:

for(int i=0; i<world.visibleCollidingObjects.size(); i++){
			Object obj = world.visibleCollidingObjects.get(i);
			...
		}


???

Mickelukas

Quote from: Fool Running on January 25, 2013, 13:50:48
EDIT: Mickelukas beat me.  :P

And we seem to think exactly alike :)

Quote from: Daslee on January 25, 2013, 14:23:49
3) Still reading and trying to understand how to do that..

Instead of doing:
for(Object obj : world.visibleCollidingObjects){
	for(int i=0; i<obj.sides.length; i++){
		if(obj.sides[i].r == (rgb.get(0) & 0xFF) &&
			obj.sides[i].g == (rgb.get(1) & 0xFF) &&
			obj.sides[i].b == (rgb.get(2) & 0xFF))
		}
	}
}

Do something like:
Byte r=rgb.get(0);
Byte g=rgb.get(1);
Byte b=rgb.get(2);
for(Object obj : world.visibleCollidingObjects){
			for(int i=0; i<obj.sides.length; i++){
				if(obj.sides[i].r == (r & 0xFF) &&
						obj.sides[i].g == (g & 0xFF) &&
						obj.sides[i].b == (b & 0xFF))
				}
			}
		}


You're never going to get a great performance out of it though and learning ray picking is time well spent :)

Mike

Daslee

Quote from: Mickelukas on January 26, 2013, 20:50:09
Quote from: Fool Running on January 25, 2013, 13:50:48
EDIT: Mickelukas beat me.  :P

And we seem to think exactly alike :)

Quote from: Daslee on January 25, 2013, 14:23:49
3) Still reading and trying to understand how to do that..

Instead of doing:
for(Object obj : world.visibleCollidingObjects){
	for(int i=0; i<obj.sides.length; i++){
		if(obj.sides[i].r == (rgb.get(0) & 0xFF) &&
			obj.sides[i].g == (rgb.get(1) & 0xFF) &&
			obj.sides[i].b == (rgb.get(2) & 0xFF))
		}
	}
}

Do something like:
Byte r=rgb.get(0);
Byte g=rgb.get(1);
Byte b=rgb.get(2);
for(Object obj : world.visibleCollidingObjects){
			for(int i=0; i<obj.sides.length; i++){
				if(obj.sides[i].r == (r & 0xFF) &&
						obj.sides[i].g == (g & 0xFF) &&
						obj.sides[i].b == (b & 0xFF))
				}
			}
		}


You're never going to get a great performance out of it though and learning ray picking is time well spent :)

Mike

Heh fps got increased per 10-15 :D I know that I'll never get great performance with color picking, but ray picking is haard. Maybe later after completing some easier things I'll try to do ray picking.

Thanks for help. :)