// Sphere Plane Collision - returns true if collsion exists - takes Point3d params bool Collision::SpherePlane(Vector3d& centerSphere, float radiusSphere, Vector3d planeNormal, Point3d p1, Point3d p2, Point3d p3, Point3d p4){ float dist1 = 0.0; float dist2 = 0.0; // this checks for the collsion on both sides of the plane if(RayPlane(planeNormal.getX(), planeNormal.getY(), planeNormal.getZ(), p1.getX(), p1.getY(), p1.getZ(), centerSphere.getX(), centerSphere.getY(), centerSphere.getZ(), -planeNormal.getX(), -planeNormal.getY(), -planeNormal.getZ(), p1, p2, p3, p4, &dist1) || RayPlane(-planeNormal.getX(), -planeNormal.getY(), -planeNormal.getZ(), p1.getX(), p1.getY(), p1.getZ(), centerSphere.getX(), centerSphere.getY(), centerSphere.getZ(), planeNormal.getX(), planeNormal.getY(), planeNormal.getZ(), p1, p2, p3, p4, &dist2)){ if(dist1 > radiusSphere || dist2 > radiusSphere){ // if either distance is > the radiusSphere....no collision return false; } // indicates that we are on the side where dist1 has been determined to be > 0 // the else is the other side of the plane. This calculates the point as well // as the new location of the sphere if(dist1 > 0 ){ centerSphere.setX(centerSphere.getX() + planeNormal.getX() * (radiusSphere - dist1)); centerSphere.setY(centerSphere.getY() + planeNormal.getY() * (radiusSphere - dist1)); centerSphere.setZ(centerSphere.getZ() + planeNormal.getZ() * (radiusSphere - dist1)); }else{ centerSphere.setX(centerSphere.getX() + planeNormal.getX() * (radiusSphere - dist2)); centerSphere.setY(centerSphere.getY() + planeNormal.getY() * (radiusSphere - dist2)); centerSphere.setZ(centerSphere.getZ() + planeNormal.getZ() * (radiusSphere - dist2)); } return true; } return false; }
bool RayTriangle(const Vector3& rayStart, const Vector3& rayDir, const Vector3& triP0, const Vector3& triP1, const Vector3& triP2, float& t, float triExpansionEpsilon) { ++Application::mStatistics.mRayTriangleTests; Math::Vector3 normal = (triP1 - triP0).Cross(triP2 - triP0).Normalized(); if(RayPlane(rayStart, rayDir, Math::Vector4(normal.x, normal.y, normal.z, normal.Dot(triP0)), t)) { Math::Vector3 pointOnPlane = (rayDir * t) + rayStart; Math::Vector3 barycentric; return BarycentricCoordinates(pointOnPlane, triP0, triP1, triP2, barycentric.x, barycentric.y, barycentric.z, triExpansionEpsilon); } return false; }
bool RayAabb(const Vector3& rayStart, const Vector3& rayDir, const Vector3& aabbMin, const Vector3& aabbMax, float& t) { ++Application::mStatistics.mRayAabbTests; if(PointAabb(rayStart, aabbMin, aabbMax)) { t = 0.0f; return true; } std::vector<float> tVals; std::vector<Plane> planes; if(rayDir.x) { planes.emplace_back(Plane(Math::Vector3(aabbMin.x / Math::Abs(aabbMin.x), 0.0f, 0.0f), aabbMin)); planes.emplace_back(Plane(Math::Vector3(aabbMax.x / Math::Abs(aabbMax.x), 0.0f, 0.0f), aabbMax)); tVals.emplace_back(FLT_MAX); tVals.emplace_back(FLT_MAX); } else { if(Math::Clamp(rayStart.x, aabbMin.x, aabbMax.x) != rayStart.x) { return false; } } if(rayDir.y) { planes.emplace_back(Plane(Math::Vector3(0.0f, aabbMin.y / Math::Abs(aabbMin.y), 0.0f), aabbMin)); planes.emplace_back(Plane(Math::Vector3(0.0f, aabbMax.y / Math::Abs(aabbMax.y), 0.0f), aabbMax)); tVals.emplace_back(FLT_MAX); tVals.emplace_back(FLT_MAX); } else { if(Math::Clamp(rayStart.y, aabbMin.y, aabbMax.y) != rayStart.y) { return false; } } if(rayDir.z) { planes.emplace_back(Plane(Math::Vector3(0.0f, 0.0f, aabbMin.z / Math::Abs(aabbMin.z)), aabbMin)); planes.emplace_back(Plane(Math::Vector3(0.0f, 0.0f, aabbMax.z / Math::Abs(aabbMax.z)), aabbMax)); tVals.emplace_back(FLT_MAX); tVals.emplace_back(FLT_MAX); } else { if(Math::Clamp(rayStart.z, aabbMin.z, aabbMax.z) != rayStart.z) { return false; } } for(int i = 0; i < planes.size(); i += 2) { RayPlane(rayStart, rayDir, planes[i].mData, tVals[i]); RayPlane(rayStart, rayDir, planes[i + 1].mData, tVals[i + 1]); //we dot with positive plane axis to get the desired component if(rayDir.Dot(Math::Vector3(planes[i + 1].mData.x, planes[i + 1].mData.y, planes[i + 1].mData.z)) < 0.0f) { std::swap(tVals[i], tVals[i + 1]); } } float tmin = -FLT_MAX; float tmax = FLT_MAX; for(int i = 0; i < tVals.size(); i += 2) { tmin = Math::Max(tmin, tVals[i]); tmax = Math::Min(tmax, tVals[i + 1]); } //tmin should be start of our collision if(tmin < tmax) { if(tmin > 0.0f) { t = tmin; return true; } } return false; }