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 DistanceEstimator::Intersect(const Ray &r, float *tHit, float *rayEpsilon, DifferentialGeometry *dg) const { bool succeed = DoesIntersect(r, tHit); if (!succeed) return false; Ray ray; (*WorldToObject)(r, &ray); Point p = ray(*tHit); *rayEpsilon = DE_params.hitEpsilon * DE_params.rayEpsilonMultiplier; Vector n = CalculateNormal(p, DE_params.normalEpsilon); Vector DPDU, DPDV; CoordinateSystem(n, &DPDU, &DPDV); const Transform &o2w = *ObjectToWorld; *dg = DifferentialGeometry(o2w(p), o2w(DPDU), o2w(DPDV), Normal(), Normal(), 0, 0, this); return true; }
bool Sphere::Intersect(const Ray &r, Float *distance, Float *rayEpsilon, DifferentialGeometry *dg) const { Ray ray; (*worldToLocal)(r, &ray); // Compute quadratic sphere coefficients Float A = ray.d.x * ray.d.x + ray.d.y * ray.d.y + ray.d.z * ray.d.z; Float B = 2 * (ray.d.x * ray.o.x + ray.d.y * ray.o.y + ray.d.z * ray.o.z); Float C = ray.o.x * ray.o.x + ray.o.y * ray.o.y + ray.o.z * ray.o.z - mRad * mRad; Float t0, t1; if (!Quadratic(A, B, C, &t0, &t1)) return false; // Compute intersection distance along ray if (t0 > ray.maxT || t1 < ray.minT) return false; Float thit = t0; if (t0 < ray.minT) { thit = t1; if (thit > ray.maxT) return false; } //这里开始计算参数化变量 //计算phi Point phit; Float phi; phit = ray(thit); if (phit.x == 0.f && phit.y == 0.f) phit.x = 1e-5f * mRad; //排除除零的情况 phi = atan2f(phit.y, phit.x); if (phi < 0.) phi += 2.f * Pi; //保证phi在2PI之中 //判断是否在Z坐标之间的裁剪空间中 if ((mZMin > -mRad && phit.z < mZMin) || (mZMax < mRad && phit.z > mZMax) || phi > mPhiMax) { if (thit == t1) return false; if (t1 > ray.maxT) return false; thit = t1; phit = ray(thit); if (phit.x == 0.f && phit.y == 0.f) phit.x = 1e-5f * mRad; phi = atan2f(phit.y, phit.x); if (phi < 0.) phi += 2.f * Pi; if ((mZMin > -mRad && phit.z < mZMin) || (mZMax < mRad && phit.z > mZMax) || phi > mPhiMax) return false; } // Find parametric representation of sphere hit //寻找参数化的u和v Float u = phi / mPhiMax; Float theta = acosf(Clamp(phit.z / mRad, -1.f, 1.f)); Float v = (theta - mThetaMin) / (mThetaMax - mThetaMin); // 计算偏导 偏导还不是很熟悉,所以这里照搬了PBRT的公式,详细公式可以查阅PBRT Float zradius = sqrtf(phit.x * phit.x + phit.y * phit.y); Float invzradius = 1.f / zradius; Float cosphi = phit.x * invzradius; Float sinphi = phit.y * invzradius; Vector3f dpdu(-mPhiMax * phit.y, mPhiMax * phit.x, 0); Vector3f dpdv = (mThetaMax - mThetaMin) * Vector3f(phit.z * cosphi, phit.z * sinphi, -mRad * sinf(theta)); //计算法线的偏导 Vector3f d2Pduu = -mPhiMax * mPhiMax * Vector3f(phit.x, phit.y, 0); Vector3f d2Pduv = (mThetaMax - mThetaMin) * phit.z * mPhiMax * Vector3f(-sinphi, cosphi, 0.); Vector3f d2Pdvv = -(mThetaMax - mThetaMin) * (mThetaMax - mThetaMin) * Vector3f(phit.x, phit.y, phit.z); Float E = Dot(dpdu, dpdu); Float F = Dot(dpdu, dpdv); Float G = Dot(dpdv, dpdv); Vector3f N = Normalize(Cross(dpdu, dpdv)); Float e = Dot(N, d2Pduu); Float f = Dot(N, d2Pduv); Float g = Dot(N, d2Pdvv); Float invEGF2 = 1.f / (E * G - F * F); Normal dndu = Normal( (f * F - e * G) * invEGF2 * dpdu + (e * F - f * E) * invEGF2 * dpdv); Normal dndv = Normal( (g * F - f * G) * invEGF2 * dpdu + (f * F - g * E) * invEGF2 * dpdv); const Transform &o2w = *localToWorld; *dg = DifferentialGeometry(o2w(phit), o2w(dpdu), o2w(dpdv), o2w(dndu), o2w(dndv), u, v, this); *distance = thit; *rayEpsilon = 5e-4f * *distance; //交点处的Float误差 return true; }
/*! * Triangle intersection */ bool Triangle::Intersect( const Ray& objectRay, double* tHit, DifferentialGeometry* dg ) const { //e1 = B - A //e2 = C - A Vector3D pVector = CrossProduct( objectRay.direction(), m_vE2 ); double det = DotProduct( m_vE1, pVector ); double inv_det = 1/det; //std::cout<<"det: "<<det<<std::endl; //Vector3D tVector = Vector3D( objectRay.origin ) – Vector3D(m_v1) ; Vector3D tVector = Vector3D( objectRay.origin - m_v1 ); Vector3D qVec = CrossProduct( tVector , m_vE1 ); double thit; double tol = 0.000001; if (det > tol) { double u = DotProduct( tVector,pVector ); if (u < 0 || u > det ) return ( false ); double v = DotProduct( objectRay.direction(), qVec ); if (v < 0 || ( v + u ) > det) return ( false ); double t = DotProduct( m_vE2, qVec ); thit = t * inv_det; u *= inv_det; v *= inv_det; } else if (det < - tol) { double u = DotProduct( tVector, pVector ) * inv_det; if (u < 0.0 || u > 1.0) return ( false ); double v = DotProduct( objectRay.direction(), qVec ) * inv_det; if (v < 0.0 || ( ( v+u ) > 1.0 ) ) return ( false ); double t = DotProduct( m_vE2, qVec ) * inv_det; thit = t; } else return ( false ); //return intersection == true , t, P /*//Jimenez algorithm double t0; double t1; if( !m_bbox.IntersectP(objectRay, &t0, &t1 ) ) return ( false ); //Evaluate Tolerance t0 -= 0.1; t1 += 0.1; Point3D Q1 = objectRay( t0 ); Point3D Q2 = objectRay( t1 ); Vector3D vA = Vector3D( Q1 - m_v3 ); double w = DotProduct( vA, m_vW1 ); Vector3D vD = Vector3D( Q2 - m_v3 ); double s = DotProduct( vD, m_vW1 ); double tol = 0.000001; if( w > tol ) { if( s > tol ) return ( false ); Vector3D vW2 = CrossProduct( vA, vD ); double t = DotProduct( vW2, m_vC ); if( t < -tol ) return ( false ); double u = DotProduct( - vW2, m_vB ); if( u < -tol ) return ( false ); if( w < ( s + t + u ) ) return ( false ); } else if ( w < -tol ) { if( s < -tol ) return ( false ); Vector3D vW2 = CrossProduct( vA, vD ); double t = DotProduct( vW2, m_vC ); if( t > tol ) return ( false ); double u = DotProduct( - vW2, m_vB ); if( u > tol ) return ( false ); if( w > ( s + t + u ) ) return ( false ); } else // w == 0, swap( Q1, Q2 ) { Vector3D vW2 = CrossProduct( vD, vA ); double t = DotProduct( vW2, m_vC ); if( s > tol ) { if( t < -tol ) return ( false ); double u = DotProduct( - vW2, m_vB); if( u < -tol ) return ( false ); if( -s < ( t + u ) ) return ( false ); } else if( s < - tol ) { if( t > tol ) return ( false ); double u = DotProduct( - vW2, m_vB ); if( u > tol ) return ( false ); if( -s > ( t + u ) ) return ( false ); } else return ( false ); } double t_param = ( DotProduct( Normalize( m_vW1 ), vA ) / DotProduct( Normalize( m_vW1 ), Vector3D( Q1 - Q2 ) ) ); double thit = t0 + t_param * Distance( Q1, Q2 ); */ if( thit > *tHit ) return false; if( (thit - objectRay.mint) < tol ) return false; Point3D hitPoint = objectRay( thit ); Vector3D dpdu = Normalize( m_vE1 ); Vector3D dpdv = Normalize( m_vE2 ); // Compute ShapeCone \dndu and \dndv Vector3D d2Pduu( 0.0, 0.0, 0.0 ); Vector3D d2Pduv( 0.0, 0.0, 0.0 ); Vector3D d2Pdvv( 0.0, 0.0, 0.0 ); // Compute coefficients for fundamental forms double E = DotProduct( dpdu, dpdu ); double F = DotProduct( dpdu, dpdv ); double G = DotProduct( dpdv, dpdv ); Vector3D N = Normalize( NormalVector( CrossProduct( dpdu, dpdv ) ) ); double e = DotProduct( N, d2Pduu ); double f = DotProduct( N, d2Pduv ); double g = DotProduct( N, d2Pdvv ); // Compute \dndu and \dndv from fundamental form coefficients double invEGF2 = 1.0 / (E*G - F*F); Vector3D dndu = (f*F - e*G) * invEGF2 * dpdu + (e*F - f*E) * invEGF2 * dpdv; Vector3D dndv = (g*F - f*G) * invEGF2 * dpdu + (f*F - g*E) * invEGF2 * dpdv; // Initialize _DifferentialGeometry_ from parametric information *dg = DifferentialGeometry( hitPoint , dpdu, dpdv, dndu, dndv, -1, -1, 0 ); dg->shapeFrontSide = ( DotProduct( N, objectRay.direction() ) > 0 ) ? false : true; // Update _tHit_ for quadric intersection *tHit = thit; return true; }
// 1. -- intersection or not. // 2. -- fill differentialGeometry bool Sphere::Intersect(const Ray &r, float *tHit, float *rayEpsilon, DifferentialGeometry *dg) const { float phi; Point phit; // Transform _Ray_ to object space Ray ray; (*WorldToObject)(r, &ray); // 1. -- intersection or not. // Compute quadratic sphere coefficients float A = ray.d.x*ray.d.x + ray.d.y*ray.d.y + ray.d.z*ray.d.z; float B = 2 * (ray.d.x*ray.o.x + ray.d.y*ray.o.y + ray.d.z*ray.o.z); float C = ray.o.x*ray.o.x + ray.o.y*ray.o.y + ray.o.z*ray.o.z - radius*radius; // Solve quadratic equation for _t_ values float t0, t1; if (!Quadratic(A, B, C, &t0, &t1)) // in pbrt.h: Find quadratic discriminant return false; // Compute intersection distance along ray if (t0 > ray.maxt || t1 < ray.mint) return false; float thit = t0; if (t0 < ray.mint) { thit = t1; if (thit > ray.maxt) return false; } // Compute sphere hit position and $\phi$ phit = 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 ((zmin > -radius && phit.z < zmin) || (zmax < radius && phit.z > zmax) || phi > phiMax) { if (thit == t1) return false; if (t1 > ray.maxt) return false; thit = t1; // Compute sphere hit position and $\phi$ phit = 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 ((zmin > -radius && phit.z < zmin) || (zmax < radius && phit.z > zmax) || phi > phiMax) return false; } // 2. -- fill differentialGeometry // Find parametric representation of sphere hit float u = phi / phiMax; float theta = acosf(Clamp(phit.z / radius, -1.f, 1.f)); float v = (theta - thetaMin) / (thetaMax - thetaMin); // Compute sphere $\dpdu$ and $\dpdv$ float zradius = sqrtf(phit.x*phit.x + phit.y*phit.y); float invzradius = 1.f / zradius; float cosphi = phit.x * invzradius; float sinphi = phit.y * invzradius; Vector dpdu(-phiMax * phit.y, phiMax * phit.x, 0); Vector dpdv = (thetaMax-thetaMin) * Vector(phit.z * cosphi, phit.z * sinphi, -radius * sinf(theta)); // Compute sphere $\dndu$ and $\dndv$ Vector d2Pduu = -phiMax * phiMax * Vector(phit.x, phit.y, 0); Vector d2Pduv = (thetaMax - thetaMin) * phit.z * phiMax * Vector(-sinphi, cosphi, 0.); Vector d2Pdvv = -(thetaMax - thetaMin) * (thetaMax - thetaMin) * Vector(phit.x, phit.y, phit.z); // Compute coefficients for fundamental forms float E = Dot(dpdu, dpdu); float F = Dot(dpdu, dpdv); float G = Dot(dpdv, dpdv); Vector N = Normalize(Cross(dpdu, dpdv)); float e = Dot(N, d2Pduu); float f = Dot(N, d2Pduv); float g = Dot(N, d2Pdvv); // Compute $\dndu$ and $\dndv$ from fundamental form coefficients float invEGF2 = 1.f / (E*G - F*F); Normal dndu = Normal((f*F - e*G) * invEGF2 * dpdu + (e*F - f*E) * invEGF2 * dpdv); Normal dndv = Normal((g*F - f*G) * invEGF2 * dpdu + (f*F - g*E) * invEGF2 * dpdv); // 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 Cone::Intersect(const Ray &r, float *tHit, float *rayEpsilon, DifferentialGeometry *dg) const { float phi; pbrt::Point phit; // Transform _Ray_ to object space Ray ray; (*WorldToObject)(r, &ray); // Compute quadratic cone coefficients float k = radius / height; k = k*k; float A = ray.d.x * ray.d.x + ray.d.y * ray.d.y - k * ray.d.z * ray.d.z; float B = 2 * (ray.d.x * ray.o.x + ray.d.y * ray.o.y - k * ray.d.z * (ray.o.z-height) ); float C = ray.o.x * ray.o.x + ray.o.y * ray.o.y - k * (ray.o.z -height) * (ray.o.z-height); // 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 > ray.maxt || t1 < ray.mint) return false; float thit = t0; if (t0 < ray.mint) { thit = t1; if (thit > ray.maxt) return false; } // Compute cone inverse mapping phit = ray(thit); phi = atan2f(phit.y, phit.x); if (phi < 0.) phi += 2.f*M_PI; // Test cone intersection against clipping parameters if (phit.z < 0 || phit.z > height || phi > phiMax) { if (thit == t1) return false; thit = t1; if (t1 > ray.maxt) return false; // Compute cone inverse mapping phit = ray(thit); phi = atan2f(phit.y, phit.x); if (phi < 0.) phi += 2.f*M_PI; if (phit.z < 0 || phit.z > height || phi > phiMax) return false; } // Find parametric representation of cone hit float u = phi / phiMax; float v = phit.z / height; // Compute cone $\dpdu$ and $\dpdv$ Vector dpdu(-phiMax * phit.y, phiMax * phit.x, 0); Vector dpdv(-phit.x / (1.f - v), -phit.y / (1.f - v), height); // Compute cone $\dndu$ and $\dndv$ Vector d2Pduu = -phiMax * phiMax * Vector(phit.x, phit.y, 0.); Vector d2Pduv = phiMax / (1.f - v) * Vector(phit.y, -phit.x, 0.); Vector d2Pdvv(0, 0, 0); // Compute coefficients for fundamental forms float E = Dot(dpdu, dpdu); float F = Dot(dpdu, dpdv); float G = Dot(dpdv, dpdv); Vector N = Normalize(Cross(dpdu, dpdv)); float e = Dot(N, d2Pduu); float f = Dot(N, d2Pduv); float g = Dot(N, d2Pdvv); // Compute $\dndu$ and $\dndv$ from fundamental form coefficients float invEGF2 = 1.f / (E*G - F*F); Normal dndu = Normal((f*F - e*G) * invEGF2 * dpdu + (e*F - f*E) * invEGF2 * dpdv); Normal dndv = Normal((g*F - f*G) * invEGF2 * dpdu + (f*F - g*E) * invEGF2 * dpdv); // 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 Hyperboloid::Intersect(const Ray &r, float *tHit, float *rayEpsilon, DifferentialGeometry *dg) const { float phi, v; Point phit; // Transform _Ray_ to object space Ray ray; (*WorldToObject)(r, &ray); // Compute quadratic hyperboloid coefficients float A = a*ray.d.x*ray.d.x + a*ray.d.y*ray.d.y - c*ray.d.z*ray.d.z; float B = 2.f * (a*ray.d.x*ray.o.x + a*ray.d.y*ray.o.y - c*ray.d.z*ray.o.z); float C = a*ray.o.x*ray.o.x + a*ray.o.y*ray.o.y - c*ray.o.z*ray.o.z - 1; // 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 > ray.maxt || t1 < ray.mint) return false; float thit = t0; if (t0 < ray.mint) { thit = t1; if (thit > ray.maxt) return false; } // Compute hyperboloid inverse mapping phit = ray(thit); v = (phit.z - p1.z)/(p2.z - p1.z); Point pr = (1.f-v) * p1 + v * p2; phi = atan2f(pr.x*phit.y - phit.x*pr.y, phit.x*pr.x + phit.y*pr.y); if (phi < 0) phi += 2*M_PI; // Test hyperboloid intersection against clipping parameters if (phit.z < zmin || phit.z > zmax || phi > phiMax) { if (thit == t1) return false; thit = t1; if (t1 > ray.maxt) return false; // Compute hyperboloid inverse mapping phit = ray(thit); v = (phit.z - p1.z)/(p2.z - p1.z); Point pr = (1.f-v) * p1 + v * p2; phi = atan2f(pr.x*phit.y - phit.x*pr.y, phit.x*pr.x + phit.y*pr.y); if (phi < 0) phi += 2*M_PI; if (phit.z < zmin || phit.z > zmax || phi > phiMax) return false; } // Compute parametric representation of hyperboloid hit float u = phi / phiMax; // Compute hyperboloid $\dpdu$ and $\dpdv$ float cosphi = cosf(phi), sinphi = sinf(phi); Vector dpdu(-phiMax * phit.y, phiMax * phit.x, 0.); Vector dpdv((p2.x-p1.x) * cosphi - (p2.y-p1.y) * sinphi, (p2.x-p1.x) * sinphi + (p2.y-p1.y) * cosphi, p2.z-p1.z); // Compute hyperboloid $\dndu$ and $\dndv$ Vector d2Pduu = -phiMax * phiMax * Vector(phit.x, phit.y, 0); Vector d2Pduv = phiMax * Vector(-dpdv.y, dpdv.x, 0.); Vector d2Pdvv(0, 0, 0); // Compute coefficients for fundamental forms float E = Dot(dpdu, dpdu); float F = Dot(dpdu, dpdv); float G = Dot(dpdv, dpdv); Vector N = Normalize(Cross(dpdu, dpdv)); float e = Dot(N, d2Pduu); float f = Dot(N, d2Pduv); float g = Dot(N, d2Pdvv); // Compute $\dndu$ and $\dndv$ from fundamental form coefficients float invEGF2 = 1.f / (E*G - F*F); Normal dndu = Normal((f*F - e*G) * invEGF2 * dpdu + (e*F - f*E) * invEGF2 * dpdv); Normal dndv = Normal((g*F - f*G) * invEGF2 * dpdu + (f*F - g*E) * invEGF2 * dpdv); // 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 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; }
bool Triangle::Intersect(const Ray &ray, Float *distance, Float *rayEpsilon, DifferentialGeometry *dg) const { Point p1 = mMesh->p[mIndex[0]]; Point p2 = mMesh->p[mIndex[1]]; Point p3 = mMesh->p[mIndex[2]]; //这里使用质心坐标来计算 详见PBRT公式 Vector3f e1 = p2 - p1; //e1=p2-p1 Vector3f e2 = p3 - p1; //e2=p3-p1 Vector3f s1 = Cross(ray.d, e2); //s1=d x e2 Float divisor = Dot(s1, e1); if (divisor == 0.0f) return false; Float invDivisor = 1.f / divisor; //1/(s1.e1) // 计算第一个质心坐标 Vector3f s = ray.o - p1; //s = o - p1 Float b1 = Dot(s, s1) * invDivisor; //b1 = (s.s1)/(s1.e1) if (b1 < 0. || b1 > 1.) return false; // 计算第二个质心坐标 Vector3f s2 = Cross(s, e1); //s2 = s x e1 Float b2 = Dot(ray.d, s2) * invDivisor; // b2 = (d.s2)/(s1.e1) if (b2 < 0. || b1 + b2 > 1.) return false; // 计算参数t Float t = Dot(e2, s2) * invDivisor; if (t < ray.minT || t > ray.maxT) return false; Vector3f dpdu, dpdv; //p在u和v上的偏导 Float uvs[3][2]; GetUVs(uvs); //计算p在u和v上的偏导 Float du1 = uvs[0][0] - uvs[2][0]; Float du2 = uvs[1][0] - uvs[2][0]; Float dv1 = uvs[0][1] - uvs[2][1]; Float dv2 = uvs[1][1] - uvs[2][1]; Vector3f dp1 = p1 - p3, dp2 = p2 - p3; Float determinant = du1 * dv2 - dv1 * du2; if (determinant == 0.f) { //行列式为0 CoordinateSystem(Normalize(Cross(e2, e1)), &dpdu, &dpdv); } else { Float invdet = 1.f / determinant; dpdu = (dv2 * dp1 - dv1 * dp2) * invdet; dpdv = (-du2 * dp1 + du1 * dp2) * invdet; } //这里是在计算参数坐标 用的也是质心坐标 Float b0 = 1 - b1 - b2; Float tu = b0 * uvs[0][0] + b1 * uvs[1][0] + b2 * uvs[2][0]; Float tv = b0 * uvs[0][1] + b1 * uvs[1][1] + b2 * uvs[2][1]; *dg = DifferentialGeometry(ray(t), dpdu, dpdv, Normal(0, 0, 0), Normal(0, 0, 0), tu, tv, this); *distance = t; *rayEpsilon = 1e-3f * *distance; //cout<<"射中三角"<<endl; return true; }
bool ShapeParabolicRectangle::Intersect(const Ray& objectRay, double *tHit, DifferentialGeometry *dg) const { double focus = focusLength.getValue(); double wX = widthX.getValue(); double wZ = widthZ.getValue(); // Compute quadratic coefficients double A = objectRay.direction().x * objectRay.direction().x + objectRay.direction().z * objectRay.direction().z; double B = 2.0 * ( objectRay.direction().x * objectRay.origin.x + objectRay.direction().z * objectRay.origin.z - 2 * focus * objectRay.direction().y ); double C = objectRay.origin.x * objectRay.origin.x + objectRay.origin.z * objectRay.origin.z - 4 * focus * objectRay.origin.y; // Solve quadratic equation for _t_ values double t0, t1; if( !gf::Quadratic( A, B, C, &t0, &t1 ) ) return false; // Compute intersection distance along ray if( t0 > objectRay.maxt || t1 < objectRay.mint ) return false; double thit = ( t0 > objectRay.mint )? t0 : t1 ; if( thit > objectRay.maxt ) return false; //Evaluate Tolerance double tol = 0.00001; //Compute possible hit position Point3D hitPoint = objectRay( thit ); // Test intersection against clipping parameters if( (thit - objectRay.mint) < tol || hitPoint.x < ( - wX / 2 ) || hitPoint.x > ( wX / 2 ) || hitPoint.z < ( - wZ / 2 ) || hitPoint.z > ( wZ / 2 ) ) { if ( thit == t1 ) return false; if ( t1 > objectRay.maxt ) return false; thit = t1; hitPoint = objectRay( thit ); if( (thit - objectRay.mint) < tol || hitPoint.x < ( - wX / 2 ) || hitPoint.x > ( wX / 2 ) || hitPoint.z < ( - wZ / 2 ) || hitPoint.z > ( wZ / 2 ) ) return false; } // Now check if the function is being called from IntersectP, // in which case the pointers tHit and dg are 0 if( ( tHit == 0 ) && ( dg == 0 ) ) return true; else if( ( tHit == 0 ) || ( dg == 0 ) ) gf::SevereError( "Function ParabolicCyl::Intersect(...) called with null pointers" ); /////////////////////////////////////////////////////////////////////////////////////// // Compute possible parabola hit position // Find parametric representation of paraboloid hit double u = ( hitPoint.x / wX ) + 0.5; double v = ( hitPoint.z / wZ ) + 0.5; Vector3D dpdu( wX, ( (-0.5 + u) * wX * wX ) / ( 2 * focus ), 0 ); Vector3D dpdv( 0.0, (( -0.5 + v) * wZ * wZ ) /( 2 * focus ), wZ ); // Compute parabaloid \dndu and \dndv Vector3D d2Pduu( 0.0, (wX * wX ) /( 2 * focus ), 0.0 ); Vector3D d2Pduv( 0.0, 0.0, 0.0 ); Vector3D d2Pdvv( 0.0, (wZ * wZ ) /( 2 * focus ), 0.0 ); // Compute coefficients for fundamental forms double E = DotProduct(dpdu, dpdu); double F = DotProduct(dpdu, dpdv); double G = DotProduct(dpdv, dpdv); NormalVector N = Normalize( NormalVector( CrossProduct( dpdu, dpdv ) ) ); double e = DotProduct(N, d2Pduu); double f = DotProduct(N, d2Pduv); double g = DotProduct(N, d2Pdvv); // Compute \dndu and \dndv from fundamental form coefficients double invEGF2 = 1.0 / (E*G - F*F); Vector3D dndu = (f*F - e*G) * invEGF2 * dpdu + (e*F - f*E) * invEGF2 * dpdv; Vector3D dndv = (g*F - f*G) * invEGF2 * dpdu + (f*F - g*E) * invEGF2 * dpdv; // Initialize _DifferentialGeometry_ from parametric information *dg = DifferentialGeometry(hitPoint, dpdu, dpdv, dndu, dndv, u, v, this); dg->shapeFrontSide = ( DotProduct( N, objectRay.direction() ) > 0 ) ? false : true; /////////////////////////////////////////////////////////////////////////////////////// // Update _tHit_ for quadric intersection *tHit = thit; return true; }
bool ShapeTroughCHC::Intersect(const Ray& objectRay, double *tHit, DifferentialGeometry *dg) const { double a = ( m_s - height.getValue() )/( cos( m_theta ) * 2 * m_eccentricity); double b = sqrt( ( m_eccentricity * m_eccentricity - 1 ) * a * a ); double angle = -( 0.5 * gc::Pi ) + m_theta; Transform hTransform( cos( angle ), -sin( angle ), 0.0, -r1.getValue() + a * m_eccentricity * sin( m_theta ), sin( angle ), cos( angle ), 0.0, - a * m_eccentricity * cos( m_theta ), 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ); Ray transformedRay = hTransform.GetInverse()( objectRay ); double A = ( transformedRay.direction().x * transformedRay.direction().x ) / ( a * a ) - ( transformedRay.direction().y * transformedRay.direction().y ) / ( b * b ); double B = 2.0 * ( ( ( transformedRay.origin.x * transformedRay.direction().x ) / ( a * a ) ) - ( ( transformedRay.origin.y * transformedRay.direction().y ) / ( b * b ) ) ); double C = ( ( transformedRay.origin.x * transformedRay.origin.x ) / ( a * a ) ) - ( ( transformedRay.origin.y * transformedRay.origin.y ) / ( b * b ) ) - 1; // Solve quadratic equation for _t_ values double t0, t1; if( !gf::Quadratic( A, B, C, &t0, &t1 ) ) return false; // Compute intersection distance along ray if( t0 > objectRay.maxt || t1 < objectRay.mint ) return false; double thit = ( t0 > objectRay.mint )? t0 : t1 ; if( thit > objectRay.maxt ) return false; //Evaluate Tolerance double tol = 0.00001; // Compute ShapeTroughCHC hit position and $\phi$ Point3D hitPoint = objectRay( thit ); // Test intersection against clipping parameters double m = ( lengthX2.getValue() / 2- lengthX1.getValue() / 2 ) / ( p1.getValue() - r1.getValue() ); double zmax = ( lengthX1.getValue() / 2 ) + m * ( hitPoint.x - r1.getValue() ); double zmin = - zmax; // Test intersection against clipping parameters if( (thit - objectRay.mint) < tol || hitPoint.x < r1.getValue() || hitPoint.x > p1.getValue() || hitPoint.y < 0.0 || hitPoint.y > height.getValue() || hitPoint.z < zmin || hitPoint.z > zmax ) { if ( thit == t1 ) return false; if ( t1 > objectRay.maxt ) return false; thit = t1; // Compute ShapeSphere hit position and $\phi$ hitPoint = objectRay( thit ); zmax = ( lengthX1.getValue() / 2 ) + m * ( hitPoint.x - r1.getValue() ); zmin = - zmax; if( (thit - objectRay.mint) < tol || hitPoint.x < r1.getValue() || hitPoint.x > p1.getValue() || hitPoint.y < 0.0 || hitPoint.y > height.getValue() || hitPoint.z < zmin || hitPoint.z > zmax ) return false; } // Find parametric representation of CHC concentrator hit double sup = m_theta + 0.5* gc::Pi; double inf = m_theta + m_phi; double alpha; bool isAlpha = findRoot( fPart, hitPoint.x, m_eccentricity, r1.getValue(), m_theta, inf, sup, 0.5*( sup-inf), 500, &alpha ); if( !isAlpha )return false; double u = ( alpha - inf ) / ( sup - inf ); zmax = (lengthX1.getValue() / 2 ) + m* ( hitPoint.x - r1.getValue() ); double v = ( ( hitPoint.z / zmax ) + 1 )/ 2; // Compute \dpdu and \dpdv Vector3D dpdu = GetDPDU( u, v ); Vector3D dpdv = GetDPDV( u, v ); // Compute cylinder \dndu and \dndv //Not yet implemented Vector3D d2Pduu( 0.0, 0.0, 0.0 ); Vector3D d2Pduv( 0.0, 0.0, 0.0 ); Vector3D d2Pdvv( 0.0, 0.0, 0.0 ); // Compute coefficients for fundamental forms double E = DotProduct( dpdu, dpdu ); double F = DotProduct( dpdu, dpdv ); double G = DotProduct( dpdv, dpdv ); Vector3D N = Normalize( CrossProduct( dpdu, dpdv ) ); double e = DotProduct( N, d2Pduu ); double f = DotProduct( N, d2Pduv ); double g = DotProduct( N, d2Pdvv ); // Compute \dndu and \dndv from fundamental form coefficients double invEGF2 = 1.0 / (E*G - F*F); Vector3D dndu = (f*F - e*G) * invEGF2 * dpdu + (e*F - f*E) * invEGF2 * dpdv; Vector3D dndv = (g*F - f*G) * invEGF2 * dpdu + (f*F - g*E) * invEGF2 * dpdv; // Initialize _DifferentialGeometry_ from parametric information *dg = DifferentialGeometry( hitPoint , dpdu, dpdv, dndu, dndv, u, v, this ); // Update _tHit_ for quadric intersection *tHit = thit; dg->shapeFrontSide = ( DotProduct( N, objectRay.direction() ) > 0 ) ? false : true; return true; }
// copy shapes/tianglemesh.cpp -> bool Triangle::Intersect(const Ray &ray, float *tHit, float *rayEpsilon, DifferentialGeometry *dg) const bool Heightfield2::triangleIntersect (const Ray &ray, float *tHit, float *rayEpsilon, DifferentialGeometry *dg, Point triangle[]) const { const Point p1 = (*ObjectToWorld)(triangle[0]); const Point p2 = (*ObjectToWorld)(triangle[1]); const Point p3 = (*ObjectToWorld)(triangle[2]); Vector e1 = p2 - p1; Vector e2 = p3 - p1; Vector s1 = Cross(ray.d, e2); float divisor = Dot(s1, e1); if (divisor == 0.) return false; float invDivisor = 1.f / divisor; // Compute first barycentric coordinate Vector s = ray.o - p1; float b1 = Dot(s, s1) * invDivisor; if (b1 < 0. || b1 > 1.) return false; // Compute second barycentric coordinate Vector s2 = Cross(s, e1); float b2 = Dot(ray.d, s2) * invDivisor; if (b2 < 0. || b1 + b2 > 1.) return false; // Compute _t_ to intersection point float t = Dot(e2, s2) * invDivisor; if (t < ray.mint || t > ray.maxt) return false; // Compute triangle partial derivatives Vector dpdu, dpdv; // Compute deltas for triangle partial derivatives float du1 = triangle[0].x - triangle[2].x; float du2 = triangle[1].x - triangle[2].x; float dv1 = triangle[0].y - triangle[2].y; float dv2 = triangle[1].y - triangle[2].y; Vector dp1 = p1 - p3, dp2 = p2 - p3; float determinant = du1 * dv2 - dv1 * du2; if (determinant == 0.f) { // Handle zero determinant for triangle partial derivative matrix CoordinateSystem(Normalize(Cross(e2, e1)), &dpdu, &dpdv); } else { float invdet = 1.f / determinant; dpdu = ( dv2 * dp1 - dv1 * dp2) * invdet; dpdv = (-du2 * dp1 + du1 * dp2) * invdet; } // Interpolate $(u,v)$ triangle parametric coordinates float b0 = 1 - b1 - b2; float tu = b0*triangle[0].x + b1*triangle[1].x + b2*triangle[2].x; float tv = b0*triangle[0].y + b1*triangle[1].y + b2*triangle[2].y; // Fill in _DifferentialGeometry_ from triangle hit *dg = DifferentialGeometry(ray(t), dpdu, dpdv, Normal(0,0,0), Normal(0,0,0), tu, tv, this); *tHit = t; *rayEpsilon = 1e-3f * *tHit; return true; }
void Heightfield2::GetShadingGeometry(const Transform &obj2world, const DifferentialGeometry &dg, DifferentialGeometry *dgShading) const { // Initialize _Triangle_ shading geometry with _n_ and _s_ // *dgShading = dg; // return; Point p = Point(dg.u, dg.v, 0); int x = posToVoxel(p, 0); int y = posToVoxel(p, 1); int index1 = x + y*nx; int index2, index3; const Point &p1o = point[index1]; if((dg.u-p1o.x)*width[1] > (dg.v-p1o.y)*width[0]){ index2 = x+1 + y*nx; index3 = x+1 + (y+1)*nx; }else{ index2 = x+1 + (y+1)*nx; index3 = x + (y+1)*nx; } const Point &p2o = point[index2]; const Point &p3o = point[index3]; const Normal &normal0 = normal[index1]; const Normal &normal1 = normal[index2]; const Normal &normal2 = normal[index3]; // Compute barycentric coordinates for point float b[3]; // Initialize _A_ and _C_ matrices for barycentrics float A[2][2] = { { p2o.x - p1o.x, p3o.x - p1o.x }, { p2o.y - p1o.y, p3o.y - p1o.y } }; float C[2] = { dg.u - p1o.x, dg.v - p1o.y }; if (!SolveLinearSystem2x2(A, C, &b[1], &b[2])) { // Handle degenerate parametric mapping b[0] = b[1] = b[2] = 1.f/3.f; } else b[0] = 1.f - b[1] - b[2]; // Use _n_ and _s_ to compute shading tangents for triangle, _ss_ and _ts_ Normal ns; Vector ss, ts; ns = Normalize(obj2world(b[0] * normal0 + b[1] * normal1 + b[2] * normal2)); ss = Normalize(dg.dpdu); ts = Cross(ss, ns); if (ts.LengthSquared() > 0.f) { ts = Normalize(ts); ss = Cross(ts, ns); } else CoordinateSystem((Vector)ns, &ss, &ts); Normal dndu, dndv; // Compute $\dndu$ and $\dndv$ for triangle shading geometry // Compute deltas for triangle partial derivatives of normal float du1 = p1o.x - p3o.x; float du2 = p2o.x - p3o.x; float dv1 = p1o.y - p3o.y; float dv2 = p2o.y - p3o.y; Normal dn1 = normal0 - normal2; Normal dn2 = normal1 - normal2; float determinant = du1 * dv2 - dv1 * du2; if (determinant == 0.f) dndu = dndv = Normal(0,0,0); else { float invdet = 1.f / determinant; dndu = ( dv2 * dn1 - dv1 * dn2) * invdet; dndv = (-du2 * dn1 + du1 * dn2) * invdet; } *dgShading = DifferentialGeometry(dg.p, ss, ts, obj2world(dndu), obj2world(dndv), dg.u, dg.v, dg.shape); dgShading->dudx = dg.dudx; dgShading->dvdx = dg.dvdx; dgShading->dudy = dg.dudy; dgShading->dvdy = dg.dvdy; dgShading->dpdx = dg.dpdx; dgShading->dpdy = dg.dpdy; }
bool Heightfield2::TriangleIntersect(const Ray &ray, float *tHit, float *rayEpsilon, DifferentialGeometry *dg, int index[]) const{ PBRT_RAY_TRIANGLE_INTERSECTION_TEST(const_cast<Ray *>(&ray), const_cast<Triangle *>(this)); // Get triangle vertices in _p1_, _p2_, and _p3_ const Point &p1o = point[index[0]]; const Point &p2o = point[index[1]]; const Point &p3o = point[index[2]]; const Point &p1 = (*ObjectToWorld)(p1o); const Point &p2 = (*ObjectToWorld)(p2o); const Point &p3 = (*ObjectToWorld)(p3o); Vector e1 = p2 - p1; Vector e2 = p3 - p1; Vector s1 = Cross(ray.d, e2); float divisor = Dot(s1, e1); if (divisor == 0.) return false; float invDivisor = 1.f / divisor; // Compute first barycentric coordinate Vector s = ray.o - p1; float b1 = Dot(s, s1) * invDivisor; if (b1 < 0. || b1 > 1.) return false; // Compute second barycentric coordinate Vector s2 = Cross(s, e1); float b2 = Dot(ray.d, s2) * invDivisor; if (b2 < 0. || b1 + b2 > 1.) return false; // Compute _t_ to intersection point float t = Dot(e2, s2) * invDivisor; if (t < ray.mint || t > ray.maxt) return false; // Compute triangle partial derivatives Vector dpdu, dpdv; // Compute deltas for triangle partial derivatives float du1 = p1o.x - p3o.x; float du2 = p2o.x - p3o.x; float dv1 = p1o.y - p3o.y; float dv2 = p2o.y - p3o.y; Vector dp1 = p1 - p3, dp2 = p2 - p3; float determinant = du1 * dv2 - dv1 * du2; if (determinant == 0.f) { // Handle zero determinant for triangle partial derivative matrix CoordinateSystem(Normalize(Cross(e2, e1)), &dpdu, &dpdv); } else { float invdet = 1.f / determinant; dpdu = ( dv2 * dp1 - dv1 * dp2) * invdet; dpdv = (-du2 * dp1 + du1 * dp2) * invdet; } // Interpolate $(u,v)$ triangle parametric coordinates float b0 = 1 - b1 - b2; float tu = b0*p1o.x + b1*p2o.x + b2*p3o.x; float tv = b0*p1o.y + b1*p2o.y + b2*p3o.y; // Fill in _DifferentialGeometry_ from triangle hit *dg = DifferentialGeometry(ray(t), dpdu, dpdv, Normal(0,0,0), Normal(0,0,0), tu, tv, this); *tHit = t; *rayEpsilon = 1e-3f * *tHit; ray.maxt = t; PBRT_RAY_TRIANGLE_INTERSECTION_HIT(const_cast<Ray *>(&ray), t); return true; }
bool Triangle::Intersect(const Ray &ray, float *tHit, float *rayEpsilon, DifferentialGeometry *dg) const { PBRT_RAY_TRIANGLE_INTERSECTION_TEST(const_cast<Ray *>(&ray), const_cast<Triangle *>(this)); // Compute $\VEC{s}_1$ // Get triangle vertices in _p1_, _p2_, and _p3_ const Point &p1 = mesh->p[v[0]]; const Point &p2 = mesh->p[v[1]]; const Point &p3 = mesh->p[v[2]]; Vector e1 = p2 - p1; Vector e2 = p3 - p1; Vector s1 = Cross(ray.d, e2); float divisor = Dot(s1, e1); if (divisor == 0.) return false; float invDivisor = 1.f / divisor; // Compute first barycentric coordinate Vector d = ray.o - p1; float b1 = Dot(d, s1) * invDivisor; if (b1 < 0. || b1 > 1.) return false; // Compute second barycentric coordinate Vector s2 = Cross(d, e1); float b2 = Dot(ray.d, s2) * invDivisor; if (b2 < 0. || b1 + b2 > 1.) return false; // Compute _t_ to intersection point float t = Dot(e2, s2) * invDivisor; if (t < ray.mint || t > ray.maxt) return false; // Compute triangle partial derivatives Vector dpdu, dpdv; float uvs[3][2]; GetUVs(uvs); // Compute deltas for triangle partial derivatives float du1 = uvs[0][0] - uvs[2][0]; float du2 = uvs[1][0] - uvs[2][0]; float dv1 = uvs[0][1] - uvs[2][1]; float dv2 = uvs[1][1] - uvs[2][1]; Vector dp1 = p1 - p3, dp2 = p2 - p3; float determinant = du1 * dv2 - dv1 * du2; if (determinant == 0.f) { // Handle zero determinant for triangle partial derivative matrix CoordinateSystem(Normalize(Cross(e2, e1)), &dpdu, &dpdv); } else { float invdet = 1.f / determinant; dpdu = ( dv2 * dp1 - dv1 * dp2) * invdet; dpdv = (-du2 * dp1 + du1 * dp2) * invdet; } // Interpolate $(u,v)$ triangle parametric coordinates float b0 = 1 - b1 - b2; float tu = b0*uvs[0][0] + b1*uvs[1][0] + b2*uvs[2][0]; float tv = b0*uvs[0][1] + b1*uvs[1][1] + b2*uvs[2][1]; // Test intersection against alpha texture, if present if (ray.depth != -1) { if (mesh->alphaTexture) { DifferentialGeometry dgLocal(ray(t), dpdu, dpdv, Normal(0,0,0), Normal(0,0,0), tu, tv, this); if (mesh->alphaTexture->Evaluate(dgLocal) == 0.f) return false; } } // Fill in _DifferentialGeometry_ from triangle hit *dg = DifferentialGeometry(ray(t), dpdu, dpdv, Normal(0,0,0), Normal(0,0,0), tu, tv, this); *tHit = t; *rayEpsilon = 1e-3f * *tHit; PBRT_RAY_TRIANGLE_INTERSECTION_HIT(const_cast<Ray *>(&ray), t); return true; }
void Triangle::GetShadingGeometry(const Transform &obj2world, const DifferentialGeometry &dg, DifferentialGeometry *dgShading) const { if (!mesh->n && !mesh->s) { *dgShading = dg; return; } // Initialize _Triangle_ shading geometry with _n_ and _s_ // Compute barycentric coordinates for point float b[3]; // Initialize _A_ and _C_ matrices for barycentrics float uv[3][2]; GetUVs(uv); float A[2][2] = { { uv[1][0] - uv[0][0], uv[2][0] - uv[0][0] }, { uv[1][1] - uv[0][1], uv[2][1] - uv[0][1] } }; float C[2] = { dg.u - uv[0][0], dg.v - uv[0][1] }; if (!SolveLinearSystem2x2(A, C, &b[1], &b[2])) { // Handle degenerate parametric mapping b[0] = b[1] = b[2] = 1.f/3.f; } else b[0] = 1.f - b[1] - b[2]; // Use _n_ and _s_ to compute shading tangents for triangle, _ss_ and _ts_ Normal ns; Vector ss, ts; if (mesh->n) ns = Normalize(obj2world(b[0] * mesh->n[v[0]] + b[1] * mesh->n[v[1]] + b[2] * mesh->n[v[2]])); else ns = dg.nn; if (mesh->s) ss = Normalize(obj2world(b[0] * mesh->s[v[0]] + b[1] * mesh->s[v[1]] + b[2] * mesh->s[v[2]])); else ss = Normalize(dg.dpdu); ts = Cross(ss, ns); if (ts.LengthSquared() > 0.f) { ts = Normalize(ts); ss = Cross(ts, ns); } else CoordinateSystem((Vector)ns, &ss, &ts); Normal dndu, dndv; // Compute $\dndu$ and $\dndv$ for triangle shading geometry if (mesh->n) { float uvs[3][2]; GetUVs(uvs); // Compute deltas for triangle partial derivatives of normal float du1 = uvs[0][0] - uvs[2][0]; float du2 = uvs[1][0] - uvs[2][0]; float dv1 = uvs[0][1] - uvs[2][1]; float dv2 = uvs[1][1] - uvs[2][1]; Normal dn1 = mesh->n[v[0]] - mesh->n[v[2]]; Normal dn2 = mesh->n[v[1]] - mesh->n[v[2]]; float determinant = du1 * dv2 - dv1 * du2; if (determinant == 0.f) dndu = dndv = Normal(0,0,0); else { float invdet = 1.f / determinant; dndu = ( dv2 * dn1 - dv1 * dn2) * invdet; dndv = (-du2 * dn1 + du1 * dn2) * invdet; } } else dndu = dndv = Normal(0,0,0); *dgShading = DifferentialGeometry(dg.p, ss, ts, (*ObjectToWorld)(dndu), (*ObjectToWorld)(dndv), dg.u, dg.v, dg.shape); dgShading->dudx = dg.dudx; dgShading->dvdx = dg.dvdx; dgShading->dudy = dg.dudy; dgShading->dvdy = dg.dvdy; dgShading->dpdx = dg.dpdx; dgShading->dpdy = dg.dpdy; }
bool Sphere::Intersect( Ray const &ray, float *tHit, float *epsilon, DifferentialGeometry *geom ) const { Transform tf = Tform(); Ray r = ray * Inverse( tf ); float t; if( !Intersect( ray, &t ) ) return false; // compute differential geometry Vec4 p = ray.Point( t ); float x = p.X(); float y = p.Y(); float z = p.Z(); if( x == 0.0f && z == 0.0f ) { // can't have both atan2 arguments be zero z = kEpsilon * m_radius; } float theta = atan2( p.X(), p.Z() ); if( theta < 0.0f ) { // remap theta to [0, 2pi] to match sphere's definition theta += k2Pi; } float phi = Acos( Clamp( z / m_radius, -1.0f, 1.0f ) ); // parameterize sphere hit float u = theta * kInv2Pi; float v = phi * kInvPi; float sTheta, cTheta; float sPhi, cPhi; SinCos( theta, &sTheta, &cTheta ); SinCos( phi, &sPhi, &cPhi ); Vec4 dpdu( k2Pi * z, 0.0f, -k2Pi * x, 0.0f ); Vec4 dpdv( kPi * y * sTheta, -kPi * m_radius * sPhi, kPi * y * cTheta, 0.0f ); Vec4 d2pdu2( -k2Pi * k2Pi * x, 0.0f, -k2Pi * k2Pi * z, 0.0f ); Vec4 d2pduv( k2Pi * kPi * y * cTheta, 0.0f, -k2Pi * kPi * y * sTheta, 0.0f ); Vec4 d2pdv2( -kPi * kPi * x, -kPi * kPi * y, -kPi * kPi * z, 0.0f ); // change in normal is computed using Weingarten equations Scalar E = Dot( dpdu, dpdu ); Scalar F = Dot( dpdu, dpdv ); Scalar G = Dot( dpdv, dpdv ); Vec4 N = Normalize( Cross( dpdu, dpdv ) ); Scalar e = Dot( N, d2pdu2 ); Scalar f = Dot( N, d2pduv ); Scalar g = Dot( N, d2pdv2 ); Scalar h = 1.0f / ( E * G - F * F ); Vec4 dndu = ( f * F - e * G ) * h * dpdu + ( e * F - f * E ) * h * dpdv; Vec4 dndv = ( g * F - f * G ) * h * dpdu + ( f * F - g * E ) * h * dpdv; *tHit = t; *epsilon = 5e-4f * t; // return world space differential geometry *geom = DifferentialGeometry( Handle(), p * tf, dpdu * tf, dpdv * tf, Normal( dndu ) * tf, Normal( dndv ) * tf, u, v ); return true; }