// Add intersections to queue void AddIsects( const Ray3D &ray, const Box3D &box, PointQueue &isects ) { const unsigned nPairs = 3; Point3D rayEnd( ray.origin + ray.direction ); for ( unsigned i = 0; i < nPairs; ++i ) { unsigned j = ( i + 1 ) % nPairs, k = ( i + 2 ) % nPairs; if ( rayEnd[i] != ray.origin[i] ) { for ( unsigned m = 0; m < 2; ++m) { float t = (!m) ? ( box.origin[i] - ray.origin[i] ) / ( ray.direction[i] ) : ( box.extent[i] - ray.origin[i] ) / ( ray.direction[i] ); if ( t >= -epsilon && t <= 1.f + epsilon ) { Point3D isect = ray.origin + t * ray.direction; if ( ( isect[j] >= box.origin[j] && isect[j] <= box.extent[j] ) && ( isect[k] >= box.origin[k] && isect[k] <= box.extent[k] ) ) { TimedPoint point = { t, isect }; if ( isects.c.end() == std::find( isects.c.begin(), isects.c.end(), point ) ) isects.push( point ); } } } } } }
//-------------------------------------------------------------- ofxBulletRaycastData ofxBulletWorldRigid::raycastTest( ofVec3f a_rayStart, ofVec3f a_rayEnd, short int a_filterMask) { ofxBulletRaycastData data; data.bHasHit = false; btVector3 rayStart( a_rayStart.x, a_rayStart.y, a_rayStart.z ); btVector3 rayEnd( a_rayEnd.x, a_rayEnd.y, a_rayEnd.z ); btCollisionWorld::ClosestRayResultCallback rayCallback( rayStart, rayEnd ); rayCallback.m_collisionFilterMask = a_filterMask; world->rayTest( rayStart, rayEnd, rayCallback ); if (rayCallback.hasHit()) { btRigidBody* body = btRigidBody::upcast( (btCollisionObject*)rayCallback.m_collisionObject ); if (body) { data.bHasHit = true; data.userData = (ofxBulletUserData*)body->getUserPointer(); data.body = body; data.rayWorldPos = a_rayEnd; btVector3 pickPos = rayCallback.m_hitPointWorld; data.pickPosWorld = ofVec3f(pickPos.getX(), pickPos.getY(), pickPos.getZ()); btVector3 localPos = body->getCenterOfMassTransform().inverse() * pickPos; data.localPivotPos = ofVec3f(localPos.getX(), localPos.getY(), localPos.getZ() ); } } return data; }
bool CollisionManager::checkMovementCollision(CreatureObject* creature, float x, float z, float y, Zone* zone) { SortedVector<ManagedReference<QuadTreeEntry*> > closeObjects; zone->getInRangeObjects(x, y, 128, &closeObjects, true); //Vector3 rayStart(x, z + 0.25, y); //Vector3 rayStart(creature->getWorldPositionX(), creature->getWorldPositionZ(), creature->getPos) Vector3 rayStart = creature->getWorldPosition(); rayStart.set(rayStart.getX(), rayStart.getY(), rayStart.getZ() + 0.25f); //Vector3 rayEnd(x + System::random(512), z + 0.3f, y + System::random(512)); /*Vector3 rayEnd; rayEnd.set(targetPosition.getX(), targetPosition.getY(), targetPosition.getZ());*/ Vector3 rayEnd(x, z + 0.25, y); float maxDistance = rayEnd.distanceTo(rayStart); if (maxDistance == 0) return false; printf("%f\n", maxDistance); SortedVector<IntersectionResult> results; results.setAllowDuplicateInsertPlan(); printf("starting test\n"); Triangle* triangle; for (int i = 0; i < closeObjects.size(); ++i) { SceneObject* object = dynamic_cast<SceneObject*>(closeObjects.get(i).get()); if (object == NULL) continue; AABBTree* tree = getAABBTree(object, 255); if (tree == NULL) continue; Ray ray = convertToModelSpace(rayStart, rayEnd, object); //results.removeAll(10, 10); //ordered by intersection distance //tree->intersects(ray, maxDistance, results); float intersectionDistance; if (tree->intersects(ray, maxDistance, intersectionDistance, triangle, true)) { String str = object->getObjectTemplate()->getFullTemplateString(); object->info("intersecting with me " + str, true); return true; } } return false; }
Vector<float>* CollisionManager::getCellFloorCollision(float x, float y, CellObject* cellObject) { Vector<float>* collisions = NULL; ManagedReference<SceneObject*> rootObject = cellObject->getRootParent(); if (rootObject == NULL) return NULL; SharedObjectTemplate* templateObject = rootObject->getObjectTemplate(); if (templateObject == NULL) return NULL; PortalLayout* portalLayout = templateObject->getPortalLayout(); if (portalLayout == NULL) return NULL; FloorMesh* mesh = portalLayout->getFloorMesh(cellObject->getCellNumber()); if (mesh == NULL) return NULL; AABBTree* tree = mesh->getAABBTree(); if (tree == NULL) return NULL; Vector3 rayStart(x, 16384.f, y); Vector3 rayEnd(x, -16384.f, y); Vector3 norm = rayEnd - rayStart; norm.normalize(); Ray ray(rayStart, norm); SortedVector<IntersectionResult> results(3, 2); tree->intersects(ray, 16384 * 2, results); if (results.size() == 0) return NULL; collisions = new Vector<float>(results.size(), 1); for (int i = 0; i < results.size(); ++i) { float floorHeight = 16384 - results.get(i).getIntersectionDistance(); collisions->add(floorHeight); } return collisions; }
//-------------------------------------------------------------- ofxBulletRaycastData ofxBulletWorldSoft::raycastTest( ofVec3f a_rayStart, ofVec3f a_rayEnd, short int a_filterMask) { ofxBulletRaycastData data; data.bHasHit = false; if(_camera == NULL) { ofLog( OF_LOG_ERROR, "ofxBulletWorldSoft :: raycastTest : must set the camera first!!"); return data; } btVector3 rayStart( a_rayStart.x, a_rayStart.y, a_rayStart.z ); btVector3 rayEnd( a_rayEnd.x, a_rayEnd.y, a_rayEnd.z ); btCollisionWorld::ClosestRayResultCallback rayCallback( rayStart, rayEnd ); rayCallback.m_collisionFilterMask = a_filterMask; world->rayTest( rayStart, rayEnd, rayCallback ); if (rayCallback.hasHit()) { if ( rayCallback.m_collisionObject->getInternalType() & btCollisionObject::CO_SOFT_BODY ) { // cast a ray into the soft body to get the point exactly //ofLogNotice("ofxBulletWorldSoft: soft body intersection"); btSoftBody::sRayCast result; #warning Casting (const btSoftBody*) to (btSoftBody*) -- not necessarily safe btSoftBody* body = (btSoftBody*)btSoftBody::upcast( rayCallback.m_collisionObject ); if ( body->rayTest( rayStart, rayEnd, result ) ) { if ( result.fraction<1.0f ) { //ofLogNotice("ofxBulletWorldSoft") << " at " << result.getFeatureName() << " index " << result.index; } } } else { #warning Casting (const btRigidBody*) to (btRigidBody*) -- not necessarily safe btRigidBody* body = (btRigidBody*)btRigidBody::upcast(rayCallback.m_collisionObject); if (body) { data.bHasHit = true; data.userData = (ofxBulletUserData*)body->getUserPointer(); data.body = body; data.rayWorldPos = a_rayEnd; btVector3 pickPos = rayCallback.m_hitPointWorld; data.pickPosWorld = ofVec3f(pickPos.getX(), pickPos.getY(), pickPos.getZ()); btVector3 localPos = body->getCenterOfMassTransform().inverse() * pickPos; data.localPivotPos = ofVec3f(localPos.getX(), localPos.getY(), localPos.getZ() ); } } } return data; }
void CollisionManager::getWorldFloorCollisions(float x, float y, Zone* zone, SortedVector<IntersectionResult>* result, const Vector<QuadTreeEntry*>& inRangeObjects) { Vector3 rayStart(x, 16384.f, y); Vector3 rayEnd(x, -16384.f, y); for (int i = 0; i < inRangeObjects.size(); ++i) { SceneObject* sceno = static_cast<SceneObject*>(inRangeObjects.get(i)); AABBTree* aabbTree = getAABBTree(sceno, 255); if (aabbTree == NULL) continue; Ray ray = convertToModelSpace(rayStart, rayEnd, sceno); aabbTree->intersects(ray, 16384 * 2, *result); } }
float CollisionManager::getWorldFloorCollision(float x, float y, Zone* zone, bool testWater) { SortedVector<ManagedReference<QuadTreeEntry*> > closeObjects; zone->getInRangeObjects(x, y, 128, &closeObjects, true); PlanetManager* planetManager = zone->getPlanetManager(); if (planetManager == NULL) return 0.f; float height = 0; TerrainManager* terrainManager = planetManager->getTerrainManager(); //need to include exclude affectors in the terrain calcs height = terrainManager->getHeight(x, y); Vector3 rayStart(x, 16384.f, y); Vector3 rayEnd(x, -16384.f, y); Triangle* triangle = NULL; if (testWater) { float waterHeight; if (terrainManager->getWaterHeight(x, y, waterHeight)) if (waterHeight > height) height = waterHeight; } float intersectionDistance; for (int i = 0; i < closeObjects.size(); ++i) { BuildingObject* building = dynamic_cast<BuildingObject*>(closeObjects.get(i).get()); if (building == NULL) continue; //building->getObjectTemplate()->get SharedObjectTemplate* templateObject = building->getObjectTemplate(); if (templateObject == NULL) continue; PortalLayout* portalLayout = templateObject->getPortalLayout(); if (portalLayout == NULL) continue; if (portalLayout->getFloorMeshNumber() == 0) continue; //find nearest entrance FloorMesh* exteriorFloorMesh = portalLayout->getFloorMesh(0); // get outside layout AABBTree* aabbTree = exteriorFloorMesh->getAABBTree(); if (aabbTree == NULL) continue; Ray ray = convertToModelSpace(rayStart, rayEnd, building); if (aabbTree->intersects(ray, 16384 * 2, intersectionDistance, triangle, true)) { float floorHeight = 16384 - intersectionDistance; if (floorHeight > height) height = floorHeight; } } return height; }
/*! * Lesson 01 - Hello Bullet * Create an irrlicht scene and a bullet world * Implement the integration, and build a foundation * for the other tutorials */ int main(int argc, char *argv[]) { // Irrlicht grabs the cursor so it is not in the way of our visualisation // Window caption gets set. device->getCursorControl()->setVisible(0); device->setWindowCaption(L"Lesson 03 - Intro to Raycasting"); // Set the camera backwards and viewing the origin; setting up the visualisation cam->setPosition(irr::core::vector3df(0, 2, -5)); cam->setTarget(irr::core::vector3df(0, 2, 0)); smgr->addLightSceneNode(0, irr::core::vector3df(2, 10, -2), irr::video::SColorf(4, 4, 4, 1)); // Creating our scene createScene(); // Use a timestamp to regulate the frames, and stepping the simulation irr::u32 timeStamp = timer->getTime(), deltaTime = 0; // Game loop while(!done) { // Code to record when the frame began deltaTime = timer->getTime() - timeStamp; timeStamp = timer->getTime(); // Step the simulation updatePhysics(deltaTime); // Irrlicht draws the scene driver->beginScene(true, true, irr::video::SColor(0, 15, 192, 252)); //Visualize the raycast for the camera. The line needs to only be as long as the ray cast that way we are not blazing through objects and it really helps show the concept of ray casting, and it is a more realistic laser sight // Need the name for this mathmatical formula irr::core::vector3df rayEnd(sin(cam->getRotation().Y * M_PI / 180.0f) * cos(cam->getRotation().X * M_PI / 180.0f) * 50.0f, -1 * sin(cam->getRotation().X * M_PI / 180.0f) * 50.0f, cos(cam->getRotation().Y * M_PI / 180.0f) * cos(cam->getRotation().X * M_PI / 180.0f) * 50.0f); // Reset the transformation matrix for the raycast irr::video::SMaterial m; m.Lighting=false; driver->setMaterial(m); driver->setTransform(irr::video::ETS_WORLD, irr::core::matrix4()); //Draw our laser sight driver->draw3DLine(cam->getPosition() + irr::core::vector3df(.1, .01, 0), rayEnd, irr::video::SColor(255, 255, 0, 0)); smgr->drawAll(); driver->endScene(); device->run(); } // clean up clearObjects(); delete world; delete solver; delete dispatcher; delete broadphase; delete collisionConfiguration; device->drop(); return 0; }