//------------------------------------------------------- std::pair<bool, Ogre::Vector3> Ground::GetIntersectionLocalSpace(const Ogre::Ray & ray) const { if (ray.intersects(mGlobalBoundingBox).first) { float intersection = -1.0f; for (const auto & region : mEntities) { auto hit = ray.intersects(region->getBoundingBox()); if (hit.first) { auto meshHit = GetVertexIntersection(ray, region->getMesh()->getSubMesh(0)); if (meshHit.first && (intersection < 0.0f || meshHit.second < intersection)) { intersection = meshHit.second; } } } if (intersection >= 0.0f) { return std::make_pair(true, ray.getPoint(intersection)); } } return std::make_pair(false, Ogre::Vector3::ZERO); }
int IntrBox3Sphere3<Real>::FindVertexRegionIntersection (Real ex, Real ey, Real ez, Real cx, Real cy, Real cz, Real vx, Real vy, Real vz, Real& ix, Real& iy, Real& iz) { // Assumes the sphere is above the vertex +ex, +ey, +ez. Real dx = cx - ex; Real dy = cy - ey; Real dz = cz - ez; Real rsqr = mSphere->Radius*mSphere->Radius; Real diff = dx*dx + dy*dy + dz*dz - rsqr; if (diff <= (Real)0) { // Sphere is already intersecting the box. mContactTime = (Real)0; return -1; } if (vx*dx + vy*dy + vz*dz >= (Real)0) { // Sphere not moving towards box. return 0; } // The box can be divided up into 3 regions, which simplifies checking to // see what the sphere hits. The regions are divided by which edge // (formed by the vertex and some axis) is closest to the velocity // vector. // // To check if it hits the vertex, look at the edge (E) it is going // towards. Create a plane formed by the other two edges (with E as the // plane normal) with the vertex at the origin. The intercept along an // axis, in that plane, of the line formed by the sphere center and the // velocity as its direction, will be fCrossAxis/fVEdge. Thus, the // distance from the origin to the point in the plane that that line from // the sphere in the velocity direction crosses will be the squared sum // of those two intercepts. If that sum is less than the radius squared, // then the sphere will hit the vertex otherwise, it will continue on // past the vertex. If it misses, since it is known which edge the box // is near, the find edge region test can be used. // // Also, due to the constrained conditions, only those six cases (two for // each region, since fCrossEdge can be + or -) of signs of fCross values // can occur. // // The 3rd case will also pick up cases where D = V, causing a ZERO cross. Real crossX = vy*dz - vz*dy; Real crossY = vx*dz - vz*dx; Real crossZ = vy*dx - vx*dy; Real crX2 = crossX*crossX; Real crY2 = crossY*crossY; Real crZ2 = crossZ*crossZ; Real vx2 = vx*vx; Real vy2 = vy*vy; Real vz2 = vz*vz; // Intersection with the vertex? if ((crossY < (Real)0 && crossZ >= (Real)0 && crY2 + crZ2 <= rsqr*vx2) || (crossZ < (Real)0 && crossX < (Real)0 && crX2 + crZ2 <= rsqr*vy2) || (crossY >= (Real)0 && crossX >= (Real)0 && crX2 + crY2 <= rsqr*vz2)) { // Standard line-sphere intersection. mContactTime = GetVertexIntersection(dx, dy, dz, vx, vy, vz, mSphere->Radius*mSphere->Radius); ix = mContactTime*vx + cx; iy = mContactTime*vy + cy; iz = mContactTime*vz + cz; return 1; } else if (crossY < (Real)0 && crossZ >= (Real)0) { // x edge region, check y,z planes. return FindEdgeRegionIntersection(ey, ex, ez, cy, cx, cz, vy, vx, vz, iy, ix, iz, false); } else if (crossZ < (Real)0 && crossX < (Real)0) { // y edge region, check x,z planes. return FindEdgeRegionIntersection(ex, ey, ez, cx, cy, cz, vx, vy, vz, ix, iy, iz, false); } else // crossY >= 0 && crossX >= 0 { // z edge region, check x,y planes. return FindEdgeRegionIntersection(ex, ez, ey, cx, cz, cy, vx, vz, vy, ix, iz, iy, false); } }
int IntrBox3Sphere3<Real>::FindJustEdgeIntersection (Real cy, Real ex, Real ey, Real ez, Real dx, Real dz, Real vx, Real vy, Real vz, Real& ix, Real& iy, Real& iz) { // Finds the intersection of a point dx and dz away from an edge with // direction y. The sphere is at a point cy, and the edge is at the // point ex. Checks the edge and the vertex the velocity is heading // towards. Real rsqr = mSphere->Radius*mSphere->Radius; Real dy, crossZ, crossX; // possible edge/vertex intersection int signY; // Depending on the sign of Vy, pick the vertex that the velocity is // heading towards on the edge, as well as creating crossX and crossZ // such that their sign will always be positive if the sphere center goes // over that edge. if (vy >= (Real)0) { signY = 1; dy = cy - ey; crossZ = dx*vy - dy*vx; crossX = dz*vy - dy*vz; } else { signY = -1; dy = cy + ey; crossZ = dy*vx - dx*vy; crossX = dy*vz - dz*vy; } // Check where on edge this intersection will occur. if (crossZ >= (Real)0 && crossX >= (Real)0 && crossX*crossX + crossZ*crossZ > vy*vy*mSphere->Radius*mSphere->Radius) { // Sphere potentially intersects with vertex. Vector3<Real> relVelocity(vx, vy, vz); Vector3<Real> D(dx, dy, dz); Vector3<Real> cross = D.Cross(relVelocity); if (cross.SquaredLength() > rsqr*relVelocity.SquaredLength()) { // Sphere overshoots the box on the vertex. return 0; } // Sphere actually does intersect the vertex. mContactTime = GetVertexIntersection(dx, dy, dz, vx, vy, vz, rsqr); ix = ex; iy = signY*ey; iz = ez; } else { // Sphere intersects with edge. Real vsqrX = vz*vz + vx*vx; mContactTime = GetEdgeIntersection(dx, dz, vx, vz, vsqrX, rsqr); ix = ex; iy = cy + mContactTime*vy; iz = ez; } return 1; }
int IntrBox3Sphere3<Real>::FindFaceRegionIntersection (Real ex, Real ey, Real ez, Real cx, Real cy, Real cz, Real vx, Real vy, Real vz, Real& ix, Real& iy, Real& iz, bool aboveFace) { // Returns when and whether a sphere in the region above face +Z // intersects face +Z or any of its vertices or edges. The input // aboveFace is true when the x and y coordinates are within the x and y // extents. The function will still work if they are not, but it needs // to be false then, to avoid some checks that assume that x and y are // within the extents. This function checks face z, and the vertex and // two edges that the velocity is headed towards on the face. // Check for already intersecting if above face. if (cz <= ez + mSphere->Radius && aboveFace) { mContactTime = (Real)0; return -1; } // Check for easy out (moving away on Z axis). if (vz >= (Real)0) { return 0; } Real rsqr = mSphere->Radius*mSphere->Radius; Real vsqrX = vz*vz + vx*vx; Real vsqrY = vz*vz + vy*vy; Real dx, dy, dz = cz - ez; Real crossX, crossY; int signX, signY; // This determines which way the box is heading and finds the values of // CrossX and CrossY which are positive if the sphere center will not // pass through the box. Then it is only necessary to check two edges, // the face and the vertex for intersection. if (vx >= (Real)0) { signX = 1; dx = cx - ex; crossX = vx*dz - vz*dx; } else { signX = -1; dx = cx + ex; crossX = vz*dx - vx*dz; } if (vy >= (Real)0) { signY = 1; dy = cy - ey; crossY = vy*dz - vz*dy; } else { signY = -1; dy = cy + ey; crossY = vz*dy - vy*dz; } // Does the circle intersect along the x edge? if (crossX > mSphere->Radius*vx*signX) { if (crossX*crossX > rsqr*vsqrX) { // Sphere overshoots box on the x-axis (either side). return 0; } // Does the circle hit the y edge? if (crossY > mSphere->Radius*vy*signY) { // Potential vertex intersection. if (crossY*crossY > rsqr*vsqrY) { // Sphere overshoots box on the y-axis (either side). return 0; } Vector3<Real> relVelocity(vx,vy,vz); Vector3<Real> D(dx,dy,dz); Vector3<Real> cross = D.Cross(relVelocity); if (cross.SquaredLength() > rsqr*relVelocity.SquaredLength()) { // Sphere overshoots the box on the corner. return 0; } mContactTime = GetVertexIntersection(dx, dy, dz, vx, vy, vz, rsqr); ix = ex*signX; iy = ey*signY; } else { // x-edge intersection mContactTime = GetEdgeIntersection(dx, dz, vx, vz, vsqrX, rsqr); ix = ex*signX; iy = cy + vy*mContactTime; } } else { // Does the circle hit the y edge? if (crossY > mSphere->Radius*vy*signY) { // Potential y-edge intersection. if (crossY*crossY > rsqr*vsqrY) { // Sphere overshoots box on the y-axis (either side). return 0; } mContactTime = GetEdgeIntersection(dy, dz, vy, vz, vsqrY, rsqr); ix = cx + vx*mContactTime; iy = ey*signY; } else { // Face intersection (easy). mContactTime = (-dz + mSphere->Radius)/vz; ix = mContactTime*vx + cx; iy = mContactTime*vy + cy; } } // z coordinate of any intersection must be the face of z. iz = ez; return 1; }