FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Very basic Ray Picking

 
Post new topic   Reply to topic     Forum Index -> Yage
View previous topic :: View next topic  
Author Message
That Guy



Joined: 01 Jan 2011
Posts: 5
Location: Edwards, CO

PostPosted: Mon Jan 03, 2011 12:12 pm    Post subject: Very basic Ray Picking Reply with quote

I have been working on ray picking as part of my getting to know yage. I have discovered there are about a million ways to do it. Finally I found what looks like the simplest way, which is below.
Code:
Vec3f getPickRayDir( float width, float height, Vec2f pos ) {
    Render.graphics.bindCamera( this );
   
    int[4] viewport;
    double[16] modelMatrix, projMatrix;
   
    glGetIntegerv( GL_VIEWPORT, cast(int*)viewport ); // viewport will be (0,0 width,height)
    glGetDoublev( GL_MODELVIEW_MATRIX, cast(double*)modelMatrix );
    glGetDoublev( GL_PROJECTION_MATRIX, cast(double*)projMatrix );
    float winX = pos.x;
    float winY = viewport[3] - pos.y;
    float winZ = 0.0f;
    //glReadPixels( cast(int)winX, cast(int)winY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ );
    double p1x, p1y, p1z, p2x, p2y, p2z;
    gluUnProject( winX, winY, 0.0f,
                  cast(double*)modelMatrix, cast(double*)projMatrix, cast(int*)viewport,
                  &p1x, &p1y, &p1z );
    gluUnProject( winX, winY, 1.0f,
                  cast(double*)modelMatrix, cast(double*)projMatrix, cast(int*)viewport,
                  &p2x, &p2y, &p2z );
    return (Vec3f(p2x, p2y, p2z)-Vec3f(p1x, p1y, p1z)).normalize();
}

There are a few things which I think need some discussion. As you can see, it is presently quite inefficient given the three calls to glGet. these are needed as the two matrices are not saved anywhere (that I have been able to find). This leads to needing the call to bindCamera. These should be pretty easy to fix, just by someone who actually knows the code.

I also have very basic ray/sphere intersection detection.
Code:
   bool testIntersection( Vec3f rayOrg, Vec3f rayDir ) {
        if( !this.visible || this.getRadius() <= 0 ) {
            return false;
        }
        Vec3f diff = rayOrg - this.getPosition();
        auto a0 = diff.dot(diff) - this.getRadius()*this.getRadius();
        if ( a0 <= 0.0 ) // rayOrg is inside the sphere
            return true;
        // else: rayOrg is outside the sphere
        auto a1 = rayDir.dot(diff);
        if ( a1 >= 0.0 ) {
            return false;
        }
        // quadratic has a real root if discriminant is nonnegative
        return a1*a1 >= a0;
   }
It looks a bit like magic, but seems to work well.
This then leads into a discussion of the best/correct way to walk the scene. Also, how yage should be doing collision detection in general, eg. should it be built into Node (VisibleNode right now) or somehow delegated off to other classes.
The main point is that I now have a demo with 2 ship where you can click on then to make it a little bigger.

Note: I have left out getNodesAtCoordinate() and doPick() which are both fairly boring.

Dan
Back to top
View user's profile Send private message
JoeCoder



Joined: 29 Oct 2005
Posts: 294

PostPosted: Wed Jan 05, 2011 9:03 pm    Post subject: Reply with quote

This is great! Yage has definitely been needing this. scene/camera.d already has some empty functions where I had been planning it, getNodesAtCoordinate(), and getWorldCoordinate().

Quote:
As you can see, it is presently quite inefficient given the three calls to glGet. these are needed as the two matrices are not saved anywhere (that I have been able to find). This leads to needing the call to bindCamera.

Not only that, but the scene graph code (including camera position) runs in a different thread than the rendering code. It's not safe to make gl_* calls from the scene thread.

If you look in the calcWorld() function at the bottom of scene/camera.d, you can see where I'm calculating these matrices without using OpenGL. Like other nodes, changing a camera's position toggles its worldDirty flag, and then when any absolute positioning is requested, calcWorld is called lazily to update the cached absolute values. CameraNode overrides Node's calcWorld to also update it's view frustum.

I don't have glGetViewport implemented, but you can take a look at mesa's implementation of it. That's where I learned the math needed to build the project and modelview matrices.

Finally, if you want to agree to the rules for contributing, I'll give you svn write access.
Back to top
View user's profile Send private message
That Guy



Joined: 01 Jan 2011
Posts: 5
Location: Edwards, CO

PostPosted: Thu Jan 06, 2011 12:50 am    Post subject: Reply with quote

Sure, I can agree with the rules for contributing.

I saw both getNodesAtCoordinate() and getWorldCoordinate(). I used getNodesAtCoordinate() but dropped getWorldCoordinate() as it is not needed to calculate the needed ray. If there is a use case for getWorldCoordinate() I can add it back in when I rework doPick().

I did take a look at calcWorld() but did not use that for the inital code because replacing the glGet calls with the calculations results in doPick() returning a bad ray. Why it is bad, I don't know, tho I did not really look into it.

I will take a look at mesa, especially now that I know that is where the matrix calculations came from.

And for some off-topic stuff...
I have also started to take a look at Input.d. Right now, what threads are running? Why does SDL input polling need to be in the render thread? Is this a SDL issue or just the way we are using it.

I think you mentioned that you are working on the GUI. What is the status of this work? Is it the code I see in trunk? If this is the case, and you have not done any work on controls, I would like to offer to do this. I have wanted to create a GUI system for a while now.

I ask about both of these because I was attempting to implement a mouse pointer for use in the picking demo and was having trouble based on the way messages are passed to parent Surfaces. When I move the mouse over a child Surface, like the one in Demo2, the mouse no longer updates because the main Surface, which owns the mouse, no longer gets mouse events.
Back to top
View user's profile Send private message
That Guy



Joined: 01 Jan 2011
Posts: 5
Location: Edwards, CO

PostPosted: Thu Jan 06, 2011 2:42 am    Post subject: calculated model matrix Reply with quote

Edit: this post has been removed because it is no longer needed.
Back to top
View user's profile Send private message
JoeCoder



Joined: 29 Oct 2005
Posts: 294

PostPosted: Thu Jan 06, 2011 11:10 pm    Post subject: Reply with quote

You should now have commit access using your dsource username and password with svn.

Quote:
but dropped getWorldCoordinate() as it is not needed to calculate the needed ray. If there is a use case for getWorldCoordinate() I can add it back in when I rework doPick().


I originally planned for getWorldCoordinate() to return the 3d position and getNodesAtCoordinate() would use that to find nearby nodes. Maybe you're doing the same thing with different function names?

Quote:
I have also started to take a look at Input.d. Right now, what threads are running? Why does SDL input polling need to be in the render thread? Is this a SDL issue or just the way we are using it.


Rendering occurs in the main thread. You can see it in a loop in main. Each scene also has its own thread that updates the positions of every node 60 times a second. Scenes have their own start() / pause() functions. Finally, the sound system runs in its own thread as well.

SDL requires input polling to be in the same thread as the render thread. I don't know why, but it breaks if I change it and the SDL docs also list this as a requirement. I hope to eventually drop SDL.

Quote:
I think you mentioned that you are working on the GUI. What is the status of this work? Is it the code I see in trunk? If this is the case, and you have not done any work on controls, I would like to offer to do this. I have wanted to create a GUI system for a while now.


This is great. I had been hoping to work out a few more bugs before handing this off, but you're welcome to have a go at it if you want. If you look at gui/controls, it is full of items that have been spec'd out and are ready to implement. Resizer would be a good place to start, since it will be needed for scrollbars. Keep me up-to-date with any bugs you run into. Chances are I'll know a quick way to fix them that can save you a lot of time.

Quote:
I ask about both of these because I was attempting to implement a mouse pointer for use in the picking demo and was having trouble based on the way messages are passed to parent Surfaces. When I move the mouse over a child Surface, like the one in Demo2, the mouse no longer updates because the main Surface, which owns the mouse, no longer gets mouse events.


This is a recent regression. If it's fixed you should be able to click on the box in demo2 and type text. I'm not sure what's causing it.

You can also take a look at a more complex ui in tests/integration/main.d. I had planned to use the controls tab to demo and test all of the controls once they're implemented.
Back to top
View user's profile Send private message
bioinfornatics



Joined: 22 Jun 2010
Posts: 90

PostPosted: Wed Jan 12, 2011 11:48 pm    Post subject: Reply with quote

you can replace cast(double*)projMatrix by projMatrix.ptr
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic     Forum Index -> Yage All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group