bool CollisionManager::checkLineOfSightWorldToCell(const Vector3& rayOrigin, const Vector3& rayEnd, float distance, CellObject* cellObject) { ManagedReference<SceneObject*> building = cellObject->getParent(); if (building == NULL) return true; SharedObjectTemplate* objectTemplate = building->getObjectTemplate(); PortalLayout* portalLayout = objectTemplate->getPortalLayout(); if (portalLayout == NULL) return true; Ray ray = convertToModelSpace(rayOrigin, rayEnd, building); if (cellObject->getCellNumber() >= portalLayout->getAppearanceTemplatesSize()) return true; MeshAppearanceTemplate* app = portalLayout->getMeshAppearanceTemplate(cellObject->getCellNumber()); AABBTree* aabbTree = app->getAABBTree(); if (aabbTree == NULL) return true; float intersectionDistance; Triangle* triangle = NULL; if (aabbTree->intersects(ray, distance, intersectionDistance, triangle, true)) return false; return true; }
TriangleNode* CollisionManager::getTriangle(const Vector3& point, FloorMesh* floor) { /*PathGraph* graph = node->getPathGraph(); FloorMesh* floor = graph->getFloorMesh();*/ AABBTree* aabbTree = floor->getAABBTree(); //Vector3 nodePosition = node->getPosition(); Vector3 rayOrigin(point.getX(), point.getZ() + 0.5, point.getY()); //Vector3 rayOrigin(point.getX(), point.getY(), point.getZ() + 0.2); Vector3 direction(0, -1, 0); Ray ray(rayOrigin, direction); float intersectionDistance = 0; Triangle* triangle = NULL; aabbTree->intersects(ray, 4, intersectionDistance, triangle, true); TriangleNode* triangleNode = dynamic_cast<TriangleNode*>(triangle); if (triangleNode == NULL) { //System::out << "CollisionManager::getTriangle triangleNode NULL" << endl; return floor->findNearestTriangle(rayOrigin); } return triangleNode; }
bool CollisionManager::checkLineOfSightInParentCell(SceneObject* object, Vector3& endPoint) { ManagedReference<SceneObject*> parent = object->getParent(); if (parent == NULL || !parent->isCellObject()) return true; CellObject* cell = cast<CellObject*>( parent.get()); SharedObjectTemplate* objectTemplate = parent->getRootParent().get()->getObjectTemplate(); PortalLayout* portalLayout = objectTemplate->getPortalLayout(); MeshAppearanceTemplate* appearanceMesh = NULL; if (portalLayout == NULL) return true; try { appearanceMesh = portalLayout->getMeshAppearanceTemplate(cell->getCellNumber()); } catch (Exception& e) { return true; } if (appearanceMesh == NULL) { //info("null appearance mesh "); return true; } AABBTree* aabbTree = appearanceMesh->getAABBTree(); if (aabbTree == NULL) return true; //switching Y<->Z, adding 0.1 to account floor Vector3 startPoint = object->getPosition(); startPoint.set(startPoint.getX(), startPoint.getY(), startPoint.getZ() + 0.1f); endPoint.set(endPoint.getX(), endPoint.getY(), endPoint.getZ() + 0.1f); Vector3 dir = endPoint - startPoint; dir.normalize(); float distance = endPoint.distanceTo(startPoint); float intersectionDistance; Ray ray(startPoint, dir); Triangle* triangle = NULL; //nothing in the middle if (aabbTree->intersects(ray, distance, intersectionDistance, triangle, true)) return false; Ray ray2(endPoint, Vector3(0, -1, 0)); //check if we are in the cell with dir (0, -1, 0) if (!aabbTree->intersects(ray2, 64000.f, intersectionDistance, triangle, true)) return false; return true; }
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; }
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); } }
bool CollisionManager::checkSphereCollision(const Vector3& origin, float radius, Zone* zone) { Vector3 sphereOrigin(origin.getX(), origin.getZ(), origin.getY()); SortedVector<ManagedReference<QuadTreeEntry*> > objects(512, 512); zone->getInRangeObjects(origin.getX(), origin.getY(), 512, &objects, true); for (int i = 0; i < objects.size(); ++i) { AABBTree* aabbTree = NULL; SceneObject* scno = cast<SceneObject*>(objects.get(i).get()); try { aabbTree = getAABBTree(scno, -1); if (aabbTree == NULL) continue; } catch (Exception& e) { aabbTree = NULL; } catch (...) { throw; } if (aabbTree != NULL) { //moving ray to model space try { Sphere sphere(convertToModelSpace(sphereOrigin, scno), radius); //structure->info("checking ray with building dir" + String::valueOf(structure->getDirectionAngle()), true); if (aabbTree->testCollide(sphere)) { return true; } } catch (Exception& e) { scno->error(e.getMessage()); } catch (...) { throw; } } } return false; }
bool CollisionManager::checkLineOfSightInBuilding(SceneObject* object1, SceneObject* object2, SceneObject* building) { SharedObjectTemplate* objectTemplate = building->getObjectTemplate(); PortalLayout* portalLayout = objectTemplate->getPortalLayout(); if (portalLayout == NULL) return true; //we are in model space... in cells Vector3 rayOrigin = object1->getPosition(); rayOrigin.set(rayOrigin.getX(), rayOrigin.getY(), rayOrigin.getZ() + 1.f); Vector3 rayEnd = object2->getPosition(); rayEnd.set(rayEnd.getX(), rayEnd.getY(), rayEnd.getZ() + 1.f); Vector3 direction(Vector3(rayEnd - rayOrigin)); direction.normalize(); float distance = rayEnd.distanceTo(rayOrigin); float intersectionDistance; Ray ray(rayOrigin, direction); Triangle* triangle = NULL; // we check interior cells for (int i = 1; i < portalLayout->getAppearanceTemplatesSize(); ++i) { MeshAppearanceTemplate* app = portalLayout->getMeshAppearanceTemplate(i); AABBTree* aabbTree = app->getAABBTree(); if (aabbTree == NULL) continue; if (aabbTree->intersects(ray, distance, intersectionDistance, triangle, true)) return false; } return true; }
bool HybridModel::Build(const OPCODECREATE& create) { // 1) Checkings if(!create.mIMesh || !create.mIMesh->IsValid()) return false; // Look for degenerate faces. udword NbDegenerate = create.mIMesh->CheckTopology(); if(NbDegenerate) OpcodeLog("OPCODE WARNING: found %d degenerate faces in model! Collision might report wrong results!\n", NbDegenerate); // We continue nonetheless.... Release(); // Make sure previous tree has been discarded // 1-1) Setup mesh interface automatically SetMeshInterface(create.mIMesh); bool Status = false; AABBTree* LeafTree = null; Internal Data; // 2) Build a generic AABB Tree. mSource = new AABBTree; CHECKALLOC(mSource); // 2-1) Setup a builder. Our primitives here are triangles from input mesh, // so we use an AABBTreeOfTrianglesBuilder..... { AABBTreeOfTrianglesBuilder TB; TB.mIMesh = create.mIMesh; TB.mNbPrimitives = create.mIMesh->GetNbTriangles(); TB.mSettings = create.mSettings; TB.mSettings.mLimit = 16; // ### Hardcoded, but maybe we could let the user choose 8 / 16 / 32 ... if(!mSource->Build(&TB)) goto FreeAndExit; } // 2-2) Here's the trick : create *another* AABB tree using the leaves of the first one (which are boxes, this time) struct Local { // A callback to count leaf nodes static bool CountLeaves(const AABBTreeNode* current, udword depth, void* user_data) { if(current->IsLeaf()) { Internal* Data = (Internal*)user_data; Data->mNbLeaves++; } return true; } // A callback to setup leaf nodes in our internal structures static bool SetupLeafData(const AABBTreeNode* current, udword depth, void* user_data) { if(current->IsLeaf()) { Internal* Data = (Internal*)user_data; // Get current leaf's box Data->mLeaves[Data->mNbLeaves] = *current->GetAABB(); // Setup leaf data udword Index = (size_t(current->GetPrimitives()) - size_t(Data->mBase)) / sizeof(size_t); Data->mTriangles[Data->mNbLeaves].SetData(current->GetNbPrimitives(), Index); Data->mNbLeaves++; } return true; } }; // Walk the tree & count number of leaves Data.mNbLeaves = 0; mSource->Walk(Local::CountLeaves, &Data); mNbLeaves = Data.mNbLeaves; // Keep track of it // Special case for 1-leaf meshes if(mNbLeaves==1) { mModelCode |= OPC_SINGLE_NODE; Status = true; goto FreeAndExit; } // Allocate our structures Data.mLeaves = new IceMaths::AABB[Data.mNbLeaves]; CHECKALLOC(Data.mLeaves); mTriangles = new LeafTriangles[Data.mNbLeaves]; CHECKALLOC(mTriangles); // Walk the tree again & setup leaf data Data.mTriangles = mTriangles; Data.mBase = mSource->GetIndices(); Data.mNbLeaves = 0; // Reset for incoming walk mSource->Walk(Local::SetupLeafData, &Data); // Handle source indices { bool MustKeepIndices = true; if(create.mCanRemap) { // We try to get rid of source indices (saving more ram!) by reorganizing triangle arrays... // Remap can fail when we use callbacks => keep track of indices in that case (it still // works, only using more memory) if(create.mIMesh->RemapClient(mSource->GetNbPrimitives(), mSource->GetIndices())) { MustKeepIndices = false; } } if(MustKeepIndices) { // Keep track of source indices (from vanilla tree) mNbPrimitives = mSource->GetNbPrimitives(); mIndices = new udword[mNbPrimitives]; CopyMemory(mIndices, mSource->GetIndices(), mNbPrimitives*sizeof(udword)); } } // Now, create our optimized tree using previous leaf nodes LeafTree = new AABBTree; CHECKALLOC(LeafTree); { AABBTreeOfAABBsBuilder TB; // Now using boxes ! TB.mSettings = create.mSettings; TB.mSettings.mLimit = 1; // We now want a complete tree so that we can "optimize" it TB.mNbPrimitives = Data.mNbLeaves; TB.mAABBArray = Data.mLeaves; if(!LeafTree->Build(&TB)) goto FreeAndExit; } // 3) Create an optimized tree according to user-settings if(!CreateTree(create.mNoLeaf, create.mQuantized)) goto FreeAndExit; // 3-2) Create optimized tree if(!mTree->Build(LeafTree)) goto FreeAndExit; // Finally ok... Status = true; FreeAndExit: // Allow me this one... DELETESINGLE(LeafTree); // 3-3) Delete generic tree if needed if(!create.mKeepOriginal) DELETESINGLE(mSource); return Status; }
bool CollisionManager::checkShipCollision(ShipObject* ship, const Vector3& targetPosition, Vector3& collisionPoint) { Zone* zone = ship->getZone(); if (zone == NULL) return false; TerrainManager* terrainManager = zone->getPlanetManager()->getTerrainManager(); if (terrainManager->getProceduralTerrainAppearance() != NULL) { float height = terrainManager->getHeight(targetPosition.getX(), targetPosition.getY()); float waterHeight = -16368.f; if (terrainManager->getWaterHeight(targetPosition.getY(), targetPosition.getY(), waterHeight)) height = MAX(waterHeight, height); if (height > targetPosition.getZ()) { collisionPoint = targetPosition; collisionPoint.setZ(height); //ship->info("colliding with terrain", true); return true; } } Vector3 rayOrigin = ship->getWorldPosition(); rayOrigin.set(rayOrigin.getX(), rayOrigin.getY(), rayOrigin.getZ()); Vector3 rayEnd; rayEnd.set(targetPosition.getX(), targetPosition.getY(), targetPosition.getZ()); float dist = rayEnd.distanceTo(rayOrigin); float intersectionDistance; Triangle* triangle = NULL; SortedVector<ManagedReference<QuadTreeEntry*> > objects(512, 512); zone->getInRangeObjects(targetPosition.getX(), targetPosition.getY(), 512, &objects, true); for (int i = 0; i < objects.size(); ++i) { AABBTree* aabbTree = NULL; SceneObject* scno = cast<SceneObject*>(objects.get(i).get()); try { aabbTree = getAABBTree(scno, -1); if (aabbTree == NULL) continue; } catch (Exception& e) { aabbTree = NULL; } catch (...) { throw; } if (aabbTree != NULL) { //moving ray to model space try { Ray ray = convertToModelSpace(rayOrigin, rayEnd, scno); //structure->info("checking ray with building dir" + String::valueOf(structure->getDirectionAngle()), true); if (aabbTree->intersects(ray, dist, intersectionDistance, triangle, true)) { //rayOrigin.set(rayOrigin.getX(), rayOrigin.getY(), rayOrigin.getZ()); Vector3 direction = rayEnd - rayOrigin; direction.normalize(); //intersectionDistance -= 0.5f; collisionPoint.set(rayOrigin.getX() + (direction.getX() * intersectionDistance), rayOrigin.getY() + (direction.getY() * intersectionDistance), rayOrigin.getZ() + (direction.getZ() * intersectionDistance)); //ship->info("colliding with building", true); return true; } } catch (Exception& e) { ship->error(e.getMessage()); } catch (...) { throw; } } } return false; }
bool CollisionManager::checkLineOfSight(SceneObject* object1, SceneObject* object2) { Zone* zone = object1->getZone(); if (zone == NULL) return false; if (object2->getZone() != zone) return false; if (object1->isAiAgent() || object2->isAiAgent()) { Vector<WorldCoordinates>* path = PathFinderManager::instance()->findPath(object1, object2); if (path == NULL) return false; else delete path; } ManagedReference<SceneObject*> rootParent1 = object1->getRootParent(); ManagedReference<SceneObject*> rootParent2 = object2->getRootParent(); if (rootParent1 != NULL || rootParent2 != NULL) { if (rootParent1 == rootParent2) { return CollisionManager::checkLineOfSightInBuilding(object1, object2, rootParent1); } else if (rootParent1 != NULL && rootParent2 != NULL) return false; //different buildings } //switching z<->y, adding player height (head) Vector3 rayOrigin = object1->getWorldPosition(); float heightOrigin = 1.f; float heightEnd = 1.f; Reference<SortedVector<ManagedReference<QuadTreeEntry*> >*> closeObjects = new SortedVector<ManagedReference<QuadTreeEntry*> >(); // = object1->getCloseObjects(); int maxInRangeObjectCount = 0; if (object1->getCloseObjects() == NULL) { object1->info("Null closeobjects vector in CollisionManager::checkLineOfSight", true); // closeObjectsCopy = new SortedVector<ManagedReference<QuadTreeEntry*> >(); zone->getInRangeObjects(object1->getPositionX(), object1->getPositionY(), 512, closeObjects, true); } else { CloseObjectsVector* vec = (CloseObjectsVector*) object1->getCloseObjects(); vec->safeCopyTo(*closeObjects); } if (object1->isCreatureObject()) heightOrigin = getRayOriginPoint(cast<CreatureObject*>(object1)); if (object2->isCreatureObject()) heightEnd = getRayOriginPoint(cast<CreatureObject*>(object2)); rayOrigin.set(rayOrigin.getX(), rayOrigin.getY(), rayOrigin.getZ() + heightOrigin); Vector3 rayEnd = object2->getWorldPosition(); rayEnd.set(rayEnd.getX(), rayEnd.getY(), rayEnd.getZ() + heightEnd); float dist = rayEnd.distanceTo(rayOrigin); float intersectionDistance; Triangle* triangle = NULL; // zone->rlock(); try { for (int i = 0; i < closeObjects->size(); ++i) { AABBTree* aabbTree = NULL; SceneObject* scno = cast<SceneObject*>(closeObjects->get(i).get()); try { aabbTree = getAABBTree(scno, 255); if (aabbTree == NULL) continue; } catch (Exception& e) { aabbTree = NULL; } catch (...) { // zone->runlock(); throw; } if (aabbTree != NULL) { //moving ray to model space // zone->runlock(); try { Ray ray = convertToModelSpace(rayOrigin, rayEnd, scno); //structure->info("checking ray with building dir" + String::valueOf(structure->getDirectionAngle()), true); if (aabbTree->intersects(ray, dist, intersectionDistance, triangle, true)) { return false; } } catch (...) { throw; } // zone->rlock(); } } } catch (Exception& e) { Logger::console.error("unreported exception caught in bool CollisionManager::checkLineOfSight(SceneObject* object1, SceneObject* object2) "); Logger::console.error(e.getMessage()); } // zone->runlock(); ManagedReference<SceneObject*> parent1 = object1->getParent(); ManagedReference<SceneObject*> parent2 = object2->getParent(); if (parent1 != NULL || parent2 != NULL) { CellObject* cell = NULL; if (parent1 != NULL && parent1->isCellObject()) { cell = cast<CellObject*>(parent1.get()); } else if (parent2 != NULL && parent2->isCellObject()) { cell = cast<CellObject*>(parent2.get()); } if (cell != NULL) { return checkLineOfSightWorldToCell(rayOrigin, rayEnd, dist, cell); } } return true; }
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; }