my gluUnProject calls is way to costly

Started by
10 comments, last by Wilhelm van Huyssteen 14 years, 6 months ago
hey! in the RTS like game im making i need to determine the 3D location of my mouse pointer so i can know for example where to place buildings etc. every frame i get this location and i store it somewhere and if i ever need it i just read from that variable. This is freaking slow... so to improve it i changed it so it only updates twice a second instead of every frame. The result is a small but anoying lag spike twice a second... since my rendering and game logic happens on separate threads i cant update it on demand (and even if i could i still dont want that lag spike). is there maybe a better way to get the cursor position in 3D space than using gluUnProject? or am i just using it wrong. Thnx in Advance!
Advertisement
Are you using glReadPixels, to obtain the Z to pass to gluUnProject?
sorry i didnt mention it. yes i am
Generally speaking the approach you would actually use would be to use UnProject to get a ray, and then do a ray intersect against the geometry of interest. If you really, really want to use Z, you could do a fast Z-pass to a separate render target and read it back the next frame to get the Z value you want. You'll always be a frame off, but it shouldn't actually matter. You can even set the viewport on that render target to just be a couple pixels large, around the mouse cursor.
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
wel its not like i want to use Z. more like i didnt know any other way. could you maybe elaborate more on the generaly accepteble method u mentioned or just point me to a nice article/tutorial :P

Thnx!
On modern machines the ReadPixels call shouldn't stall (that much! It will stall some, but it shouldn't be noticable) if you are only reading exactly the pixel you need. If you are instead reading the ENTIRE buffer into memory every frame and then back projecting it, that is an absolutely terrible idea. The ideal way, as was already said was doing glUnproject to get a ray value (by doing a random arbitary non-zero value for Z) and then using that ray to do intersection tests, but keeping your exact code the same but changing the ReadPixels call to only read 1-4 pixels at a time should be more than real-time.

Alternately, there is the option of the selection buffer and opengl picking, if you want to do that It might give you the best accuracy/ease tradeoff you can possibly get for the type of thing you are trying to do.
Is your game area a flat plane? Cause you know, the math for that case is laughably trivial and you wouldn't really have to jump through any hoops. All you need in that case is a simple ray-plane intersection, which is easy and well documented.

Thing is, it just dawned on me what you're doing -- you're doing a read pixels to find out what Z to pass to UnProject, and then using the resulting coordinates (probably world XZ) to figure out where you are on a grid. You don't need anything clever for that at all. Here's a version I have lying around that's hard coded to the XZ plane at the origin:
		Math::Vector cameraPos = m_camera.GetPosition();		double coordX, coordY, coordZ;		gluUnProject(mousePos.x, viewport[3] - mousePos.y, 0.5, modelview, projection, viewport, &coordX, &coordY, &coordZ);		//figure out click pos at board height (ie 0)		Math::Vector coord((float) coordX, (float) coordY, (float) coordZ);		Math::Vector ray = (cameraPos - coord).Normalize();		float dist = cameraPos.y / ray.y; //in the general case, this is actually a ray projection		//compute board position		Math::Vector absPos = cameraPos - (dist * ray);
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
thnx but unfortenetly its a heightmapped terrain that can vary wildly ;/

i copied my current code from some random tutorial, ported it to java and intergrated it into my engine. heres my method for getting the Z value folowd by the rest.

public static float getZDepth(int x, int y){  tmpFloat.clear();//tmpFloat is a ByteBuffer  GL11.glReadPixels(x, y, 1, 1, GL11.GL_DEPTH_COMPONENT, GL11.GL_FLOAT, tmpFloat);  return ( (float) (tmpFloat.getFloat(0)));}//and heres the rest of itpublic static Vector3 getCursor3D(Vector2 coords){  return unProject(coords.x,coords.y,getZDepth((int)coords.x,  (int)coords.y));  }public static Vector3 unProject(float x, float y, float z){  GLU.gluUnProject( x, y, z, getModelviewMatrix(), getProjectionMatrix(), getViewport(), tmpResult);  return new Vector3(tmpResult.get(0),tmpResult.get(1),tmpResult.get(2));}public static IntBuffer getViewport(){  bufferViewport.clear();  GL11.glGetInteger(GL11.GL_VIEWPORT, bufferViewport);  return bufferViewport;}//projection and modelview matrixes is allready calculated elsewhere since my engine is shader basedpublic static FloatBuffer getModelviewMatrix(){  return viewMatrix.toFloatBuffer();}public static FloatBuffer getProjectionMatrix(){  return projectionMatrix.toFloatBuffer();}


so to me it doesnt seem like im reading the entire buffer (if i understand the parameters correctly).

[Edited by - EternityZA on October 14, 2009 2:50:08 PM]
It can still stall though. I'm not sure exactly how this is handled, but it may interfere with driver-level buffering of frames. Generally the driver will allow your program to continue three frames ahead, buffering the previous frames. When you read back the depth, perhaps it must actually process the current frame and read it back before letting you continue with your draw-calls for the next frame (which doesn't necessarily need to stall enough to be noticeable, but it might).
Ray/heightmap collision detection isn't that hard, for example you could do it iteratively, moving closer and closer from the startpoint to the endpoint of the line, until you are below the terrain (divide the interval in 2 each step for speed). This will most likely be the best and fastest solution.
Another solution is to do what Promit suggested with rendering only Z to a separate render target (keep an array of these and cycle through them to read back the Z a couple of frames behind, if it still stalls).
Quote:Original post by Erik Rufelt
...Ray/heightmap collision detection isn't that hard. for example you could do it iteratively, moving closer and closer from the startpoint to the endpoint of the line, until you are below the terrain (divide the interval in 2 each step for speed...


Thnx! i think il start from here.

This topic is closed to new replies.

Advertisement