Jump to content
  • Advertisement
Sign in to follow this  
EternityZA

my gluUnProject calls is way to costly

This topic is 3316 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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!

Share this post


Link to post
Share on other sites
Advertisement
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.

Share this post


Link to post
Share on other sites
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!

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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);



Share this post


Link to post
Share on other sites
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 it

public 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 based
public 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]

Share this post


Link to post
Share on other sites
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).

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!