#include "RaytracerSetup.h" #include "../CommonInterfaces/CommonGraphicsAppInterface.h" #include "Bullet3Common/b3Quaternion.h" #include "Bullet3Common/b3AlignedObjectArray.h" #include "../CommonInterfaces/CommonRenderInterface.h" #include "../CommonInterfaces/Common2dCanvasInterface.h" //#include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h" #include "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h" //#include "BulletCollision/NarrowPhaseCollision/btGjkConvexCast.h" //#include "BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h" #include "../CommonInterfaces/CommonExampleInterface.h" #include "LinearMath/btAlignedObjectArray.h" #include "btBulletCollisionCommon.h" #include "../CommonInterfaces/CommonGUIHelperInterface.h" struct RaytracerPhysicsSetup : public CommonExampleInterface { struct CommonGraphicsApp* m_app; struct RaytracerInternalData* m_internalData; RaytracerPhysicsSetup(struct CommonGraphicsApp* app); virtual ~RaytracerPhysicsSetup(); virtual void initPhysics(); virtual void exitPhysics(); virtual void stepSimulation(float deltaTime); virtual void physicsDebugDraw(int debugFlags); virtual void syncPhysicsToGraphics(struct GraphicsPhysicsBridge& gfxBridge); ///worldRaytest performs a ray versus all objects in a collision world, returning true is a hit is found (filling in worldNormal and worldHitPoint) bool worldRaytest(const btVector3& rayFrom,const btVector3& rayTo,btVector3& worldNormal,btVector3& worldHitPoint); ///singleObjectRaytest performs a ray versus one collision shape, returning true is a hit is found (filling in worldNormal and worldHitPoint) bool singleObjectRaytest(const btVector3& rayFrom,const btVector3& rayTo,btVector3& worldNormal,btVector3& worldHitPoint); ///lowlevelRaytest performs a ray versus convex shape, returning true is a hit is found (filling in worldNormal and worldHitPoint) bool lowlevelRaytest(const btVector3& rayFrom,const btVector3& rayTo,btVector3& worldNormal,btVector3& worldHitPoint); virtual bool mouseMoveCallback(float x,float y); virtual bool mouseButtonCallback(int button, int state, float x, float y); virtual bool keyboardCallback(int key, int state); virtual void renderScene() { } }; struct RaytracerInternalData { int m_canvasIndex; struct Common2dCanvasInterface* m_canvas; int m_width; int m_height; btAlignedObjectArray m_shapePtr; btAlignedObjectArray m_transforms; btVoronoiSimplexSolver m_simplexSolver; btScalar m_pitch; btScalar m_roll; btScalar m_yaw; RaytracerInternalData() :m_canvasIndex(-1), m_canvas(0), m_roll(0), m_pitch(0), m_yaw(0), #ifdef _DEBUG m_width(64), m_height(64) #else m_width(128), m_height(128) #endif { btConeShape* cone = new btConeShape(1,1); btSphereShape* sphere = new btSphereShape(1); btBoxShape* box = new btBoxShape (btVector3(1,1,1)); m_shapePtr.push_back(cone); m_shapePtr.push_back(sphere); m_shapePtr.push_back(box); updateTransforms(); } void updateTransforms() { int numObjects = m_shapePtr.size(); m_transforms.resize(numObjects); for (int i=0;im_canvas = m_app->m_2dCanvasInterface; if (m_internalData->m_canvas) { m_internalData->m_canvasIndex = m_internalData->m_canvas->createCanvas("raytracer",m_internalData->m_width,m_internalData->m_height); for (int i=0;im_width;i++) { for (int j=0;jm_height;j++) { unsigned char red=255; unsigned char green=255; unsigned char blue=255; unsigned char alpha=255; m_internalData->m_canvas->setPixel(m_internalData->m_canvasIndex,i,j,red,green,blue,alpha); } } m_internalData->m_canvas->refreshImageData(m_internalData->m_canvasIndex); //int bitmapId = gfxBridge.createRenderBitmap(width,height); } } ///worldRaytest performs a ray versus all objects in a collision world, returning true is a hit is found (filling in worldNormal and worldHitPoint) bool RaytracerPhysicsSetup::worldRaytest(const btVector3& rayFrom,const btVector3& rayTo,btVector3& worldNormal,btVector3& worldHitPoint) { return false; } ///singleObjectRaytest performs a ray versus one collision shape, returning true is a hit is found (filling in worldNormal and worldHitPoint) bool RaytracerPhysicsSetup::singleObjectRaytest(const btVector3& rayFrom,const btVector3& rayTo,btVector3& worldNormal,btVector3& worldHitPoint) { return false; } ///lowlevelRaytest performs a ray versus convex shape, returning true is a hit is found (filling in worldNormal and worldHitPoint) bool RaytracerPhysicsSetup::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); int numObjects = m_internalData->m_shapePtr.size(); for (int s=0;sm_shapePtr[s]->getAabb( m_internalData->m_transforms[s],aabbMin,aabbMax); btScalar hitLambda = 1.f; btVector3 hitNormal; btCollisionObject tmpObj; tmpObj.setWorldTransform( m_internalData->m_transforms[s]); if (btRayAabb(rayFrom,rayTo,aabbMin,aabbMax,hitLambda,hitNormal)) { //reset previous result //choose the continuous collision detection method btSubsimplexConvexCast convexCaster(&pointShape, m_internalData->m_shapePtr[s],&m_internalData->m_simplexSolver); //btGjkConvexCast convexCaster(&pointShape,shapePtr[s],&simplexSolver); //btContinuousConvexCollision convexCaster(&pointShape,shapePtr[s],&simplexSolver,0); if (convexCaster.calcTimeOfImpact(rayFromTrans,rayToTrans, m_internalData->m_transforms[s], m_internalData->m_transforms[s],rayResult)) { if (rayResult.m_fraction < closestHitResults) { closestHitResults = rayResult.m_fraction; worldNormal = m_internalData->m_transforms[s].getBasis() *rayResult.m_normal; worldNormal.normalize(); hasHit = true; } } } } return hasHit; } void RaytracerPhysicsSetup::exitPhysics() { if (m_internalData->m_canvas && m_internalData->m_canvasIndex>=0) { m_internalData->m_canvas->destroyCanvas(m_internalData->m_canvasIndex); } } void RaytracerPhysicsSetup::stepSimulation(float deltaTime) { m_internalData->updateTransforms(); float top = 1.f; float bottom = -1.f; float nearPlane = 1.f; float tanFov = (top-bottom)*0.5f / nearPlane; float fov = 2.0 * atanf (tanFov); btVector3 cameraPosition(5,0,0); btVector3 cameraTargetPosition(0,0,0); btVector3 rayFrom = cameraPosition; btVector3 rayForward = cameraTargetPosition-cameraPosition; rayForward.normalize(); float farPlane = 600.f; rayForward*= farPlane; btVector3 rightOffset; btVector3 vertical(0.f,1.f,0.f); btVector3 hor; hor = rayForward.cross(vertical); hor.normalize(); vertical = hor.cross(rayForward); vertical.normalize(); float tanfov = tanf(0.5f*fov); hor *= 2.f * farPlane * tanfov; vertical *= 2.f * farPlane * tanfov; btVector3 rayToCenter = rayFrom + rayForward; btVector3 dHor = hor * 1.f/float(m_internalData->m_width); btVector3 dVert = vertical * 1.f/float(m_internalData->m_height); int mode = 0; int x,y; for (x=0;xm_width;x++) { for (int y=0;ym_height;y++) { btVector4 rgba(0,0,0,0); btVector3 rayTo = rayToCenter - 0.5f * hor + 0.5f * vertical; rayTo += x * dHor; rayTo -= y * dVert; btVector3 worldNormal(0,0,0); btVector3 worldPoint(0,0,0); bool hasHit = false; int mode = 0; switch (mode) { case 0: hasHit = lowlevelRaytest(rayFrom,rayTo,worldNormal,worldPoint); break; case 1: hasHit = singleObjectRaytest(rayFrom,rayTo,worldNormal,worldPoint); break; case 2: hasHit = worldRaytest(rayFrom,rayTo,worldNormal,worldPoint); break; default: { } } if (hasHit) { float lightVec0 = worldNormal.dot(btVector3(0,-1,-1));//0.4f,-1.f,-0.4f)); float lightVec1= worldNormal.dot(btVector3(-1,0,-1));//-0.4f,-1.f,-0.4f)); rgba = btVector4(lightVec0,lightVec1,0,1.f); rgba.setMin(btVector3(1,1,1)); rgba.setMax(btVector3(0.2,0.2,0.2)); rgba[3] = 1.f; unsigned char red = rgba[0] * 255; unsigned char green = rgba[1] * 255; unsigned char blue = rgba[2] * 255; unsigned char alpha=255; m_internalData->m_canvas->setPixel(m_internalData->m_canvasIndex,x,y,red,green,blue,alpha); } else { // btVector4 rgba = raytracePicture->getPixel(x,y); } if (!rgba.length2()) { m_internalData->m_canvas->setPixel(m_internalData->m_canvasIndex,x,y,255,0,0,255); } } } m_internalData->m_canvas->refreshImageData(m_internalData->m_canvasIndex); } void RaytracerPhysicsSetup::physicsDebugDraw(int debugDrawFlags) { } bool RaytracerPhysicsSetup::mouseMoveCallback(float x,float y) { return false; } bool RaytracerPhysicsSetup::mouseButtonCallback(int button, int state, float x, float y) { return false; } bool RaytracerPhysicsSetup::keyboardCallback(int key, int state) { return false; } void RaytracerPhysicsSetup::syncPhysicsToGraphics(GraphicsPhysicsBridge& gfxBridge) { } CommonExampleInterface* RayTracerCreateFunc(struct CommonExampleOptions& options) { return new RaytracerPhysicsSetup(options.m_guiHelper->getAppInterface()); }