RayIntersection SpatialList::rayIntersection(Ray ray) const { if (objectsVector.empty() || (boundingBox && !boundingBox->rayIntersection(ray).intersects)) return RayIntersection(); RayIntersection first_intersection = RayIntersection(); for (unsigned int i = 0; i < objectsVector.size(); i++) { RayIntersection intersection = objectsVector[i]->rayIntersection(ray); if (intersection.intersects && (!first_intersection.intersects || intersection < first_intersection)) { first_intersection = intersection; } } return first_intersection; }
RayIntersection Sphere::intersectWithRay(const Ray &ray) const { // Solve square equation x^2 + b * x + c = 0 Vector cameraToRayOrigin = ray.getOriginPosition() - mCenter; float b = ray.getDirection().dotProduct(cameraToRayOrigin); float c = cameraToRayOrigin.dotProduct(cameraToRayOrigin) - mRadius * mRadius; float descriminant = b * b - c; if (descriminant < 0) { return RayIntersection(); } descriminant = sqrt(descriminant); std::vector<float> intersectionDistances; float closestRoot = -1.f; // Get closest root float root = -b - descriminant; float rayExit = -1.f; if (root >= 0.f) { closestRoot = root; intersectionDistances.push_back(root); } root = -b + descriminant; if (root >= 0.f) { intersectionDistances.push_back(root); if (closestRoot < 0.f) { closestRoot = root; } else if (root < closestRoot) { rayExit = closestRoot; closestRoot = root; } else { rayExit = root; } } if (closestRoot > 0.f) { if (rayExit < 0.f) { intersectionDistances.insert(intersectionDistances.begin(), 0.f); } SpherePointer pointer = SpherePointer(new Sphere(*this)); return RayIntersection(true, pointer, closestRoot, getNormal(ray, closestRoot), intersectionDistances); } return RayIntersection(); }
std::vector<RayIntersection> FastArc::RayIntersects(gp_Pnt p) { std::vector<RayIntersection> ret; double y = p.Y() - C.Y(); if(fabs(y) > rad) return ret; double x1 = sqrt(rad*rad - y*y); double x2 = x1+C.X(); x1 = C.X()-x1; if(x1 < p.X()) ret.push_back(RayIntersection(GetU(x1,p.Y()),gp_Pnt(x1,p.Y(),0),false,false)); if(x2 < p.X()) ret.push_back(RayIntersection(GetU(x2,p.Y()),gp_Pnt(x2,p.Y(),0),false,false)); return ret; }
RayIntersection Plane::intersectWithRay(const Ray &ray) const { float cosineRayNormal = mNormal.dotProduct(ray.getDirection()); if (fabs(cosineRayNormal) < FLOAT_ZERO) { return RayIntersection(); } float distance = -(ray.getOriginPosition().dotProduct(mNormal) + mDistance) / cosineRayNormal; if (distance > 0.0) { PlanePointer pointer = PlanePointer(new Plane(*this)); std::vector<float> intersectionDistances; intersectionDistances.push_back(distance); return RayIntersection(true, pointer, distance, getNormal(ray, distance), intersectionDistances); } return RayIntersection(); }
RayIntersection TrianglePatch::intersectWithRay(const Ray &ray) const { Vector rayOrigin = ray.getOriginPosition(); Vector rayDirection = ray.getDirection(); Vector e1 = mVertex1->getCoordinates() - mVertex0->getCoordinates(); Vector e2 = mVertex2->getCoordinates() - mVertex0->getCoordinates(); Vector pvector = rayDirection.crossProduct(e2); float determinant = e1.dotProduct(pvector); if (fabs(determinant) < FLOAT_ZERO) { return RayIntersection(); } const float invertedDeterminant = 1.0f / determinant; Vector tvec = rayOrigin - mVertex0->getCoordinates(); float lambda = tvec.dotProduct(pvector); lambda *= invertedDeterminant; if (lambda < 0.0f || lambda > 1.0f) { return RayIntersection(); } Vector qvec = tvec.crossProduct(e1); float mue = rayDirection.dotProduct(qvec); mue *= invertedDeterminant; if (mue < 0.0f || mue + lambda > 1.0f) { return RayIntersection(); } float f = e2.dotProduct(qvec); f = f * invertedDeterminant - FLOAT_ZERO; if (f < FLOAT_ZERO) { return RayIntersection(); } TrianglePatchPointer pointer = TrianglePatchPointer(new TrianglePatch(*this)); return RayIntersection(true, pointer, f, lambda, mue); }
bool Sphere::closestIntersectionModel(const Ray &ray, double maxLambda, RayIntersection& intersection) const { // Implicit sphere: (x-c)^2-r^2 = 0 // r = 1, c=0 // x^2 = 1 // Ray: x = o+t*d // Solve: 0=(o+t*d)^2 -1 // 0 = t^2*(d*d) + t*(2*o*d) + (o*o-1) // Then, these are the 2 possible solutions // t0 = 0.5*(-b-sqrt(b*b - 4*a)) // simplify // t01 = -o.d +- sqrt( (o.d)^2 - o.o + 1) const Vec3d &d = ray.direction(); const Vec3d &o = ray.origin(); double b = dot(o,d); double c = o.lengthSquared() - 1; double ds = b*b - c; //discriminant is negative, no intersection if(ds < 0) return false; double dssqr = sqrt(ds); double t0 = -b-dssqr; double t1 = -b+dssqr; double lambda = t0; //ray starts inside sphere, discard first hit if(t0 < 0) lambda = t1; if(lambda < 0 || lambda > maxLambda) return false; // Compute intersection point const Vec3d p = ray.pointOnRay(lambda); // Compute parameterization of intersection point const double theta = std::atan2(p[1], p[0]); const double phi = std::acos (p[2]); const Vec3d uvw(theta,phi,double(0)); intersection = RayIntersection(ray,shared_from_this(),lambda,ray.pointOnRay(lambda),uvw); return true; }
bool IndexedTriangleMesh::closestIntersectionModel(const Ray &ray, double maxLambda, RayIntersection& intersection) const { double closestLambda = maxLambda; Vec3d closestbary; int closestTri = -1; Vec3d bary; double lambda; // Loop over all stored triangles to find a possible intersection between ray // and any triangle for (size_t i=0;i<mIndices.size();i+=3) { const int i0 = mIndices[i+0]; const int i1 = mIndices[i+1]; const int i2 = mIndices[i+2]; if (Intersection::lineTriangle(ray,mVertexPosition[i0],mVertexPosition[i1],mVertexPosition[i2],bary,lambda) && lambda > 0 && lambda < closestLambda) { closestLambda = lambda; closestbary = bary; closestTri = (int)i; } } // If an intersection occurred, compute the normal and the uv coordinates based // on the barycentric coordinates of the hit point if (closestTri >= 0) { const int i0 = mIndices[closestTri+0]; const int i1 = mIndices[closestTri+1]; const int i2 = mIndices[closestTri+2]; Vec3d n; if(mVertexNormal.empty()) n = cross(mVertexPosition[i1]-mVertexPosition[i0],mVertexPosition[i2]-mVertexPosition[i0]).normalize(); else n = (mVertexNormal[i0]*closestbary[0]+ mVertexNormal[i1]*closestbary[1]+ mVertexNormal[i2]*closestbary[2]).normalize(); Vec3d uvw(0,0,0); if(!mVertexTextureCoordinate.empty()) uvw = (mVertexTextureCoordinate[i0]*closestbary[0]+ mVertexTextureCoordinate[i1]*closestbary[1]+ mVertexTextureCoordinate[i2]*closestbary[2]); intersection=RayIntersection(ray,shared_from_this(),closestLambda,n,uvw); return true; } return false; }
bool CollisionGeometry::closestIntersectionModel(const Ray &ray, float maxLambda, RayIntersection& intersection) const { const BVTree &collisionTree = mInstance ? mInstance->mCollisionTree : mCollisionTree; const std::vector<Vec3f> &collisionPositions = mInstance ? mInstance->mCollisionPositions : mCollisionPositions; const std::vector<Vec3f> &collisionNormals = mInstance ? mInstance->mCollisionNormals : mCollisionNormals; const std::vector<Vec3i> &collisionIndices = mInstance ? mInstance->mCollisionIndices : mCollisionIndices; const std::vector<int> &intersectionCandidates = collisionTree.intersectBoundingBoxes(ray,maxLambda); float closestLambda = maxLambda; Vec3f closestbary; int closestTri = -1; Vec3f bary; float lambda; for(size_t i=0;i<intersectionCandidates.size();++i) { const int triangleIndex = intersectionCandidates[i]; const int idx0 = collisionIndices[triangleIndex][0]; const int idx1 = collisionIndices[triangleIndex][1]; const int idx2 = collisionIndices[triangleIndex][2]; const Vec3f &p0 = collisionPositions[idx0]; const Vec3f &p1 = collisionPositions[idx1]; const Vec3f &p2 = collisionPositions[idx2]; if (Intersection::lineTriangle(ray,p0,p1,p2,bary,lambda) && lambda > 0 && lambda < closestLambda) { closestLambda = lambda; closestbary = bary; closestTri = triangleIndex; } } if (closestTri >= 0) { const int i0 = collisionIndices[closestTri][0]; const int i1 = collisionIndices[closestTri][1]; const int i2 = collisionIndices[closestTri][2]; Vec3f n = collisionNormals[i0]*closestbary[0]+ collisionNormals[i1]*closestbary[1]+ collisionNormals[i2]*closestbary[2]; intersection = RayIntersection(ray,closestLambda,n); return true; } return false; }
bool Sphere::closestIntersectionModel(const Ray &ray, double maxLambda, RayIntersection& intersection) const { /* A ray and a sphere intersect if and only if (o + lambda * d - c)^2 = r^2 where o is the origin of the ray d is the direction vector of the ray c is the center of the sphere r is the radius of the sphere Since o and d are known, c = O and r = 1, we have a quadratic equation in lambda. We solve it using calcRoots() which is a slightly modified version of the classical quadratic formula (as described in [1]). [1] http://wiki.delphigl.com/index.php/Tutorial_Raytracing_-_Grundlagen_I#Quadratische_Gleichungen */ // a, b and c are the constants in // a * lambda^2 + b * lambda + c = 0. double a = dot(ray.direction(), ray.direction()); double b = 2 * dot(ray.direction(), ray.origin()); double c = dot(ray.origin(), ray.origin()) - 1; // t1 and t2 are the solutions of our quadratic equation. // W.l.o.g. t1 <= t2 (calcRoots takes care of that) // calcRoots return the number of roots it found (zero, one or two). double t1, t2; int roots = calcRoots(a, b, c, t1, t2); bool doIntersect = false; if (roots > 0) { // There is a solution, we just need the (smallest) positve one. double lambda = t1 >= 0 ? t1 : t2; if (lambda >= 0.0 && lambda < maxLambda) { doIntersect = true; intersection = RayIntersection(ray, shared_from_this(), lambda, ray.pointOnRay(lambda), Vec3d(0,0,0)); } } return doIntersect; }
bool Triangle::closestIntersectionModel(const Ray &ray, double maxLambda, RayIntersection& intersection) const { Vec3d bary; double lambda; if(!Intersection::lineTriangle(ray,mVertices[0],mVertices[1],mVertices[2],bary,lambda)) return false; // Intersection is inside triangle if 0<=u,v,w<=1 if(lambda<0 || lambda>maxLambda) return false; const Vec3d normal = cross(mVertices[1]-mVertices[0],mVertices[2]-mVertices[0]).normalize(); const Vec3d uvw = mUVW[0]*bary[0]+mUVW[1]*bary[1]+mUVW[2]*bary[2]; intersection = RayIntersection(ray,shared_from_this(),lambda,normal,uvw); return true; }
std::vector<RayIntersection> FastLine::RayIntersects(gp_Pnt pnt) { std::vector<RayIntersection> ret; //If this line is significantly horizontal, there is nothing good //we can do here if(B.Y() < A.Y() + TOLERANCE/4 && B.Y() > A.Y() - TOLERANCE/4) return ret; if((pnt.Y() < B.Y() + TOLERANCE && pnt.Y() > A.Y() - TOLERANCE)|| (pnt.Y() > B.Y() - TOLERANCE && pnt.Y() < A.Y() + TOLERANCE)) { if(fabs(A.Y() - B.Y()) < TOLERANCE) return ret; double u = (pnt.Y() - A.Y())/(B.Y()-A.Y()); double x = GetXatU(u); if(x < pnt.X()) ret.push_back(RayIntersection(u,gp_Pnt(x,pnt.Y(),0),false,false)); } return ret; }
bool Plane::closestIntersectionModel(const Ray &ray, double maxLambda, RayIntersection &intersection) const { // Solve linear equation for lambda // see also http://en.wikipedia.org/wiki/Line-plane_intersection double a = dot((-ray.origin()), (mNormal)); double d = dot(ray.direction(), (mNormal)); // No intersection if ray is (almost) parallel to plane if (fabs(d) < Math::safetyEps()) return false; double lambda = a / d; // Only intersections in [0,1] range are valid. if (lambda < 0.0 || lambda > maxLambda) return false; const Vec3d p = ray.pointOnRay(lambda); const Vec3d uvw(dot(p, mTangent), dot(p, mBitangent), double(0)); intersection = RayIntersection(ray, shared_from_this(), lambda, mNormal, uvw); return true; }
RayIntersection Cone::intersectWithRay(const Ray &ray) const { Vector coneAxis = (mBottomCenter - mTop); coneAxis.normalize(); Vector rayOriginPosition = ray.getOriginPosition(); Vector rayDirection = ray.getDirection(); Vector bottomCenterToRayOrigin = rayOriginPosition - mTop; float rayDirectionDotAxis = rayDirection.dotProduct(coneAxis); float bottomCenterToRayOriginDotAxis = bottomCenterToRayOrigin.dotProduct(coneAxis); float radiansPerHeight = mRadius / (mBottomCenter - mTop).length(); Vector u = rayDirection + coneAxis * (-rayDirectionDotAxis); Vector v = bottomCenterToRayOrigin + coneAxis * (-bottomCenterToRayOriginDotAxis); float w = bottomCenterToRayOriginDotAxis * radiansPerHeight; float radiansPerDirection = rayDirectionDotAxis * radiansPerHeight; // Solve square equation a * x^2 + b * x + c = 0 float a = u.dotProduct(u) - radiansPerDirection * radiansPerDirection; float closestRoot = -1.f; float rayExit = -1.f; float root = 0.f; std::vector<float> intersectionDistances; if (fabs(a) > FLOAT_ZERO) { float b = 2 * (u.dotProduct(v) - w * radiansPerDirection); float c = v.dotProduct(v) - w * w; float discriminant = b * b - 4 * a * c; if (discriminant < 0.0) { return RayIntersection(); } discriminant = sqrtf(discriminant); float denominator = 1.0 / (2.0 * a); root = (-b - discriminant) * denominator; if (root > 0.0) { Vector point = ray.getPointAt(root); Vector bottomCenterToPoint = point - mTop; Vector topToPoint = point - mBottomCenter; if (coneAxis.dotProduct(bottomCenterToPoint) > 0.0 && (-coneAxis).dotProduct(topToPoint) > 0.0) { intersectionDistances.push_back(root); closestRoot = root; } } root = (-b + discriminant) * denominator; if (root > 0.0) { Vector point = ray.getPointAt(root); Vector bottomCenterToPoint = point - mTop; Vector topToPoint = point - mBottomCenter; if (coneAxis.dotProduct(bottomCenterToPoint) > 0.0 && (-coneAxis).dotProduct(topToPoint) > 0.0) { intersectionDistances.push_back(root); if (closestRoot < 0.0) { closestRoot = root; } else if (root < closestRoot) { rayExit = closestRoot; closestRoot = root; } else { rayExit = root; } } } } // Intersection with bottom if (fabs(rayDirectionDotAxis) < FLOAT_ZERO) { if (closestRoot > 0.0) { if (rayExit < 0.f) { intersectionDistances.insert(intersectionDistances.begin(), 0.f); } ConePointer pointer = ConePointer(new Cone(*this)); return RayIntersection(true, pointer, closestRoot, getNormal(ray, closestRoot), intersectionDistances); } return RayIntersection(); } // Intersection with top and bottom points root = (-coneAxis).dotProduct(rayOriginPosition - mBottomCenter) / rayDirectionDotAxis; if (root > 0.0) { Vector topToPoint = ray.getPointAt(root) - mBottomCenter; if (topToPoint.dotProduct(topToPoint) < mRadius * mRadius) { intersectionDistances.push_back(root); if (closestRoot < 0.0) { closestRoot = root; rayExit = root; } else if (root < closestRoot) { rayExit = closestRoot; closestRoot = root; } else { rayExit = root; } } } if (closestRoot > 0.0) { if (rayExit < 0.0) { intersectionDistances.insert(intersectionDistances.begin(), 0.f); } ConePointer pointer = ConePointer(new Cone(*this)); return RayIntersection(true, pointer, closestRoot, getNormal(ray, closestRoot), intersectionDistances); } return RayIntersection(); }