Picking?

Jan 28, 2009 at 10:53 PM
First off, thank you for Xen!  Great work!

I hate to bother you with my silly questions, so I appologize in advance...

Given your Tutorial 16 (Instancing and Partitioning), what is the best way to implement picking with Xen?  I have already made a cursor, and have it moving around the screen.  Now I want to know which object the user clicks on.  Do I need to take the code from XNA Viewport.Unproject() and put that in my project, and keep my own list of objects (beyond what is in the partitioning tree) and try to figure it out, or is there an easy way to do this with a part of Xen that I haven't seen yet?

Thanks again for the library and any help you can give.

~astro.

Coordinator
Jan 28, 2009 at 11:08 PM

Hi.

Picking isn't directly supported in xen, I feel it's something that can get spectacuarly complex and is very game specific. The partition classes are primarily intented to boost culling performance.

However, there are classes and methods that can help.
You can use DrawState to project from the screen into the scene (state.ProjectFromScreen).

Once you have that ray, things are more complex. The partition class does have the Query method, however there are only two implementations, the ICullPrimitive implementation, and a bounding box implementation (which internally just uses a ICullPrimitive class). So to implement ray picking, you'd need to make a class that wraps a Ray and implements ICullPrimitive to perform Ray/Box intersection tests (you'd either be returning Intersects or Disjoint - as it's Ray->Box not Box->Ray, so returning 'Contains' would mean the ray entirely contains the box, which is impossible :-).

Run this through a Query and you will get approximately the objects on the ray (the objects themselves will not be individually ray tested, you will need to implement this yourself).

Hope that helps / make sense. :-)

Jan 28, 2009 at 11:32 PM
Yes, that helps, thanks!  And, Wow! You are fast.

I hadn't seen the state.ProjectFromScreen method, so that helps a bit.  You also got me thinking because of the "game specific" comment.  Turns out that the objects that I am trying to pick all lie on a plane, so it should be easy for me to use the bounding box implementation of Query using a smal box around the point on the plane where the cursor ray intersects.   In fact, I could probably just figure it out without Query since my objects are all regularly placed (as in tiles on a board, although they are hexagons rather than squares).  In the end I was hoping for a more general purpose method of scene object picking, and I think you have set me well on my way - RayCullPrimitive.

Thanks, again.

Jan 29, 2009 at 12:46 AM
Edited Jan 29, 2009 at 1:15 AM
Sorry to bother you again...

I put this in my Draw() method:
Vector2 cp = _cursorElm.Position;
Vector3 cproj;
state.ProjectFromScreen( ref cp, 0f, out cproj );

...and ended up with a' Object reference not set to an instance of an object. (NullReferenceException)' on:

CameraControl.cs line: 4109
DrawTarget.GetWidthHeightAsVector(out drawTargetSize, ref index);

**** EDIT ****
I think it was an order of operation problem.  I was calling that method prior to calling drawToScreen.Draw(state).  When I moved that call into an IDraw object that was added to the drawToScreen object, I no longer got the error.  I think that I just need to get clear in my head how these objects tie together and how they should work together.  Again, sorry to bother you and thanks for all your efforts.


Coordinator
Jan 29, 2009 at 3:19 AM

That would have been because ProjectFromScreen requires a camera to be active, and you usually need to be drawing to something for there to be a camera.

I'll put in a more helpful exception.
In general, you can't do much in the root Draw() method of the application, as there isn't any context for what is going on