Ogre::Vector3 CharacterController::_collideWithWorld(int recursionDepth, const Ogre::Vector3& pos, const Ogre::Vector3& vel, CollisionPacket& colData, bool gravityStep, const Ogre::Degree& slopeSlideThresold) { // do we need to worry? if (recursionDepth > 5) return pos; // Ok, we need to worry: colData.velocity = vel; colData.normalizedVelocity = vel; colData.normalizedVelocity.normalise(); colData.basePoint = pos; colData.foundCollision = false; // ---------------------------- // OgreOpcode part begin _doOgreOpcodeCollision(colData, mVeryCloseDistance); // OgreOpcode part end // ---------------------------- // If no collision we just move along the velocity if (colData.foundCollision == false) { return pos + vel; } // *** Collision occured *** // The original destination point Ogre::Vector3 destinationPoint = pos + vel; Ogre::Vector3 newBasePoint = pos; // only update if we are not already very close // and if so we only move very close to intersection..not // to the exact spot. if (colData.nearestDistance >= mVeryCloseDistance) { Ogre::Vector3 V = vel; V.normalise(); V = V * (colData.nearestDistance - mVeryCloseDistance); newBasePoint = colData.basePoint + V; // Adjust polygon intersection point (so sliding // plane will be unaffected by the fact that we // move slightly less than collision tells us) V.normalise(); colData.intersectionPoint -= mVeryCloseDistance * V; } // Determine the sliding plane Ogre::Vector3 slidePlaneOrigin = colData.intersectionPoint; Ogre::Vector3 slidePlaneNormal = newBasePoint - colData.intersectionPoint; slidePlaneNormal.normalise(); Ogre::Plane slidingPlane(slidePlaneNormal, slidePlaneOrigin); Ogre::Vector3 newDestinationPoint = destinationPoint - slidingPlane.getDistance(destinationPoint) * slidePlaneNormal; // Generate the slide vector, which will become our new // velocity vector for the next iteration Ogre::Vector3 newVelocityVector = newDestinationPoint - colData.intersectionPoint; // Recurse: // dont recurse if the new velocity is very small if (newVelocityVector.length() < mVeryCloseDistance) { return newBasePoint; } // simulate "friction" if (gravityStep) { // apply gravity only if slope is steep enough const Ogre::Radian tolerance = Ogre::Radian(slopeSlideThresold); Ogre::Vector3 gravity = vel; gravity.normalise(); if (slidePlaneNormal.directionEquals(-gravity, tolerance)) { return newBasePoint; } } return _collideWithWorld(recursionDepth++, newBasePoint, newVelocityVector, colData, gravityStep, slopeSlideThresold); }
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); }