//! Collides a moving ellipsoid with a 3d world with gravity and returns //! the resulting new position of the ellipsoid. core::vector3df CSceneCollisionManager::collideEllipsoidWithWorld( ITriangleSelector* selector, const core::vector3df &position, const core::vector3df& radius, const core::vector3df& velocity, f32 slidingSpeed, const core::vector3df& gravity, core::triangle3df& triout, bool& outFalling) { if (!selector || radius.X == 0.0f || radius.Y == 0.0f || radius.Z == 0.0f) return position; // This code is based on the paper "Improved Collision detection and Response" // by Kasper Fauerby, but some parts are modified. SCollisionData colData; colData.R3Position = position; colData.R3Velocity = velocity; colData.eRadius = radius; colData.nearestDistance = 9999999999999.0f; colData.selector = selector; colData.slidingSpeed = slidingSpeed; colData.triangleHits = 0; core::vector3df eSpacePosition = colData.R3Position / colData.eRadius; core::vector3df eSpaceVelocity = colData.R3Velocity / colData.eRadius; // iterate until we have our final position core::vector3df finalPos = collideWithWorld( 0, colData, eSpacePosition, eSpaceVelocity); outFalling = false; // add gravity if (gravity != core::vector3df(0,0,0)) { colData.R3Position = finalPos * colData.eRadius; colData.R3Velocity = gravity; colData.triangleHits = 0; eSpaceVelocity = gravity/colData.eRadius; finalPos = collideWithWorld(0, colData, finalPos, eSpaceVelocity); outFalling = (colData.triangleHits == 0); } if (colData.triangleHits) { triout = colData.intersectionTriangle; triout.pointA *= colData.eRadius; triout.pointB *= colData.eRadius; triout.pointC *= colData.eRadius; } finalPos *= colData.eRadius; return finalPos; }
bool Bullet::Update(const std::vector<std::string>& levelData, float deltaTime) { _position += _direction * _speed * deltaTime; return collideWithWorld(levelData); }
core::vector3df CSceneCollisionManager::collideWithWorld(s32 recursionDepth, SCollisionData &colData, core::vector3df pos, core::vector3df vel) { f32 veryCloseDistance = colData.slidingSpeed; if (recursionDepth > 5) return pos; colData.velocity = vel; colData.normalizedVelocity = vel; colData.normalizedVelocity.normalize(); colData.basePoint = pos; colData.foundCollision = false; colData.nearestDistance = 9999999999999.0f; //------------------ collide with world // get all triangles with which we might collide core::aabbox3d<f32> box(colData.R3Position); box.addInternalPoint(colData.R3Position + colData.R3Velocity); box.MinEdge -= colData.eRadius; box.MaxEdge += colData.eRadius; s32 totalTriangleCnt = colData.selector->getTriangleCount(); Triangles.set_used(totalTriangleCnt); core::matrix4 scaleMatrix; scaleMatrix.setScale( core::vector3df(1.0f / colData.eRadius.X, 1.0f / colData.eRadius.Y, 1.0f / colData.eRadius.Z) ); s32 triangleCnt = 0; colData.selector->getTriangles(Triangles.pointer(), totalTriangleCnt, triangleCnt, box, &scaleMatrix); //colData.selector->getTriangles(Triangles.pointer(), totalTriangleCnt, triangleCnt, &scaleMatrix); for (s32 i=0; i<triangleCnt; ++i) testTriangleIntersection(&colData, Triangles[i]); //---------------- end collide with world if (!colData.foundCollision) return pos + vel; // original destination point core::vector3df destinationPoint = pos + vel; core::vector3df newBasePoint = pos; // only update if we are not already very close // and if so only move very close to intersection, not to the // exact point if (colData.nearestDistance >= veryCloseDistance) { core::vector3df v = vel; v.setLength( colData.nearestDistance - veryCloseDistance ); newBasePoint = colData.basePoint + v; v.normalize(); colData.intersectionPoint -= (v * veryCloseDistance); } // calculate sliding plane core::vector3df slidePlaneOrigin = colData.intersectionPoint; core::vector3df slidePlaneNormal = newBasePoint - colData.intersectionPoint; slidePlaneNormal.normalize(); core::plane3d<f32> slidingPlane(slidePlaneOrigin, slidePlaneNormal); core::vector3df newDestinationPoint = destinationPoint - (slidePlaneNormal * slidingPlane.getDistanceTo(destinationPoint)); // generate slide vector core::vector3df newVelocityVector = newDestinationPoint - colData.intersectionPoint; if (newVelocityVector.getLength() < veryCloseDistance) return newBasePoint; return collideWithWorld(recursionDepth+1, colData, newBasePoint, newVelocityVector); }