bool CheckRay(const CRay& ray, const CPlane& plane, Vector3* hitPoint) { //This algorithm is based on the plane equation we saw in the CheckPlane methods float planeRayDirection = plane.GetNormal().Dot(ray.GetDirection()); if (planeRayDirection == 0) { return false; } //The equation is between the plane normal and the ray origin. It is also divided by the dot product of the plane normal and ray direction float t = -(plane.GetNormal().Dot(ray.GetOrigin()) + plane.GetDistance()) / planeRayDirection; //If the result of the equation is negative then there is no hit if (t < 0) { return false; } if (hitPoint) { //Here we calculate the point where the ray hits the plane Vector3 pointOnPlane = (ray.GetDirection() * t) + ray.GetOrigin(); hitPoint->x = pointOnPlane.x; hitPoint->y = pointOnPlane.y; hitPoint->z = pointOnPlane.z; } return true; }
bool CheckRay(const CRay& ray, const CBoundingBox& bb, Vector3* hitPoint) { //This algorithm is adapted from: http://tavianator.com/fast-branchless-raybounding-box-intersections/ //Its based on the "Slab Technique" which treats a bounding box as a series of 2 planes in each axis. //It finds where the ray lies on each of these planes and compares those values across each axis. float tmin = -INFINITY; float tmax = INFINITY; float tx1 = (bb.GetMin().x - ray.GetOrigin().x) / ray.GetDirection().x; float tx2 = (bb.GetMax().x - ray.GetOrigin().x) / ray.GetDirection().x; tmin = max(tmin, min(tx1, tx2)); tmax = min(tmax, max(tx1, tx2)); float ty1 = (bb.GetMin().y - ray.GetOrigin().y) / ray.GetDirection().y; float ty2 = (bb.GetMax().y - ray.GetOrigin().y) / ray.GetDirection().y; tmin = max(tmin, min(ty1, ty2)); tmax = min(tmax, max(ty1, ty2)); float tz1 = (bb.GetMin().z - ray.GetOrigin().z) / ray.GetDirection().z; float tz2 = (bb.GetMax().z - ray.GetOrigin().z) / ray.GetDirection().z; tmin = max(tmin, min(tz1, tz2)); tmax = min(tmax, max(tz1, tz2)); //We end up with two hit values just like the sphere, if the max hit is less than 0 then it all happened behind the ray origin if (tmax < 0) return false; //If the max hit value is greater than the min hit (as it should be) then we have a hit! if (tmax >= tmin) { if (hitPoint) { //If we need to know the first hit point on the box then we should use tmin, unless it's negative then we use tmax. //This would come up in situations where the origin of the ray is within the box. float firstHitDistance = tmin < 0 ? tmax : tmin; Vector3 pointOnBox = (ray.GetDirection() * firstHitDistance) + ray.GetOrigin(); hitPoint->x = pointOnBox.x; hitPoint->y = pointOnBox.y; hitPoint->z = pointOnBox.z; } return true; } return false; }
bool CheckRay(const CRay& ray, const CBoundingSphere& sphere, Vector3* hitPoint) { //This algorithm is adatped from: http://www.cosinekitty.com/raytrace/chapter06_sphere.html //It breaks the problem down into the plane equations needed to find the hit points between the ray and sphere //To solve this correctly it makes use of a quadratic equation. Vector3 displacement = ray.GetOrigin() - sphere.GetCenter(); float a = ray.GetDirection().LengthSquared(); float b = 2.0f * displacement.Dot(ray.GetDirection()); float c = displacement.LengthSquared() - sphere.GetRadius() * sphere.GetRadius(); float randicand = b*b - 4.0f * a * c; //If the quadratic equation comes back as a negitive then there is no hit. if (randicand < 0.0f) { return false; } float root = sqrt(randicand); float denom = 2.0 * a; //Here we calculate the distance between ray origin and the two hit points (where the ray enters the sphere and where it exits) float hit1 = (-b + root) / denom; float hit2 = (-b - root) / denom; //If both of the hits are negitive then it means that the sphere is behind the origin of the ray so there is no hit if (hit1 < 0 && hit2 < 0) { return false; } if (hitPoint) { //If we need to know the first hit point on the sphere then we should use hit1, unless it's negative then we use hit2. //This would come up in situations where the origin of the ray is within the sphere. float firstHitDistance = hit1 < 0 ? hit2 : hit1; Vector3 pointOnSphere = (ray.GetDirection() * firstHitDistance) + ray.GetOrigin(); hitPoint->x = pointOnSphere.x; hitPoint->y = pointOnSphere.y; hitPoint->z = pointOnSphere.z; } return true; }
bool CSphere::Intersect(const CRay& clRay, RealType t0, RealType t1, TTracingContext& tContext ) const { /* Implement ray-sphere intersection. You must set the following member of the TTracingContext struct: t - ray parameter of intersection point v3Normal - Normal of surface at intersection point v3HitPoint - Coordinate of intersection point v2TexCoord - 2D-Texture coordinate of intersection point (use polar coordinates (method Cartesian2Polar), not needed currently) pclShader - Material of sphere */ VectorType3 vecDiff(m_v3Center - clRay.GetOrigin()); RealType t_ca = vecDiff | clRay.GetDir(); if (t_ca < 0) return false; RealType d2 = (vecDiff | vecDiff) - t_ca * t_ca; RealType r2 = m_rRadius * m_rRadius ; if (d2 > r2) { return false; } RealType desc = sqrt(r2 - d2); RealType t = (t_ca - desc) ; if (t < 0.0) { t = (t_ca + desc); } if (t > tContext.t) { return false; } tContext.t = t; tContext.v3HitPoint = clRay.Evaluate(tContext.t); tContext.v3Normal = (tContext.v3HitPoint - m_v3Center).normalize(); tContext.pclShader = GetShader(); return true; }