Doing a 'sphere cast'

Post Reply
User avatar
nikki
Posts: 22
Joined: Sat Jun 14, 2008 3:38 pm
Location: Doha, Qatar.
Contact:

Doing a 'sphere cast'

Post by nikki »

Hey guys!

In my game, there are two 'dimensions' or 'parallel worlds' (I've mentioned in a previous post). The player can switch from one dimension to another, and the world is slightly different in either dimension (there's a wall here, but it isn't there in the other one etc.). I get this to work using collision flags. That way, things only collide if they share a common dimension. The player switches dimension by having his rigidbody removed and then re-added with the new flags.

Now, the problem I face is what to do if the player tries to switch to the other dimension at a point where there's a wall in the other dimension (if he switches he'll intersect). What I'm thinking of doing is a spherecast (player is sphere-shaped) that checks for objects having the other flag at the player's position, and switching only if it's free. I'm not sure how to do a sphere-vs-world cast though, so I just tried with a convex. This cast works only if the convex actually intersects a trimesh face (level geometry is trimesh), and isn't 'inside' it. Is there anyway to instead detect when an object is 'inside' another?

This is what I'm doing, but as I said, it works only for face intersections.

Code: Select all

btVector3 pos1 = mBody->getWorldTransform().getOrigin();
btVector3 pos2 = mBody->getWorldTransform().getOrigin() + btVector3(0,0.1,0); //We need /some/ displacement it seems.
btQuaternion rot = mBody->getWorldTransform().getRotation();
btTransform trans1(rot, pos1);
btTransform trans2(rot, pos2);
btConvexShape *shape = BtOgre::StaticMeshToShapeConverter(mEntity).createConvex(); //Creates convex from graphic entity.

struct TempCallback : public btDynamicsWorld::ConvexResultCallback
{
    std::vector<btCollisionObject*> mHits;

    btScalar addSingleResult(btDynamicsWorld::LocalConvexResult& convexResult, bool normalInWorldSpace)
    {
        mHits.push_back(convexResult.m_hitCollisionObject);
        NGF::GameObject *obj = NGF::Bullet::fromBulletObject(convexResult.m_hitCollisionObject);
        LOG(obj->getFlags());
        return convexResult.m_hitFraction;
    }
} res;

GlbVar.phyWorld->convexSweepTest(shape, trans1, trans2, res);

for (std::vector<btCollisionObject*>::iterator iter = res.mHits.begin(); iter != res.mHits.end(); ++iter)
{
    btCollisionObject *currHit = (*iter);

    if (currHit == mBody)
        continue;

    if (!(currHit->getCollisionFlags() & mDimensions))
        /* can't switch */
}
Well, yeah I could've done the tests directly i nthe 'addSingleResult' instead of adding to a vector and doing it again, but that isn't the issue now.

My main questions are: How do I do a sphere-vs-world cast? How to ensure that it doesn't check just for face intersection, but also whether the object is inside a trimesh?
pico
Posts: 229
Joined: Sun Sep 30, 2007 7:58 am

Re: Doing a 'sphere cast'

Post by pico »

Hi,

only the basic shapes like boxes and spheres are considered to be 'volumes'. Trimeshes are no volumes and so you cant detect a hit when you already 'in' them (because there is no 'in'). Maybe convex meshes would do that trick, but im not sure.
DannyChapman
Posts: 84
Joined: Sun Jan 07, 2007 4:29 pm
Location: Oxford, England
Contact:

Re: Doing a 'sphere cast'

Post by DannyChapman »

If you don't detect overlap between the sphere and the mesh, you want to check if that's because the sphere centre is completely inside the mesh. If your mesh is closed, then you can tell if a point (i.e. the sphere centre) is inside it by doing a ray test in some arbitrary direction. If the number of intersections with the mesh is odd, then the point is inside the mesh.

However, you do need to be careful when the segment just skims the mesh, because the intersections functions will not be exact. You can handle most cases by using more than one ray test, and combining the results.
User avatar
nikki
Posts: 22
Joined: Sat Jun 14, 2008 3:38 pm
Location: Doha, Qatar.
Contact:

Re: Doing a 'sphere cast'

Post by nikki »

So what's the right way to handle this situation? The player is sphere-shaped, and I basically have to check whether there are any objects with the other collision flag occupying the same space as the player (mostly these will be trimeshes, but 'proper closed' trimeshes).

And also, how exactly do you do a sphere cast?
User avatar
nikki
Posts: 22
Joined: Sat Jun 14, 2008 3:38 pm
Location: Doha, Qatar.
Contact:

Re: Doing a 'sphere cast'

Post by nikki »

Sorry if I'm rude, but I thought I'd bump the topic. :oops:

Basically, I'm asking two things: What's the right way to do a sphere cast? How do I ensure that it isn't 'inside' a trimesh (all the trimeshes in question are 'proper' and 'closed')?
User avatar
Erwin Coumans
Site Admin
Posts: 4221
Joined: Sun Jun 26, 2005 6:43 pm
Location: California, USA
Contact:

Re: Doing a 'sphere cast'

Post by Erwin Coumans »

You can use btCollisionWorld::convexSweepTest using a btSphereShape, to do a sphere cast (you can use any convex shape you like).

How do I ensure that it isn't 'inside' a trimesh (all the trimeshes in question are 'proper' and 'closed')?

Bullet only checks for collisions between convex object and triangles of the trimesh, along the path from 'fromTransform' to 'toTransform'.

There is no concept of 'inside' of a concave triangle mesh, a btBvhTriangleMeshShape doesn't specify any 'inside' or 'outside' volume. For btConvexHullObject Bullet will properly detect a collision when fully embedded, because a convex object has a clear definition of 'inside' and 'outside'.
You can create some 'inside' test, following DannyChapman's suggestion, or break the triangle mesh up into convex volumes, or create a custom solution for an 'inside' check.
Thanks,
Erwin
User avatar
nikki
Posts: 22
Joined: Sat Jun 14, 2008 3:38 pm
Location: Doha, Qatar.
Contact:

Re: Doing a 'sphere cast'

Post by nikki »

Ok, I have one more little problem: For some reason, the cast is not working on collision objects whose collision mask's units digit is '0'. I'm using 1 and 2 for collision masks of the objects from different 'dimensions', and casts are not working on those from 'dimension 2'. It 'misses' those objects (addSingleResult is never called). It's probably my own mistake, I'll have to check, but do I have to specify some collision flags while doing the convexSweepTest? Or for the shape?

EDIT: Ok, I figured it out, I had to override the 'needsCollision' function. Now I'm thinking of how I'd go about implementing the 'odd number of hits' idea. What's the best way to find out the number of intersections against a ray? Does 'addSingleResult' get called only once for each intersection?
User avatar
nikki
Posts: 22
Joined: Sat Jun 14, 2008 3:38 pm
Location: Doha, Qatar.
Contact:

Re: Doing a 'sphere cast'

Post by nikki »

What's the simplest way to implement the 'inside a trimesh' check? I've tried a few things, but they don't work right, or if they do, they don't work all the time. I don't have enough knowledge of Bullet's internals to do this in a nice way.
Post Reply