finding intersected mesh face

wbult
Posts: 2
Joined: Wed Apr 06, 2011 11:54 am

finding intersected mesh face

Post by wbult »

Trying to find the nearest intersection point on a 3d mesh model from an arbitrary ray, I am not sure if bullet can answer me which face is intersected instead of giving me just intersection point coordination.

The 3D model consists of vertices and triangular faces. Each vertex and face has id and other important attributes which I need to compute on them once the intersection point is found.

Actually, I have not tried bullet before. Is any good tutorial or example about the situation described above?

thanks :)
User avatar
dphil
Posts: 237
Joined: Tue Jun 29, 2010 10:27 pm

Re: finding intersected mesh face

Post by dphil »

For getting the triangle info of a raycast, check out the code (linked file) posted in this thread on the same topic. In particular, it looks like you want to use the collision world rayTest function, and supply it with your own subclass of btCollisionWorld::RayResultCallBack. Example from the linked code:

Code: Select all

struct  MyClosestRayResultCallback : public btCollisionWorld::ClosestRayResultCallback
{
const btCollisionShape * m_hitTriangleShape;
int					  m_hitTriangleIndex;
int					  m_hitShapePart;


	MyClosestRayResultCallback (const btVector3 & rayFrom,const btVector3 & rayTo)
		: btCollisionWorld::ClosestRayResultCallback(rayFrom, rayTo),
		  m_hitTriangleShape(NULL),
		  m_hitTriangleIndex(0),
		  m_hitShapePart(0)
	{
	}

	virtual ~MyClosestRayResultCallback()
	{
	}

	virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult & rayResult, bool normalInWorldSpace)
	{
		if (rayResult.m_localShapeInfo)
		{
			m_hitTriangleShape = rayResult.m_collisionObject->getCollisionShape();
			m_hitTriangleIndex = rayResult.m_localShapeInfo->m_triangleIndex;
			m_hitShapePart = rayResult.m_localShapeInfo->m_shapePart;
		} else 
		{
			m_hitTriangleShape = NULL;
			m_hitTriangleIndex = 0;
			m_hitShapePart = 0;
		}
	return ClosestRayResultCallback::addSingleResult(rayResult,normalInWorldSpace);
	}
};
I believe "addSingleResult" is called automatically during the rayTest and used to fill your callBack with whatever info you want from the LocalRayResult, including, in this case, triangle info. I'm not positive, but I think you can only get exact triangle info if the object hit is a btGImpactMeshShape or btBvhTriangleMeshShape (I believe the former is for dynamic bodies, the latter for static), since those are specially designed for triangle contact precision. Keep in mind that for proper dynamic collisions with btGImpactMeshShape, you need to register the appropriate algorithm:

Code: Select all

btGImpactCollisionAlgorithm::registerAlgorithm(m_dispatcher);
As for the basics on setting up bullet, I suppose the best places to start would be:
1) Bullet User Manual
2) Hello World Bullet Tutorial

Those and more are available from the wiki.
wbult
Posts: 2
Joined: Wed Apr 06, 2011 11:54 am

Re: finding intersected mesh face

Post by wbult »

thanks! It works!

I use simply ray test to check if a ray intersects with btBvhTriangleMeshShape scenes.

Code: Select all

/* raycast.h */
#ifndef RAYCAST_H_
#define RAYCAST_H_

#include "btBulletDynamicsCommon.h"

class RayCast {
public:

	btDiscreteDynamicsWorld* m_dynamicsWorld;
	btDefaultCollisionConfiguration* m_collisionConfiguration;
	btCollisionDispatcher*	m_dispatcher;
	btBroadphaseInterface*	m_overlappingPairCache;
	btConstraintSolver*	m_constraintSolver;

	struct  RayCastClosestRayResultCallback : public btCollisionWorld::ClosestRayResultCallback
	{
		int	m_shapePart;
		int	m_triangleIndex;

		RayCastClosestRayResultCallback (const btVector3 & rayFrom, const btVector3 & rayTo)
		: btCollisionWorld::ClosestRayResultCallback(rayFrom, rayTo),
		  m_shapePart(-1),
		  m_triangleIndex(-1)
		{
		}

		virtual ~RayCastClosestRayResultCallback()
		{
		}

		virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult & rayResult, bool normalInWorldSpace)
		{
			btScalar result = ClosestRayResultCallback::addSingleResult(rayResult,normalInWorldSpace);

			if (rayResult.m_localShapeInfo)
			{
				m_shapePart = rayResult.m_localShapeInfo->m_shapePart;
				m_triangleIndex = rayResult.m_localShapeInfo->m_triangleIndex;
			}

			return result;
		}
	};

	RayCast()
	{
		m_collisionConfiguration = new btDefaultCollisionConfiguration();
		m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
		m_overlappingPairCache = new btDbvtBroadphase();
		m_constraintSolver = new btSequentialImpulseConstraintSolver();
		m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,
				m_overlappingPairCache,
				m_constraintSolver,
				m_collisionConfiguration);
		m_dynamicsWorld->setGravity(btVector3(0,0,0)); // static scene
	}

	~RayCast()
	{
		for (int i=m_dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--)
		{
			btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i];
			btRigidBody* body = btRigidBody::upcast(obj);
			if (body && body->getMotionState())
			{
				delete body->getMotionState();
			}
			m_dynamicsWorld->removeCollisionObject( obj );
			delete obj;
		}

		delete m_dynamicsWorld;
		delete m_constraintSolver;
		delete m_overlappingPairCache;
		delete m_dispatcher;
		delete m_collisionConfiguration;
	}

	void addScene(btBvhTriangleMeshShape *scene)
	{
		btTransform tr;
		tr.setIdentity();
		tr.setOrigin(btVector3(0, 0, 0)); // no translation
		btScalar mass(0.);
		btVector3 localInertia(0,0,0);
		btDefaultMotionState* myMotionState = new btDefaultMotionState(tr);
		btRigidBody::btRigidBodyConstructionInfo rbInfo(mass, myMotionState, scene, localInertia);
		btRigidBody* body = new btRigidBody(rbInfo);

		//add the body to the dynamics world
		m_dynamicsWorld->addRigidBody(body);
	}


	void rayTest(RayCastClosestRayResultCallback & rayCallback)
	{
		m_dynamicsWorld->rayTest(rayCallback.m_rayFromWorld, rayCallback.m_rayToWorld, rayCallback);

		if (rayCallback.hasHit())
		{
			btRigidBody * body = btRigidBody::upcast(rayCallback.m_collisionObject);
			if (body)
			{
				cout << "hit coord " << rayCallback.m_hitPointWorld.x() << " " << rayCallback.m_hitPointWorld.y() << " " << rayCallback.m_hitPointWorld.z() << endl;
				cout << "hit triangle index " << rayCallback.m_triangleIndex << endl;
				cout << "hit triangle shape part " << rayCallback.m_shapePart << endl;
				cout << "hit shape " << rayCallback.m_collisionObject->getCollisionShape()->getName() << endl;

                                 // get triangle vertices position with "process_triangle()"
			}
		}
	}
};

#endif /* RAYCAST_H_ */
the test code...

Code: Select all

/* demo.cpp */
#include "raycast.h"
int main() {

	RayCast ray_cast;

	btBvhTriangleMeshShape * scene;
	btVector3 * m_scene_vertices;
	int * m_scene_triangle_indices;
	btTriangleIndexVertexArray * m_scene_vertex_array;

	{ // scene
		const int vertStride          = sizeof(btVector3);
		const int triangleIndexStride = 3*sizeof(int);

		const int totalVerts     = 12;
		const int totalTriangles = 4;

		m_scene_vertices = new btVector3[totalVerts];
		m_scene_triangle_indices  = new int[totalTriangles*3];

		m_scene_vertices[0].setValue(-5,  5, 15);
		m_scene_vertices[1].setValue( 0, -5, 15);
		m_scene_vertices[2].setValue( 5,  5, 15);

		m_scene_vertices[3].setValue(-5,  5, 5);
		m_scene_vertices[4].setValue( 0, -5, 5);
		m_scene_vertices[5].setValue( 5,  5, 5);

		m_scene_vertices[6].setValue(-5,  5, -15);
		m_scene_vertices[7].setValue( 0, -5, -15);
		m_scene_vertices[8].setValue( 5,  5, -15);

		m_scene_vertices[9].setValue(-5,  5, -6);
		m_scene_vertices[10].setValue( 0, -5, -6);
		m_scene_vertices[11].setValue( 5,  5, -6);

		m_scene_triangle_indices[0] = 0;
		m_scene_triangle_indices[1] = 1;
		m_scene_triangle_indices[2] = 2;

		m_scene_triangle_indices[3] = 3;
		m_scene_triangle_indices[4] = 4;
		m_scene_triangle_indices[5] = 5;

		m_scene_triangle_indices[6] = 6;
		m_scene_triangle_indices[7] = 7;
		m_scene_triangle_indices[8] = 8;

		m_scene_triangle_indices[9] = 9;
		m_scene_triangle_indices[10] = 10;
		m_scene_triangle_indices[11] = 11;


		m_scene_vertex_array = new btTriangleIndexVertexArray(totalTriangles,
				m_scene_triangle_indices,
				triangleIndexStride,
				totalVerts,
				(btScalar*) &m_scene_vertices[0].x(),
				vertStride);

		bool useQuantizedAabbCompression = true;
		scene = new btBvhTriangleMeshShape(m_scene_vertex_array,useQuantizedAabbCompression);
	}

	ray_cast.addScene(scene);

	btVector3 rayFrom(0,0,0), rayTo(0,0,-10);
	RayCast::RayCastClosestRayResultCallback rayCallback(rayFrom, rayTo);
	ray_cast.rayTest(rayCallback);

	btVector3 rayTo1(0,0,10);
	RayCast::RayCastClosestRayResultCallback rayCallback1(rayFrom, rayTo1);
	ray_cast.rayTest(rayCallback1);

	delete scene;
	delete m_scene_vertices;
	delete[] m_scene_triangle_indices;
	delete m_scene_vertex_array;

        return 0;
}

However I still have some small questions.

1. what does 'm_shapePart' from LocalShapeInfo means? a sub part of a mesh? (while m_triangleIndex clearly indicates the index information in triangle index array)

2. can I get Barycentric coordinate instead computing it again? (i.e. how is the intersection point within the triangle face)

3. is there any simple way to get the intersected triangle (vertex position of a face) rather than using btStridingMeshInterface like "process_triangle" from your example? Since I build up objects with btTriangleIndexVertexArray, I should easily get triangle faces with the "hit triangle index" given in ClosestRayResultCallback. But how can I associate the "hit triangle index" to the right rigid/collision objects? is there an index, id, or something that I can define a rigid/collision object and get it in ClosestRayResultCallback.addSingleResult?

thanks again :P
Jinky
Posts: 1
Joined: Mon Aug 22, 2011 7:31 am

Re: finding intersected mesh face

Post by Jinky »

Hi all,

i has two meshs in my game, i want to detect two meshs is collision care. I konw i can useing Mesh.Intersect() to check. But i finded is c++ example in internet. Who can give me few example is useing c# or propose good solution to me?Web Application Mania

Best regards