/* * Copyright (c) 2005 Erwin Coumans * * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies. * Erwin Coumans makes no representations about the suitability * of this software for any purpose. * It is provided "as is" without express or implied warranty. */ #include "BulletCollision/CollisionDispatch/btCollisionWorld.h" /* Raytracer uses the Convex rayCast to visualize the Collision Shapes/Minkowski Sum. Very basic raytracer, rendering into a texture. */ ///Low level demo, doesn't include btBulletCollisionCommon.h #include "LinearMath/btQuaternion.h" #include "LinearMath/btTransform.h" #include "GL_ShapeDrawer.h" #include "GLDebugDrawer.h" #include "Raytracer.h" #include "GlutStuff.h" #include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h" #include "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h" #include "BulletCollision/NarrowPhaseCollision/btGjkConvexCast.h" #include "BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h" #include "BulletCollision/CollisionShapes/btSphereShape.h" #include "BulletCollision/CollisionShapes/btMultiSphereShape.h" #include "BulletCollision/CollisionShapes/btConvexHullShape.h" #include "LinearMath/btAabbUtil2.h" #include "BulletCollision/CollisionShapes/btBoxShape.h" #include "BulletCollision/CollisionShapes/btCompoundShape.h" #include "BulletCollision/CollisionShapes/btTetrahedronShape.h" #include "BulletCollision/CollisionShapes/btConeShape.h" #include "BulletCollision/CollisionShapes/btCylinderShape.h" #include "BulletCollision/CollisionShapes/btMinkowskiSumShape.h" #include "BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h" #include "BulletCollision/BroadphaseCollision/btAxisSweep3.h" #include "RenderTexture.h" static btVoronoiSimplexSolver simplexSolver; static float yaw=0.f,pitch=0.f,roll=0.f; static const int maxNumObjects = 4; static const int numObjects = 3; static btConvexShape* shapePtr[maxNumObjects]; static btTransform transforms[maxNumObjects]; renderTexture* raytracePicture = 0; //this applies to the raytracer virtual screen/image buffer static int screenWidth = 128;//256; //float aspectRatio = (3.f/4.f); static int screenHeight = 64;//256;//screenWidth * aspectRatio; GLuint glTextureId; btConeShape myCone(1,1); btSphereShape mysphere(1); btBoxShape mybox(btVector3(1,1,1)); btCollisionWorld* m_collisionWorld = 0; /// /// /// void Raytracer::initPhysics() { m_ele = 0; raytracePicture = new renderTexture(screenWidth,screenHeight); myCone.setMargin(0.2f); //choose shape shapePtr[0] = &myCone; shapePtr[1] = &mysphere; shapePtr[2] = &mybox; for (int i=0;isetCollisionShape(shapePtr[s]); obj->setWorldTransform(transforms[s]); m_collisionWorld->addCollisionObject(obj); } } Raytracer::~Raytracer() { //cleanup in the reverse order of creation/initialization //remove the rigidbodies from the dynamics world and delete them int i; for (i=m_collisionWorld->getNumCollisionObjects()-1; i>=0 ;i--) { btCollisionObject* obj = m_collisionWorld->getCollisionObjectArray()[i]; m_collisionWorld->removeCollisionObject( obj ); delete obj; } //delete collision world delete m_collisionWorld; //delete broadphase delete m_overlappingPairCache; //delete dispatcher delete m_dispatcher; delete m_collisionConfiguration; delete raytracePicture; raytracePicture=0; } //to be implemented by the demo void Raytracer::clientMoveAndDisplay() { displayCallback(); } bool Raytracer::worldRaytest(const btVector3& rayFrom,const btVector3& rayTo,btVector3& worldNormal,btVector3& worldHitPoint) { struct AllRayResultCallback : public btCollisionWorld::RayResultCallback { AllRayResultCallback(const btVector3& rayFromWorld,const btVector3& rayToWorld) :m_rayFromWorld(rayFromWorld), m_rayToWorld(rayToWorld) { } btVector3 m_rayFromWorld;//used to calculate hitPointWorld from hitFraction btVector3 m_rayToWorld; btVector3 m_hitNormalWorld; btVector3 m_hitPointWorld; virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace) { //caller already does the filter on the m_closestHitFraction btAssert(rayResult.m_hitFraction <= m_closestHitFraction); m_closestHitFraction = rayResult.m_hitFraction; m_collisionObject = rayResult.m_collisionObject; if (normalInWorldSpace) { m_hitNormalWorld = rayResult.m_hitNormalLocal; } else { ///need to transform normal into worldspace m_hitNormalWorld = m_collisionObject->getWorldTransform().getBasis()*rayResult.m_hitNormalLocal; } m_hitPointWorld.setInterpolate3(m_rayFromWorld,m_rayToWorld,rayResult.m_hitFraction); return 1.f; } }; AllRayResultCallback resultCallback(rayFrom,rayTo); // btCollisionWorld::ClosestRayResultCallback resultCallback(rayFrom,rayTo); m_collisionWorld->rayTest(rayFrom,rayTo,resultCallback); if (resultCallback.hasHit()) { worldNormal = resultCallback.m_hitNormalWorld; return true; } return false; } bool Raytracer::singleObjectRaytest(const btVector3& rayFrom,const btVector3& rayTo,btVector3& worldNormal,btVector3& worldHitPoint) { // btScalar closestHitResults = 1.f; btCollisionWorld::ClosestRayResultCallback resultCallback(rayFrom,rayTo); bool hasHit = false; btConvexCast::CastResult rayResult; btSphereShape pointShape(0.0f); btTransform rayFromTrans; btTransform rayToTrans; rayFromTrans.setIdentity(); rayFromTrans.setOrigin(rayFrom); rayToTrans.setIdentity(); rayToTrans.setOrigin(rayTo); for (int s=0;sgetAabb(transforms[s],aabbMin,aabbMax); btScalar hitLambda = 1.f; btVector3 hitNormal; btCollisionObject tmpObj; tmpObj.setWorldTransform(transforms[s]); if (btRayAabb(rayFrom,rayTo,aabbMin,aabbMax,hitLambda,hitNormal)) { //reset previous result btCollisionWorld::rayTestSingle(rayFromTrans,rayToTrans, &tmpObj, shapePtr[s], transforms[s], resultCallback); if (resultCallback.hasHit()) { //float fog = 1.f - 0.1f * rayResult.m_fraction; resultCallback.m_hitNormalWorld.normalize();//.m_normal.normalize(); worldNormal = resultCallback.m_hitNormalWorld; //worldNormal = transforms[s].getBasis() *rayResult.m_normal; worldNormal.normalize(); hasHit = true; } } } return hasHit; } bool Raytracer::lowlevelRaytest(const btVector3& rayFrom,const btVector3& rayTo,btVector3& worldNormal,btVector3& worldHitPoint) { btScalar closestHitResults = 1.f; bool hasHit = false; btConvexCast::CastResult rayResult; btSphereShape pointShape(0.0f); btTransform rayFromTrans; btTransform rayToTrans; rayFromTrans.setIdentity(); rayFromTrans.setOrigin(rayFrom); rayToTrans.setIdentity(); rayToTrans.setOrigin(rayTo); for (int s=0;sgetAabb(transforms[s],aabbMin,aabbMax); btScalar hitLambda = 1.f; btVector3 hitNormal; btCollisionObject tmpObj; tmpObj.setWorldTransform(transforms[s]); if (btRayAabb(rayFrom,rayTo,aabbMin,aabbMax,hitLambda,hitNormal)) { //reset previous result //choose the continuous collision detection method btSubsimplexConvexCast convexCaster(&pointShape,shapePtr[s],&simplexSolver); //btGjkConvexCast convexCaster(&pointShape,shapePtr[s],&simplexSolver); //btContinuousConvexCollision convexCaster(&pointShape,shapePtr[s],&simplexSolver,0); if (convexCaster.calcTimeOfImpact(rayFromTrans,rayToTrans,transforms[s],transforms[s],rayResult)) { if (rayResult.m_fraction < closestHitResults) { closestHitResults = rayResult.m_fraction; worldNormal = transforms[s].getBasis() *rayResult.m_normal; worldNormal.normalize(); hasHit = true; } } } } return hasHit; } void Raytracer::displayCallback() { updateCamera(); for (int i=0;isetPixel(x,y,rgba); } } #if 1 btVector3 rayTo; btTransform colObjWorldTransform; colObjWorldTransform.setIdentity(); int mode = 0; for (x=0;xsetPixel(x,y,rgba); } else { // btVector4 rgba = raytracePicture->getPixel(x,y); } if (!rgba.length2()) { raytracePicture->setPixel(x,y,btVector4(1,1,1,1)); } } } #endif extern unsigned char sFontData[]; if (0) { const char* text="ABC abc 123 !@#"; int x=0; for (int cc = 0;ccsetPixel(x,y,rgba); raytracePicture->addPixel(x,y,rgba); } y++; } x++; } } } //raytracePicture->grapicalPrintf("CCD RAYTRACER",sFontData); char buffer[256]; sprintf(buffer,"%d rays",screenWidth*screenHeight*numObjects); //sprintf(buffer,"Toggle",screenWidth*screenHeight*numObjects); //sprintf(buffer,"TEST",screenWidth*screenHeight*numObjects); //raytracePicture->grapicalPrintf(buffer,sFontData,0,10);//&BMF_font_helv10,0,10); raytracePicture->grapicalPrintf(buffer,sFontData,0,0);//&BMF_font_helv10,0,10); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glFrustum(-1.0,1.0,-1.0,1.0,3,2020.0); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); // reset The Modelview Matrix glTranslatef(0.0f,0.0f,-3.1f); // Move Into The Screen 5 Units glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D,glTextureId ); const unsigned char *ptr = raytracePicture->getBuffer(); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, raytracePicture->getWidth(),raytracePicture->getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, ptr); glEnable (GL_BLEND); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor4f (1,1,1,1); // alpha=0.5=half visible glBegin(GL_QUADS); glTexCoord2f(0.0f, 0.0f); glVertex2f(-1,1); glTexCoord2f(1.0f, 0.0f); glVertex2f(1,1); glTexCoord2f(1.0f, 1.0f); glVertex2f(1,-1); glTexCoord2f(0.0f, 1.0f); glVertex2f(-1,-1); glEnd(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glDisable(GL_TEXTURE_2D); glDisable(GL_DEPTH_TEST); GL_ShapeDrawer::drawCoordSystem(); { for (int i=0;igetAabb(transforms[i],aabbMin,aabbMax); } } glPushMatrix(); glPopMatrix(); pitch += 0.005f; yaw += 0.01f; m_azi += 1.f; glFlush(); glutSwapBuffers(); }