bool Disk::Intersect(const Ray &r, Float *tHit, SurfaceInteraction *isect) const { // Transform _Ray_ to object space Vector3f oErr, dErr; Ray ray = (*WorldToObject)(r, &oErr, &dErr); // Compute plane intersection for disk // Reject disk intersections for rays parallel to the disk's plane if (ray.d.z == 0) return false; Float tShapeHit = (height - ray.o.z) / ray.d.z; if (tShapeHit <= 0 || tShapeHit >= ray.tMax) return false; // See if hit point is inside disk radii and $\phimax$ Point3f pHit = ray(tShapeHit); Float dist2 = pHit.x * pHit.x + pHit.y * pHit.y; if (dist2 > radius * radius || dist2 < innerRadius * innerRadius) return false; // Refine disk intersection point pHit.z = height; // Test disk $\phi$ value against $\phimax$ Float phi = std::atan2(pHit.y, pHit.x); if (phi < 0) phi += 2 * Pi; if (phi > phiMax) return false; // Find parametric representation of disk hit Float u = phi / phiMax; Float rHit = std::sqrt(dist2); Float oneMinusV = ((rHit - innerRadius) / (radius - innerRadius)); Float v = 1 - oneMinusV; Vector3f dpdu(-phiMax * pHit.y, phiMax * pHit.x, 0.); Vector3f dpdv = Vector3f(pHit.x, pHit.y, 0.) * (innerRadius - radius) / rHit; Normal3f dndu(0, 0, 0), dndv(0, 0, 0); // Compute error bounds for disk intersection Vector3f pError(0., 0., 0.); // Initialize _SurfaceInteraction_ from parametric information *isect = (*ObjectToWorld)(SurfaceInteraction(pHit, pError, Point2f(u, v), -ray.d, dpdu, dpdv, dndu, dndv, ray.time, this)); // Update _tHit_ for quadric intersection *tHit = (Float)tShapeHit; return true; }
bool Disk::Intersect(const Ray &r, float *tHit, float *rayEpsilon, DifferentialGeometry *dg) const { // Transform _Ray_ to object space Ray ray; (*WorldToObject)(r, &ray); // Compute plane intersection for disk if (fabsf(ray.d.z) < 1e-7) return false; float thit = (height - ray.o.z) / ray.d.z; if (thit < ray.mint || thit > ray.maxt) return false; // See if hit point is inside disk radii and $\phimax$ Point phit = ray(thit); float dist2 = phit.x * phit.x + phit.y * phit.y; if (dist2 > radius * radius || dist2 < innerRadius * innerRadius) return false; // Test disk $\phi$ value against $\phimax$ float phi = atan2f(phit.y, phit.x); if (phi < 0) phi += 2. * M_PI; if (phi > phiMax) return false; // Find parametric representation of disk hit float u = phi / phiMax; float v = 1.f - ((sqrtf(dist2)-innerRadius) / (radius-innerRadius)); Vector dpdu(-phiMax * phit.y, phiMax * phit.x, 0.); Vector dpdv(-phit.x / (1-v), -phit.y / (1-v), 0.); dpdu *= phiMax * INV_TWOPI; dpdv *= (radius - innerRadius) / radius; Normal dndu(0,0,0), dndv(0,0,0); // Initialize _DifferentialGeometry_ from parametric information *dg = DifferentialGeometry((*ObjectToWorld)(phit), (*ObjectToWorld)(dpdu), (*ObjectToWorld)(dpdv), (*ObjectToWorld)(dndu), (*ObjectToWorld)(dndv), u, v, this); // Update _tHit_ for quadric intersection *tHit = thit; // Compute _rayEpsilon_ for quadric intersection *rayEpsilon = 5e-4f * *tHit; return true; }
bool Rectangle::Intersect(const Ray &r, float *tHit, float *rayEpsilon, DifferentialGeometry *dg) const { // Transform _Ray_ to object space Ray ray; (*WorldToObject)(r, &ray); // Compute plane intersection for disk // Checks if the plane is parallel to the ray or not // We can get the direction of the ray // If the Z component of the direction of the ray is zero // then, the ray is parallel to the plane and in such case // there is no intersection point between the ray and the plane. if (fabsf(ray.d.z) < 1e-7) return false; // Now, the direction of the ray is not parallel to the plane // We have to check if the intersection happens or not // We have to compute the parametric t where the ray intersects the plane // We want to find t such that the z-component of the ray intersects the plane // The ray "line" equation is l = l0 + (l1 - l0) * t // l1 - l0 will give us the distance between the two points on the plane // Then t is the ratio and in such case it should be between 0 and 1 // Considering that the rectangle completely lies in the z plane /// distance = l1 - l0 /// thit = (l - l0) / distance // But since we assume that the plane is located at height // Then, the point l is at height on the plane /// l = height float thit = (height - ray.o.z) / ray.d.z; // Then we check if the thit is between the ratio of 0 and 1 that is mapped // between ray.mint and ray.maxt, if not retrun false if (thit < ray.mint || thit > ray.maxt) return false; // Then we see if the point lies inside the disk or not // Substitute the thit in the ray equation to get hit point on the ray Point phit = ray(thit); // We have to make sure that the interesction lies inside the plane if (!(phit.x < x/2 && phit.x > -x/2 && phit.y < y/2 && phit.y > -y/2)) return false; // Assuming that the plane is formed from the following 4 points // P0, P1, P2, P3 // // p0 *---------------* p1 // | | // | | // | | // | O | // | | // | | // | | // p2 *---------------* p3 -> X // // P0 @ (-x/2, y/2) // P1 @ (x/2, y/2) // P2 @ (-x/2, -y/2) // P3 @ (x/2, -y/2) Point P0(-x/2, y/2, height), P1(x/2, y/2, height); Point P2(-x/2, -y/2, height), P3(x/2, -y/2, height); /// Now, we have to find the parametric form of the plane in terms of (u,v) /// Plane equation can be formed by at least 3 points P0, P1, P2 /// P0 -> P1 (vector 1) /// P0 -> p2 (vector 2) /// An arbitrary point on the plane p is found in the following parametric form /// P = P0 + (P1 - P0) u + (P2 - P0) v /// Now we need to express two explicit equations of u and v /// So, we have to construct the system of equation that solves for u and v /// /// Since we have found the intersection point between the plane and the line /// we have to use it to formalize the system of equations that will be used /// to find the parametric form of the plane /// Plane equation is : P = P0 + (P1 - P0) u + (P2 - P0) v /// Ray equation is : l = l0 + (l1 - l0) * thit /// But l = P, then /// l0 + (l1 - l0) * thit = P0 + (P1 - P0) * u + (P2 - P0) * v /// l0 - P0 = (l0 - l1) * thit + (P1 - P0) * u + (P2 - P0) * v /// MAPPING : l0 = ray.o /// [l0.x - P0.x] = [l0.x - l1.x P1.x - P0.x P2.x - P0.x] [t] /// [l0.y - P0.y] = [l0.y - l1.y P1.y - P0.y P2.y - P0.y] [u] /// [l0.z - P0.z] = [l0.z - l1.z P1.z - P0.z P2.z - P0.z] [v] /// /// Then, we should find the inverse of the matrix in order to /// solve for u,v and t for check // System AX = B float a11 = ray.o.x - 0; float a12 = P1.x - P0.x; float a13 = P2.x - P0.x; float a21 = ray.o.y - 0; float a22 = P1.y - P0.y; float a23 = P2.y - P0.y; float a31 = ray.o.y - height; float a32 = P1.z - P0.z; float a33 = P2.z - P0.z; float b1 = -7; float b2 = -2; float b3 = 14; float x1 = 0; float x2 = 0; float x3 = 0; Imath::M33f A(a11,a12,a13,a21,a22,a23,a31,a32,a33), AInverted; Imath::V3f X(x1, x2, x3); Imath::V3f B(b1,b2, b3); // This operation has been checked and working for getting // the correct inverse of the matrix A AInverted = A.invert(false); x1 = AInverted[0][0] * B[0] + AInverted[0][1] * B[1] + AInverted[0][2] * B[2]; x2 = AInverted[1][0] * B[0] + AInverted[1][1] * B[1] + AInverted[1][2] * B[2]; x3 = AInverted[2][0] * B[0] + AInverted[2][1] * B[1] + AInverted[2][2] * B[2]; /// Then we have u = something, and v = something /// /// Then we come for the derivatives, so we have to find the derivatives /// from the parametric forms defined above for the plane equations /// dpdu = (P1 - P0) /// dpdv = (P2 - P0) /// /// For the normal we have the always fixed direction in y /// So the derivative for the normal is zero /// dndu = (0, 0, 0) dndv = (0, 0, 0) /// /// Then we can construct the DifferentilGeometry and go ahead // Find parametric representation of disk hit float u = x2; float v = x3; Vector dpdu(P1.x - P0.x, P1.y - P0.y, P1.z - P0.z); Vector dpdv(P2.x - P0.x, P2.y - P0.y, P2.z - P0.z); Normal dndu(0,0,0), dndv(0,0,0); // Initialize _DifferentialGeometry_ from parametric information const Transform &o2w = *ObjectToWorld; *dg = DifferentialGeometry(o2w(phit), o2w(dpdu), o2w(dpdv), o2w(dndu), o2w(dndv), u, v, this); // Update _tHit_ for quadric intersection *tHit = thit; // Compute _rayEpsilon_ for quadric intersection *rayEpsilon = 5e-4f * *tHit; return true; }
bool Sphere::intersect(const Ray &ray, float *t_hit, float *ray_epsilon, DifferentialGeometry *diff_geo) const { // Transform Ray to object space Ray w_ray; (*world_to_object)(ray, &w_ray); // Compute quadratic sphere coefficients float phi; Point phit; float A = w_ray.d.x * w_ray.d.x + w_ray.d.y * w_ray.d.y + w_ray.d.z * w_ray.d.z; float B = 2 * (w_ray.d.x * w_ray.o.x + w_ray.d.y * w_ray.o.y + w_ray.d.z * w_ray.o.z); float C = w_ray.o.x*w_ray.o.x + w_ray.o.y*w_ray.o.y + w_ray.o.z*w_ray.o.z - _radius*_radius; // Solve quadratic equation for t values float t0, t1; if (!quadratic(A, B, C, &t0, &t1)) return false; // Compute intersection distance along ray if (t0 > w_ray.maxt || t1 < w_ray.mint) return false; float thit = t0; if (t0 < w_ray.mint) { thit = t1; if (thit > w_ray.maxt) return false; } // Compute sphere hit position and phi phit = w_ray(thit); if (phit.x == 0.f && phit.y == 0.f) phit.x = 1e-5f * _radius; phi = atan2f(phit.y, phit.x); if (phi < 0.) phi += 2.f * M_PI; // Test sphere intersection against clipping parameters if ((_z_min > -_radius && phit.z < _z_min) || (_z_max < _radius && phit.z > _z_max) || phi > _phi_max) { // clip t0(t1) if (thit == t1) return false; if (t1 > w_ray.maxt) return false; thit = t1; // Compute sphere hit position and phi phit = w_ray(thit); if (phit.x == 0.f && phit.y == 0.f) phit.x = 1e-5f * _radius; phi = atan2f(phit.y, phit.x); if (phi < 0.) phi += 2.f * M_PI; if ((_z_min > -_radius && phit.z < _z_min) || (_z_max < _radius && phit.z > _z_max) || phi > _phi_max) // clip t1 return false; } // Find parametric representatio n of sphere hit float u = phi / _phi_max; float theta = acosf(clamp(phit.z / _radius, -1.f, 1.f)); float v = (theta - _theta_min) / (_theta_max - _theta_min); float z_radius = sqrtf(phit.x * phit.x + phit.y * phit.y); float inv_z_radius = 1.f / z_radius; float cos_phi = phit.x * inv_z_radius; float sin_phi = phit.y * inv_z_radius; Vec3 dpdu(-_phi_max * phit.y, _phi_max * phit.x, 0); Vec3 dpdv = (_theta_max - _theta_min) * Vec3(phit.z * cos_phi, phit.z * sin_phi, _radius * sinf(theta)); //auto d2Pduu = -_phi_max * _phi_max * Vec3(phit.x, phit.y, 0); //auto d2Pduv = (_theta_max - _theta_min) * phit.z * _phi_max * Vec3(-sin_phi, cos_phi, 0.f); //auto d2Pdvv = (_theta_max - _theta_min) * (_theta_max - _theta_min) * Vec3(phit.x, phit.y, phit.z); //Normal dndu, dndv; //calc_dndu_dndv(dpdu, dpdv, d2Pduu, d2Pduv, d2Pdvv, &dndu, &dndv); Normal dndu(dpdu); Normal dndv(dpdv); const auto &o2w = *object_to_world; *diff_geo = DifferentialGeometry(o2w(phit), o2w(dpdu), o2w(dpdv), o2w(dndu), o2w(dndv), u, v, this); *t_hit = thit; *ray_epsilon = 5e-4f * *t_hit; return true; }