[SOLVED] Problems with raycasting

Discuss any questions about BEPUphysics or problems encountered.
Post Reply
Arcades
Posts: 17
Joined: Wed May 18, 2011 5:01 pm

[SOLVED] Problems with raycasting

Post by Arcades »

Hi again,
I have a problem with some ray casts: I have a mesh which is a piece of a dungeon with stairs, corridors, platforms and so on. This mesh is a StaticMesh.
On this mesh I have to create a grid which, in the future, will be the grid I have to use for the AI, basically a grid of valid points for an A* implementation. Every point of the grid must be tested with a ray cast: if I hit then there is a valid point, which means a valid passage. Then I test every point with it's neighbours and I'll have a grid of connections. In the end I'll have a bidimensional array of points which tell me I can stay in a point of the grind and how I can move further.

Since I have this StaticMesh I just used the raycast function from there, taking the points starting from the BoundingBox, like this:

Code: Select all

StaticMesh Sector; // Got from somewhere.
Space Spazio; // Got from somewhere,
float startHeight = Sector.BoundingBox.Max.Y + m_fRayCastHeight;
Vector3 position = new Vector3(0, startHeight, 0);
Vector3 direction = new Vector3(0, -1, 0);
Ray raggio = new Ray(position, direction);
RayHit colpito = new RayHit();
RayCastResult risultato;
for (uint i = 0; i < Cols; i++)
{
    position.X = Sector.BoundingBox.Min.X + i * Step;
    for (uint j = 0; j < Rows; j++)
    {
        position.Z = Sector.BoundingBox.Min.Z + j * Step;
        raggio.Position = position;

        Node iter;
        iter.connections = (byte)(Sector.RayCast(raggio, Single.MaxValue, out colpito) ? 1 : 0);
        iter.height = colpito.Location.Y;

        if (hit)
            add a debug sphere on colpito.Location
        }
    }
}
This code work perfectly. The matter is the scene is composed also of some placeables and this code will ignore them hitting the mesh under those placeables and adding unvalid points
So I had to pass to Space.raycast. I added to the scene a sample static box and I used instead this code:

Code: Select all

StaticMesh Sector; // Got from somewhere.
Space Spazio; // Got from somewhere,
float startHeight = Sector.BoundingBox.Max.Y + m_fRayCastHeight;
Vector3 position = new Vector3(0, startHeight, 0);
Vector3 direction = new Vector3(0, -1, 0);
Ray raggio = new Ray(position, direction);
RayHit colpito = new RayHit();
RayCastResult risultato;
for (uint i = 0; i < Cols; i++)
{
    position.X = Sector.BoundingBox.Min.X + i * Step;
    for (uint j = 0; j < Rows; j++)
    {
        position.Z = Sector.BoundingBox.Min.Z + j * Step;
        raggio.Position = position;

        Node iter;
        iter.connections = (byte)(Sector.RayCast(raggio, Single.MaxValue, out risultato) ? 1 : 0);
        iter.height = risultato.HitData.Location.Y;

        if (hit)
            add a debug sphere on risultato.HitData.Location
        }
    }
}
Which seems to work sometimes. The spheres I used as debug are very few, only on a part of my mesh. Instead, on the box I used for debug there are correctly as many sphere as they should be. Look at the pictures I attached. EDIT: sorry, it seems the first one is at the bottom and the last one at the top, look at the file names please.
On the first one (eh_grid.png) I used StaticMesh.rayCast and the grid is fully created (the black lines represent the connections) but as you can see below the green box there are also some spheres which shouldn't be there (instead they should be on top of that box).
On the second picture (eh_grid2.png) I used Space.rayCast which correctly stop the ray on top of the box but may others rays fails.
If I enlarge the green box ad infinitum (eh_grid3.png) I have all my raycasts in the correct positions but on top of the green box (picture 3).

This means the raycasts seems to be in the correct place but if I use Space.rayCast many of them fails touching the StaticMesh but not the Box.
Can you help me understand why?
Do I mess up with the positions or what?

Consider also both the mesh and the box are not at the world origin, so I suppose I used the right translations when creating the Ray class.
Attachments
Method 2 with a huge box.
Method 2 with a huge box.
eh_grid3.png (131.74 KiB) Viewed 6515 times
Method 2: Space.RayCast
Method 2: Space.RayCast
eh_grid_2.png (288.68 KiB) Viewed 6515 times
Method 1: StaticMesh.rayCast
Method 1: StaticMesh.rayCast
eh_grid.png (171.33 KiB) Viewed 6515 times
Last edited by Arcades on Tue Oct 11, 2011 4:27 pm, edited 1 time in total.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Problems with raycasting

Post by Norbo »

Both pieces of sample code appear to be using StaticMesh.RayCast (though the latter's parameters are off), which seems to be different than what the pictures imply. Assuming that was just a typo in the post and that the latter one is using the space.RayCast, that overload should properly return the first impact of any object in the scene.

I went ahead and made a quick version of it in the BEPUphysicsDemos using this modified StaticMeshDemo:

Code: Select all

//Load in mesh data and create the group.
            Vector3[] staticTriangleVertices;
            int[] staticTriangleIndices;

            var playgroundModel = game.Content.Load<Model>("playground");
            //This load method wraps the TriangleMesh.GetVerticesAndIndicesFromModel method 
            //to output vertices of type StaticTriangleGroupVertex instead of TriangleMeshVertex or simply Vector3.
            TriangleMesh.GetVerticesAndIndicesFromModel(playgroundModel, out staticTriangleVertices, out staticTriangleIndices);
            var staticMesh = new StaticMesh(staticTriangleVertices, staticTriangleIndices, new AffineTransform(Matrix3X3.CreateFromAxisAngle(Vector3.Up, MathHelper.Pi), new Vector3(0, -10, 0)));
            staticMesh.Sidedness = TriangleSidedness.Counterclockwise;

            Space.Add(staticMesh);
            game.ModelDrawer.Add(staticMesh);


            //Dump some boxes on top of it for fun.
            int numColumns = 8;
            int numRows = 8;
            int numHigh = 1;
            float separation = 40;
            for (int i = 0; i < numRows; i++)
                for (int j = 0; j < numColumns; j++)
                    for (int k = 0; k < numHigh; k++)
                    {
                        var toAdd = new Box(
                            new Vector3(
                            separation * i - numRows * separation / 2,
                            60f + k * separation,
                            separation * j - numColumns * separation / 2),
                            15, 1, 15);

                        Space.Add(toAdd);
                    }

            numRows = 100;
            numColumns = 100;
            Vector3 min = staticMesh.BoundingBox.Min;
            Vector3 step = (staticMesh.BoundingBox.Max - min);
            step.X /= numRows + 1;
            step.Z /= numColumns + 1;

            Ray ray;
            ray.Direction = new Vector3(0, -1, 0);
            for (int i = 1; i <= numRows; i++)
            {
                for (int j = 1; j <= numColumns; j++)
                {
                    ray.Position = new Vector3(min.X + i * step.X, 80, min.Z + j * step.Z);
                    RayCastResult result;
                    if (Space.RayCast(ray, out result))
                    {
                        var toAdd = new Sphere(result.HitData.Location, .5f);
                        toAdd.CollisionInformation.CollisionRules.Personal = CollisionRule.NoBroadPhase;
                        Space.Add(toAdd);
                    }
                }
            }

            DisplaySphere.NumSides = 8;
            game.Camera.Position = new Vector3(0, 10, 40);
Which results in this:
raycasts.jpg
raycasts.jpg (321.18 KiB) Viewed 6512 times
Is that what you're looking for? If so, I don't see any significant logical differences in your approach at a glance. There might be some other hiding issues- maybe a mesh floating up somewhere, blocking rays. Making a little demo like the above in the BEPUphysicsDemos might help isolate the problem. If you're able to reproduce it in the demos, I could debug/run it to take a closer look.
Arcades
Posts: 17
Joined: Wed May 18, 2011 5:01 pm

Re: Problems with raycasting

Post by Arcades »

Yes, that was a typo and yes: that is what I wish to achieve.
I'll check everything on the scene, thanks for your reply.
Arcades
Posts: 17
Joined: Wed May 18, 2011 5:01 pm

Re: Problems with raycasting

Post by Arcades »

I discovered that if I remove the box and leave only the StaticMesh (the red mesh you can see in the pictures) the casts on the StaticMesh generate a correct grid (like on picture eh_grid.png).
At first I thought I created a box too large but no matter how I resize and/or move the box the raycasts fails, also in the area you can see in picture eh_grid2 (on the left) a small grid is created leaving the rest of the mesh empty. I don't get it: if the box block the rays then moving it should create a different grid on the StaticMesh, instead the grid created is always the same (the rays on the box, anyway, cast correctly. The spheres on the box are placed correctly).
Any idea how to fix it?

EDIT: I've seen in debug that the ray cast fail with no redemption: starting from a specific point of the grid the ray cast fail if I add a box or a sphere in the scene (added before begin the ray casts). With "fail" I mean the Space.rayCast return false and the outval have hitData zero and hitObject null.
Maybe some mess with normals or vector data? If so why when the Space is filled with only the StaticMesh the raycast work?
Arcades
Posts: 17
Joined: Wed May 18, 2011 5:01 pm

Re: Problems with raycasting

Post by Arcades »

In the end I found a solution: if I don't translate the StaticMesh everything works fine.
Actually it's not a big deal since I need all of this for generate a grid so after it's generated I can translate the mesh and the grid with no issues however I couldn't reproduce this error on the StaticMeshDemo (which does not have my broken behavior after I loaded my mesh on it).
In the future I may get the request to translate the meshes so I'd like to understand what it's wrong and try to fix it. Any ideas?
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Problems with raycasting

Post by Norbo »

I couldn't reproduce this error on the StaticMeshDemo (which does not have my broken behavior after I loaded my mesh on it).
In the future I may get the request to translate the meshes so I'd like to understand what it's wrong and try to fix it. Any ideas?
Could it be related to the loading procedure in some way? But if the vertex/index extraction or its usage has an error, then it could conceivably cause some of what you see under some circumstances.

The key hint we have now is that it doesn't happen in the demo. There is something different between the two. Steadily building the demo closer and closer to your original application's mesh handling and testing at each stage to see if the problem has started happening would be one option.
Arcades
Posts: 17
Joined: Wed May 18, 2011 5:01 pm

Re: Problems with raycasting

Post by Arcades »

I'm very grateful for your help. How do you find the time for develop and also answer in the forum?
Anyway I found the problem, which can be reproduced in the demo: I do set the AffineTranform after adding the StaticMesh to the Space so that WorldMatrix is not calculated.
Of course it's a mine mistake, it's nonsense to translate something static after it's placed. If I would translate it then I should create a kinematic object instead a static.
Thanks again for your time.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Problems with raycasting

Post by Norbo »

How do you find the time for develop and also answer in the forum?
Time machine!
Anyway I found the problem, which can be reproduced in the demo: I do set the AffineTranform after adding the StaticMesh to the Space so that WorldMatrix is not calculated.
Of course it's a mine mistake, it's nonsense to translate something static after it's placed. If I would translate it then I should create a kinematic object instead a static.
Setting the WorldTransform of the StaticMesh should actually be a valid operation. It's not something you'd want to do all the time and directly supplying the transform to the constructor is better, but it is technically allowed.

In the demos, the BEPUphysicsDrawer computes the vertices of a mesh in world space, baking in the existing transform. When the mesh's transform is changed later, the graphics do not update, but the physics do. This makes it look desynchronized. However, if the game.ModelDrawer.Add(staticMesh) is moved to a point in the code after the mesh has been transformed, everything will be properly synchronized and in the correct location.
Arcades
Posts: 17
Joined: Wed May 18, 2011 5:01 pm

Re: Problems with raycasting

Post by Arcades »

I'd like to rent your time machine. Is it possible? No matter the price!

Anyway: you are telling me that I can translate a static object?
Aren't static object static by definition? I thought I made both a conceptual and a code mistake by translating my mesh after adding it in the Space.

I couldn't reproduce the same behavior with the playground model, actually. If I translate that mesh the raycasts still work. Only my mesh seems to suffer the translation sickness :(

I solved, anyway. Thank you.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: [SOLVED] Problems with raycasting

Post by Norbo »

I'd like to rent your time machine. Is it possible? No matter the price!
Sorry, paradoxes and all that :(
Anyway: you are telling me that I can translate a static object?
Aren't static object static by definition? I thought I made both a conceptual and a code mistake by translating my mesh after adding it in the Space.
You can indeed translate a StaticMesh. The difference between a static object and an entity is that an entity is built from the ground up to support motion efficiently. StaticMesh and the other static objects are optimized to be stationary, but they are capable of teleportation. Because of the costs associated with refitting the acceleration structures in a StaticMesh after retransformations, it's not something you want to do routinely at runtime, and certainly not something you'd use to simulate motion in real time.
Post Reply