bool Collision::AABB_vs_AABB(const AABB& a, const AABB& b, Vector *v) { const Vector a_upleft = a.upleft(); const Vector a_downright = a.downright(); const Vector b_upleft = b.upleft(); const Vector b_downright = b.downright(); bool c = !(a_downright.y < b_upleft.y || a_upleft.y > b_downright.y || a_downright.x < b_upleft.x || a_upleft.x > b_downright.x); if(c && v) { AABB ov = a.getOverlap(b); *v = ov.getCenter(); } return c; }
// If AABB intersects the frustum, an output clip mask is returned as well (indicating which // planes are crossed by the AABB). This information can be used to optimize testing of // child nodes or objects inside the nodes (pass value as 'inClipMask'). bool intersectAABBFrustum (const AABB& a, const Vector4* p, unsigned int& outClipMask, unsigned int inClipMask) { Vector3 m = a.getCenter(); // center of AABB Vector3 d = a.getMax() - m; // half-diagonal unsigned int mk = 1; outClipMask = 0; // init outclip mask while (mk <= inClipMask){ // loop while there are active planes.. if (inClipMask&mk){ // if clip plane is active... float NP = (float)(d.x*fabs(p->x)+d.y*fabs(p->y)+d.z*fabs(p->z)); float MP = m.x*p->x+m.y*p->y+m.z*p->z+p->w; if ((MP+NP) < 0.0f) return false; // behind clip plane if ((MP-NP) < 0.0f) outClipMask |= mk; } mk+=mk; // mk = (1<<iter) p++; // next plane } return true; // AABB intersects frustum }
PhysicsInterface::BodyObject Bullet::createBoundingBoxBody(const AABB& aabb, float mass, bool fixed, const Entity* entity, const SimpleTransform& initialTransform) { auto collisionShape = new btBoxShape(toBullet((aabb.getMaximum() - aabb.getMinimum()) * 0.5f)); // Calculate inertia auto localInertia = btVector3(0.0f, 0.0f, 0.0f); if (!fixed) collisionShape->calculateLocalInertia(mass, localInertia); // Motion state for this body auto motionState = new btDefaultMotionState(toBullet(initialTransform), btTransform(btQuaternion::getIdentity(), toBullet(aabb.getCenter()))); // Create Bullet rigid body auto bulletBody = new btRigidBody( btRigidBody::btRigidBodyConstructionInfo(fixed ? 0.0f : mass, motionState, collisionShape, localInertia)); bulletBody->setDamping(DefaultLinearDamping, DefaultAngularDamping); bulletBody->setSleepingThresholds(DefaultLinearSleepingThreshold, DefaultAngularSleepingThreshold); bulletBody->setRestitution(0.0f); // Add body to the simulation dynamicsWorld_->addRigidBody(bulletBody); // Create local body auto body = new Body(bulletBody, entity, fixed); bodies_.append(body); body->ownedCollisionShape = collisionShape; bulletBody->setUserPointer(body); return body; }
void Transform::setByBounds(AABB bounds) { pos = bounds.getCenter(); scale = bounds.getSize(); needUpdate = true; }
void wiSPTree::getVisible(Node* node, AABB& frustum, CulledList& objects, SortType sort, CullStrictness type){ if(!node) return; int contain_type = frustum.intersects(node->box); if(!contain_type) return; else{ for(Cullable* object : node->objects) if( type==SP_TREE_LOOSE_CULL || (type==SP_TREE_STRICT_CULL && contain_type==AABB::INSIDE || (contain_type==INTERSECTS && frustum.intersects(object->bounds)) ) ){ #ifdef SORT_SPTREE_CULL object->lastSquaredDistMulThousand=(long)(wiMath::Distance(object->bounds.getCenter(),frustum.getCenter())*1000); if (sort == SP_TREE_SORT_PAINTER) object->lastSquaredDistMulThousand *= -1; #endif objects.insert(object); } if(node->count){ for (unsigned int i = 0; i<node->children.size(); ++i) getVisible(node->children[i],frustum,objects, sort,type); } } }
//Now that the cells are created, associate each model to one or more cells of the scene. void PVSGenerator::addModelsToCells(const vector<shared_ptr<Cell>>& cells, VoxelContainer& voxelContainer, const AABB sceneAABB) { const Vector3f voxelSize = voxelContainer.getVoxelSize(); vector<Point3i> cellExternalIndices; vector<Triangle> triangles; AABB voxelAABB; Vector3f voxelMidPoint; float boxHalfSize[3]; float triverts[3][3]; float boxCenter[3]; for( unsigned int c = 0 ; c < cells.size() ; ++c) { Point3i minIndex = cells[c]->minPoint; Point3i maxIndex = cells[c]->maxPoint; //Convert the AABB to world space. AABB cellAABB( Vector3f ( minIndex.x * voxelSize.x + sceneAABB.minPoint.x, minIndex.y * voxelSize.y + sceneAABB.minPoint.y, minIndex.z * voxelSize.z + sceneAABB.minPoint.z ), Vector3f ( maxIndex.x * voxelSize.x + sceneAABB.minPoint.x + voxelSize.x, maxIndex.y * voxelSize.y + sceneAABB.minPoint.y + voxelSize.y, maxIndex.z * voxelSize.z + sceneAABB.minPoint.z + voxelSize.z)); AABB modelAABB; //For each Occludee for( int i = 0; i < scene.getModelInstancesCount() ; ++i) { //TODO: very heavy operation, try to cache it somewhere. modelAABB = scene.getModelInstance(i).getModelAABB(); //Check if model is inside the cell. If so, add it to the cell model list. if( scene.getModelInstance(i).getModelType() == OCCLUDEE) { if( CollisionUtils::boxBoxOverlapTest( modelAABB.minPoint.vec, modelAABB.maxPoint.vec, cellAABB.minPoint.vec, cellAABB.maxPoint.vec)) cells[c]->addModelId( scene.getModelInstance(i).getModelId() ); } } //Calculate the occluders. //Occluders are treated differently from the occludees. Occluders don't collide with cells directly because they are where solid voxels are. //Because of this, we have to test the cell external voxels against the actual occluder geometry. //Get all the external voxels of the cell. cellExternalIndices.clear(); getCellExternalVoxels( *(cells[c]), cellExternalIndices); //Calculate the voxel's half size in x, y and z. boxHalfSize[0] = voxelSize.x / 2.0f; boxHalfSize[1] = voxelSize.y / 2.0f; boxHalfSize[2] = voxelSize.z / 2.0f; //For each external voxel of this cell, see if there is any occluder that collides with it. for( unsigned int i = 0 ; i < cellExternalIndices.size() ; ++i) { //Only consider solid external voxels because they have geometry there. if( voxelContainer.voxelAt(cellExternalIndices[i]).getStatus() != Voxel::SOLID ) continue; //Go for each occluder and test for collision. for( int k = 0; k < scene.getModelInstancesCount() ; ++k) { //If it is occluder and it is not yet associated with the cell... if( scene.getModelInstance(k).getModelType() == OCCLUDER && cells[c]->isModelIdInCell(scene.getModelInstance(k).getModelId()) == false ) { //TODO: very heavy operation, try to cache it somewhere. modelAABB = scene.getModelInstance(k).getModelAABB(); voxelAABB = voxelContainer.getVoxelAABBFromIndex(cellExternalIndices[i], sceneAABB); //If collides with AABB of the voxel then we can test at polygon level. if( CollisionUtils::boxBoxOverlapTest( modelAABB.minPoint.vec, modelAABB.maxPoint.vec, voxelAABB.minPoint.vec, voxelAABB.maxPoint.vec)) { triangles.clear(); //Transform the model space triangle to world space. scene.getModelInstance(k).getModelTrianglesWorldSpace(triangles); voxelMidPoint = voxelAABB.getCenter(); boxCenter[0] = voxelMidPoint.x; boxCenter[1] = voxelMidPoint.y; boxCenter[2] = voxelMidPoint.z; for( unsigned int t = 0 ; t < triangles.size() ; ++t) { //Store the triangle in a format that the colission algorithm can receive. triverts[0][0] = triangles[t].a.x; triverts[0][1] = triangles[t].a.y; triverts[0][2] = triangles[t].a.z; triverts[1][0] = triangles[t].b.x; triverts[1][1] = triangles[t].b.y; triverts[1][2] = triangles[t].b.z; triverts[2][0] = triangles[t].c.x; triverts[2][1] = triangles[t].c.y; triverts[2][2] = triangles[t].c.z; //Test for intersection between the triangle and the voxel's AABB. if(CollisionUtils::triBoxOverlap(boxCenter, boxHalfSize, triverts) == 1) { cells[c]->addModelId( scene.getModelInstance(k).getModelId() ); break; } } } } } } //Log progress if( c % ( (cells.size() / 10) + 1) == 0 ) //Show 10% increments. { std::stringstream str; str << "Models to Cells %: " << ((float) c / cells.size()) * 100.0f; Logger::Log( str.str() ); } } }
bool OBB::collision(const CollisionObject * pCollisionObject, bool calculateNormal) { if(pCollisionObject->getCollisionType()==CollisionType_OBB) { OBB * pOBB = (OBB*) pCollisionObject; for(unsigned int aIndex=0; aIndex<3; aIndex++) { D3DXVECTOR3 axis = mAxis[aIndex]; float min1 = 1000000.0f; float max1 = -1000000.0f; float min2 = 1000000.0f; float max2 = -1000000.0f; for(unsigned int cIndex=0; cIndex<8; cIndex++) { float pos = D3DXVec3Dot(&axis, &mCorners[cIndex]);// axis.x * mCorners[cIndex].x + axis.y * mCorners[cIndex].y + axis.z * mCorners[cIndex].z; if(pos < min1) { min1 = pos; } else if(pos > max1) { max1 = pos; } } for(unsigned int cIndex=0; cIndex<8; cIndex++) { D3DXVECTOR3 corner = pOBB->getCorner(cIndex); float pos = D3DXVec3Dot(&axis, &corner);//axis.x * corner.x + axis.y * corner.y + axis.z * corner.z; if(pos < min2) { min2 = pos; } else if(pos > max2) { max2 = pos; } } if(max1 < min2 || min1 > max2) { return false; } } for(unsigned int aIndex=0; aIndex<3; aIndex++) { D3DXVECTOR3 axis = pOBB->getAxis(aIndex); float min1 = 1000000.0f; float max1 = -1000000.0f; float min2 = 1000000.0f; float max2 = -1000000.0f; for(unsigned int cIndex=0; cIndex<8; cIndex++) { float pos = D3DXVec3Dot(&axis, &mCorners[cIndex]);//axis.x * mCorners[cIndex].x + axis.y * mCorners[cIndex].y + axis.z * mCorners[cIndex].z; if(pos < min1) { min1 = pos; } else if(pos > max1) { max1 = pos; } } for(unsigned int cIndex=0; cIndex<8; cIndex++) { D3DXVECTOR3 corner = pOBB->getCorner(cIndex); float pos = D3DXVec3Dot(&axis, &corner);//axis.x * corner.x + axis.y * corner.y + axis.z * corner.z; if(pos < min2) { min2 = pos; } else if(pos > max2) { max2 = pos; } } if(max1 < min2 || min1 > max2) { return false; } } if(calculateNormal) { setCollisionNormal(pOBB->getCenter() - mCenter); pOBB->setCollisionNormal(mCenter - pOBB->getCenter()); } return true; } else if(pCollisionObject->getCollisionType()==CollisionType_AABB) { AABB * pAABB = (AABB*) pCollisionObject; D3DXVECTOR3 aabbAxis[3]; aabbAxis[0] = D3DXVECTOR3(1,0,0); aabbAxis[1] = D3DXVECTOR3(0,1,0); aabbAxis[2] = D3DXVECTOR3(0,0,1); for(int aIndex=0;aIndex<3;aIndex++) { float min1 = 1000000; float max1 = -1000000; float min2 = 1000000; float max2 = -1000000; for(int cIndex=0;cIndex<8;cIndex++) { //D3DXVECTOR3 corner = pAABB->getCorner(cIndex); //float pos = mAxis[aIndex].x * mCorners[cIndex].x + mAxis[aIndex].y * mCorners[cIndex].y + mAxis[aIndex].z * mCorners[cIndex].z; float pos = D3DXVec3Dot(&mAxis[aIndex], &mCorners[cIndex]); if(pos < min1) { min1 = pos; } else if(pos > max1) { max1 = pos; } } for(int cIndex=0;cIndex<8;cIndex++) { D3DXVECTOR3 corner = pAABB->getCorner(cIndex); //float pos = mAxis[aIndex].x * aabbCorners[cIndex].x + mAxis[aIndex].y * aabbCorners[cIndex].y + mAxis[aIndex].z * aabbCorners[cIndex].z; float pos = D3DXVec3Dot(&mAxis[aIndex], &corner); if(pos < min2) { min2 = pos; } else if(pos > max2) { max2 = pos; } } if(max1 < min2 || max2 < min1) { return false; } } for(int aIndex=0;aIndex<3;aIndex++) { float min1 = 1000000; float max1 = -1000000; float min2 = 1000000; float max2 = -1000000; for(int cIndex=0;cIndex<8;cIndex++) { //D3DXVECTOR3 corner = pAABB->getCorner(cIndex); //float pos = aabbAxis[aIndex].x * mCorners[cIndex].x + aabbAxis[aIndex].y * mCorners[cIndex].y + aabbAxis[aIndex].z * mCorners[cIndex].z; float pos = D3DXVec3Dot(&aabbAxis[aIndex], &mCorners[cIndex]); if(pos < min1) { min1 = pos; } else if(pos > max1) { max1 = pos; } } for(int cIndex=0;cIndex<8;cIndex++) { D3DXVECTOR3 corner = pAABB->getCorner(cIndex); //float pos = aabbAxis[aIndex].x * aabbCorners[cIndex].x + aabbAxis[aIndex].y * aabbCorners[cIndex].y + aabbAxis[aIndex].z * aabbCorners[cIndex].z; float pos = D3DXVec3Dot(&aabbAxis[aIndex], &corner); if(pos < min2) { min2 = pos; } else if(pos > max2) { max2 = pos; } } if(max1 < min2 || max2 < min1) { return false; } } if(calculateNormal) { setCollisionNormal(pAABB->getCenter() - mCenter); pAABB->setCollisionNormal(mCenter - pAABB->getCenter()); } return true; } else if(pCollisionObject->getCollisionType()==CollisionType_Sphere) { Sphere * pSphere = (Sphere*) pCollisionObject; for(int aIndex=0;aIndex<3;aIndex++) { float min1 = 1000000; float max1 = -1000000; float min2 = 1000000; float max2 = -1000000; for(int cIndex=0;cIndex<8;cIndex++) { float pos = mAxis[aIndex].x * mCorners[cIndex].x + mAxis[aIndex].y * mCorners[cIndex].y + mAxis[aIndex].z * mCorners[cIndex].z; if(pos < min1) { min1 = pos; } else if(pos > max1) { max1 = pos; } } min2 = mAxis[aIndex].x * pSphere->getX() + mAxis[aIndex].y * pSphere->getY() + mAxis[aIndex].z * pSphere->getZ() - pSphere->getR(); max2 = mAxis[aIndex].x * pSphere->getX() + mAxis[aIndex].y * pSphere->getY() + mAxis[aIndex].z * pSphere->getZ() + pSphere->getR(); if(max1 < min2 || min1 > max2) { return false; } } D3DXVECTOR3 obbToSphere = D3DXVECTOR3(pSphere->getX(),pSphere->getY(),pSphere->getZ()); obbToSphere -= mCenter; float length = obbToSphere.x * obbToSphere.x + obbToSphere.y * obbToSphere.y + obbToSphere.z * obbToSphere.z; length = sqrt(length); obbToSphere /= length; float min1 = 1000000; float max1 = -1000000; float min2 = 1000000; float max2 = -1000000; for(int cIndex=0;cIndex<8;cIndex++) { float pos = obbToSphere.x * mCorners[cIndex].x + obbToSphere.y * mCorners[cIndex].y + obbToSphere.z * mCorners[cIndex].z; if(pos < min1) { min1 = pos; } else if(pos > max1) { max1 = pos; } } min2 = obbToSphere.x * pSphere->getX() + obbToSphere.y * pSphere->getY() + obbToSphere.z * pSphere->getZ() - pSphere->getR(); max2 = obbToSphere.x * pSphere->getX() + obbToSphere.y * pSphere->getY() + obbToSphere.z * pSphere->getZ() + pSphere->getR(); if(max1 < min2 || min1 > max2) { return false; } if(calculateNormal) { D3DXVECTOR3 sphereCenter = D3DXVECTOR3(pSphere->getX(), pSphere->getY(), pSphere->getZ()); setCollisionNormal(sphereCenter - mCenter); pSphere->setCollisionNormal(mCenter - sphereCenter); } return true; } return false; }