Ray testing

Mar 6, 2009 at 2:14 PM
Edited Mar 6, 2009 at 2:16 PM
First of all, thanks for this excellent library. I'm thinking of building a good set of tutorials when I have a good know-how of all the functions for JigLibX, so people do not have to post countless forum topics to ask very basic questions (Like mine). For now, I actually have a small question about the ray testing in JigLibX.

I have the following code:

                //Shoot a ray to the second box
                Vector3 ray = movingBox.PhysicsBody.Position * new Vector3(0f, 1f, 0f);
                float frac;
                CollisionSkin skin;
                Vector3 pos, normal;

                ImmovableSkinPredicate pred = new ImmovableSkinPredicate();                

                world.CollisionSystem.SegmentIntersect(out frac, out skin, out pos, out normal,
                    new Segment(ray, Vector3.Down * 1000000000.0f), pred);

                if (skin != null && (skin.Owner != null))
                {
                    skin.Owner.Immovable = true;
                }

The ray fires, and I get a good result when I just take the possition of the moving box (And thus hitting the moving box because its fired from its origin). But when I align the ray with the bottom side of the box, and then fire the ray, I do not get any hits back. Any thoughts about why this happens?

Also, is there a quick way of visualizing the ray with a line from the debugDrawer?

The two boxes (movingBox and staticBox) are above each other when the ray is tested.
Mar 6, 2009 at 2:21 PM
Edited Mar 6, 2009 at 2:22 PM
Nevermind, off course the Vector3 ray = movingBox.PhysicsBody.Position * new Vector3(0f, 1f, 0f); should be Vector3 ray = movingBox.PhysicsBody.Position + new Vector3(0f, -1f, 0f);

But one question still remains, is there a quick way of visualizing a ray?
Mar 7, 2009 at 7:52 AM
There may be a way built into JigLibX using the DebugDrawer that i've heard people used but never touched myself.

I always use...

http://www.xnawiki.com/index.php?title=Rendering_Rays

Really useful class, even draws an arrow head on the direction the ray is pointing. There are a few other good ones on that site for rendering bounding boxes and spheres for example.


Mar 9, 2009 at 5:45 PM

Seriously, where do you find the ImmovableSkinPredicate class?? I have a hard time implementing your ray-code. And is this the best way to have rays?

I wanted to try your code because I want to make fps-aim and shoot boxes. Viewport.Unproject dosn't work because the models don't have a boundingsphere. Is it easier to add a boundingsphere or box to the models and use Unproject instead of collisionsystem.segmentintersect?

Thanks!
Carl
Mar 11, 2009 at 4:10 PM
Edited Mar 11, 2009 at 4:14 PM
The ImmovableSkinPredicate  is at the top of the jigLibGame game file. It acts like a filter for the collisions. I've set it to always return true, but the sample in the game uses it to filter out immovable and invalid items.

The original code is below: (And filters on null and immovable)
    #region ImmovableSkinPredicate
class ImmovableSkinPredicate : CollisionSkinPredicate1
{
public override bool ConsiderSkin(CollisionSkin skin0)
{
if (skin0.Owner != null && !skin0.Owner.Immovable)
return true;
else return false;
}
}
#endregion
I've used it like this because I wanted to test against a non-moving block:
    #region ImmovableSkinPredicate
class ImmovableSkinPredicate : CollisionSkinPredicate1
{
public override bool ConsiderSkin(CollisionSkin skin0)
{
if (skin0.Owner != null)
return true;
else return false;
}
}
#endregion

I do not know if this is the best way to do ray testing as I'm pretty new with this too.


Mar 13, 2009 at 11:38 AM
aha, in the game code ... thanks!

I managed to do my fps-shooting with the following code:

                Vector3 near = ((Game1)Game).GetGraphicsDevice().Viewport.Unproject(new Vector3(ms.X, ms.Y, 0f), Game1.camera.Projection, Game1.camera.View, Matrix.CreateTranslation(0f, 0f, 0f));
                Vector3 far = ((Game1)Game).GetGraphicsDevice().Viewport.Unproject(new Vector3(ms.X, ms.Y, 1f), Game1.camera.Projection, Game1.camera.View, Matrix.CreateTranslation(0f, 0f, 0f));
                Vector3 delta = far - near;
                delta.Normalize();
                Ray pick = new Ray(near, delta);
                foreach (IGameComponent comp in Game.Components)
                {
                    if (comp is BoxObject)
                    {
                        BoxObject bo = (BoxObject)comp;
                        BoundingBox bs = bo.PhysicsSkin.WorldBoundingBox;
                        if (bs != null)
                        {
                            Nullable<float> r = pick.Intersects(bs);
                            if (r.HasValue && r < 100f)
                            {
                                bo.PhysicsBody.ApplyBodyWorldImpulse(new Vector3(1000f), Vector3.Up);
                            }
                        }
                        else
                            Game1.SetDebugText("n,"); // Never happens
                    }
                }

This is an ordinary ray checking against the bounding box (that I found in boxobject.physcisskin.worldboundingbox) and if you click on a box it will fly away by the force (applybodyworldimpulse(new vector(1000f), vector3.up)).

Good luck!

Carl

Mar 13, 2009 at 1:12 PM
You do realise the implications of using WorldBoundingBox - it gives you an AxisAligned BoundingBox which means that should the box be rotated it's not particularily accurate. You might want to look into using SegmentIntersect which checks a line segment (effectively very similar to a ray) against the actual collision skin of the box regardless of it's angle...here is a snippet...

boxObject.CollisionSkin.SegmentIntersect(out distToBox, out pos, out normal, new Segment(sourcePosition, targetPosition - sourcePosition));

Using that line you get the distToBox which is distance to the box. IIRC it returns float.MaxValue if there is never a collision else it will return the distance to the collison.
Mar 16, 2009 at 10:32 PM
Still have one question, what does the frac var return in the SegmentIntersect function? Probally it is the fraction of something, but I just can't figure out of what.