bool UVSphere::shadowHit(const Ray& r, precision tMin, precision tMax, precision time) const{ Vector3 temp = r.origin() - center; double a = dot(r.direction(), r.direction()); double b = 2 * dot(r.direction(), temp); double c = dot(temp, temp) - radius * radius; double discriminant = b * b - 4 * a * c; //First check to see if the ray intersects the sphere if(discriminant > 0){ discriminant = sqrt(discriminant); double t = (- b - discriminant) / (2 * a); //Now check for a valid interval if(t < tMin) t = (- b + discriminant) / (2 * a); if(t < tMin || t > tMax) return false; //We have a valid hit return true; } return false; }
Option<Vec2> sb::Intersection::get(const Ray& a, const Polygon& b) { Option<Vec2> pt = nullptr; Option<bool> inside = nullptr; float t = std::numeric_limits<float>::max(); auto eCount = b.edgeCount(); for (ptrdiff_t i = 0; i < eCount; i++) { const auto ed = b.edge(i); auto r = Intersection::get(a, ed); if (!r) continue; if (aeq(r.value(), ed.pointA())) { if (!inside.hasValue()) inside = test(b, a.m_point); if (!inside.value() && !(-a.direction()).isBetween(b.normal(i), b.normal(i - 1))) continue; } else if (aeq(r.value(), ed.pointB())) { if (!inside.hasValue()) inside = test(b, a.m_point); if (!inside.value() && !(-a.direction()).isBetween(b.normal(i), b.normal(i + 1))) continue; } auto u = a.computeT(r.value()); if (u < t) { t = u; pt = r; } } return pt; }
void App::playSculpture(const Ray& playRay) { int maxDistance = 0; int startIndex = g_sampleWindowIndex; for (auto piece : m_sonicSculpturePieces) { const shared_ptr<AudioSample>& sample = piece->getAudioSampleFromRay(playRay); if (sample->buffer.size() > 0) { maxDistance = max(maxDistance, (int)ceil(sample->buffer.size() / 512.0f)); Synthesizer::global->queueSound(sample); m_lastInterestingEventTime = System::time(); } } if (maxDistance > 0) { PlayPlane pp; pp.direction = playRay.direction(); pp.origin = playRay.origin(); pp.beginWindowIndex = startIndex; pp.endWindowIndex = startIndex + maxDistance; Vector3 zAxis = -playRay.direction(); Vector3 xAxis; if (abs(zAxis.dot(Vector3::unitY())) < 0.9f) { xAxis = zAxis.unitCross(Vector3::unitY()); } else { xAxis = zAxis.unitCross(Vector3::unitX()); } Vector3 yAxis = zAxis.cross(xAxis); pp.frame = CFrame(Matrix3::fromColumns(xAxis, yAxis, zAxis), pp.origin); m_playPlanes.append(pp); } }
bool Metal::scatter(const Ray& r_in, const HitRecord& record, vec3& attenuation, Ray& scattered) const { vec3 reflected = reflect( glm::normalize(r_in.direction()), record.normal ); scattered = Ray(record.point, reflected + roughness * randomInUnitSphere()); attenuation = Color3(m_color); return (glm::dot(scattered.direction(), record.normal) > 0); }
bool Metal::scatter(const Ray& r_in, const HitRecord& record, vec3& attenuation, Ray& scattered) const { vec3 reflected = reflect( glm::normalize(r_in.direction()), record.normal ); scattered = Ray(record.point, reflected + roughness * random_in_unit_sphere()); attenuation = albedo; return (dot(scattered.direction(), record.normal) > 0); }
Option<Vec2> Intersection::get(const Ray& a, const Circle& b) { const auto f = a.point() - b.center(); float _a = dot(a.direction(), a.direction()); float _b = 2 * dot(f, a.direction()); float _c = dot(f, f) - b.radius() * b.radius(); float d = _b * _b - 4 * _a * _c; if (d <= 0) //if d == 0, this means that the ray is tangent to the circle... we don't wanna this Intersection... return nullptr; else { d = sqrtf(d); float t1 = (-_b - d) / (2 * _a); float t2 = (-_b + d) / (2 * _a); if (t1 >= 0) { if (t2 >= 0) { if (t1 < t2) return a.sampleAlongRay(t1); else return a.sampleAlongRay(t2); } else { return a.sampleAlongRay(t1); } } else { if (t2 >= 0) return a.sampleAlongRay(t2); else return nullptr; } } }
void RayTracer::traceOnePixel(int x, int y, int threadID) { //used for constructing viewport Vector2 tmp(m_settings.width, m_settings.height); Ray primaryRay; // If one ray per pixel: (kinda debugging mode with blue color for places with no surfel hit if (m_settings.raysPerPixel == 1){ //Get the primary ray from the pixel x,y primaryRay = m_camera->worldRay(x + 0.5f, y + 0.5f, Rect2D(tmp)); //Get the first surfel hit. //Can't call L_i unfortunately because we want the blue background for debugging const shared_ptr<Surfel>& s = RayTracer::castRay(primaryRay, finf(), 0); //If there is a surfel hit, get the direct illumination value and apply to the pixel if (s){ //Call L_scatteredDirect to get direct illumination. Invert primaryRay to get the direction for incident light m_image->set(Point2int32(x,y), L_o(s, -primaryRay.direction(), m_settings.recursiveBounces, *(m_rnd[threadID]))); } else{ //Set the pixels with no surfel hit. Include this line so we could make it a specific color for debug purposes. m_image->set(Point2int32(x,y), Color3(0,0,1)); } } else { Radiance3 L(0,0,0); //If more than one ray, randomly generate required number of rays within the pixel for (int i = 0; i < m_settings.raysPerPixel; ++i){ primaryRay = m_camera->worldRay(x + m_rnd[threadID]->uniform(), y + m_rnd[threadID]->uniform(), Rect2D(tmp)); L += L_i(primaryRay.origin(), primaryRay.direction(), m_settings.recursiveBounces, *(m_rnd[threadID])); } m_image->set(Point2int32(x,y), L/m_settings.raysPerPixel); } }
bool Mesh::intersect(const Ray& ray, Intersection& j) const { bool intersected = false; // Check if bounding ball has been intersected first // If not then the mesh cannot have been intersected Intersection k; bool bball_intersected = m_boundingBall.intersect(ray, k); if(bball_intersected) { // Loop through each face and check if there is an intersection double prev_t = std::numeric_limits<double>::infinity(); for(auto face : m_faces) { // Compute the normal for the face Point3D P0 = m_verts[face[0]]; Point3D P1 = m_verts[face[1]]; Point3D P2 = m_verts[face[2]]; Vector3D n = (P1-P0).cross(P2-P0).normalized(); // Now check if the ray intersects the polygon containing the face // If denom is 0 then the ray does not intersect the plane at all double denom = n.dot(ray.direction()); if(fabs(denom) < std::numeric_limits<double>::epsilon()) continue; // If t is negative or a previous intersection has a smaller t (meaning it is closer to the // ray's origin) then disregard this face and continue double t = n.dot(P0 - ray.origin()) / denom; if(t < 0 || prev_t < t) continue; // Calculate intersection point Point3D Q = ray.origin() + t*ray.direction(); bool outside = false; for(size_t i = 0; i < face.size(); i++) { Point3D Q0 = (i == 0) ? m_verts[face.back()] : m_verts[face[i-1]]; Point3D Q1 = m_verts[face[i]]; if((Q1-Q0).cross(Q-Q0).dot(n) < 0) { outside = true; break; } } if(!outside) { // It is within the bounds of the polygon intersected = true; prev_t = t; j.q = Q; j.n = n; } } } return intersected; }
bool UVSphere::intersect(const Ray& r, float tmin, float tmax, float time, HitRecord& record)const{ Vec temp = r.origin() - center; float a = r.direction().dot(r.direction()); float b = 2 * r.direction().dot(temp); float c = temp.dot(temp) - radius * radius; float discriminant = b*b - 4*a*c; if(discriminant > 0){ discriminant = sqrt(discriminant); float t = (-b -discriminant) /(2*a); if(t < tmin) t = (-b + discriminant) / (2*a); if(t < tmin || t > tmax) return false; record.t = t; record.hit_p = r.origin() + r.direction() * t; record.reflect = reflectionCoef; record.transparency = refractionCoef; Vec n = record.normal = normalize(r.origin() + r.direction()*t - center); //calculate UV coordinates float theta = acos(n.y); float phi = atan2(n.z, n.x); if(phi < 0) phi += M_PI * 2; record.uv = Vec(phi/(2* M_PI), (M_PI - theta)/M_PI, 0); record.hit_tex = tex; return true; } return false; }
Color Scene::traceNoDepthMod(Ray &ray, bool &hitSomething, Color &Oi) const { if (ray.traceDepth == maxTraceDetph) { hitSomething = false; return Color(all_zero()); } ray.traceDepth++; const float prevMaxT = ray.maxT; IntersectionInfo info; const Geometry *nearestObj = bvhRoot->findClosest(ray, info); if (!nearestObj) { hitSomething = false; return Color(all_zero()); } hitSomething = true; // Object doesn't have shader, make it appear even for blind people! if (!nearestObj->hasShader()) { Oi = Color(sse::all_one); return Color(1, 0, 1); } CompiledShader shader(nearestObj->getShader(), true); shader.setCurrentDepth(ray.traceDepth); shader.setRTVarValueByIndex(CompiledShader::Cs, info.Cs); shader.setRTVarValueByIndex(CompiledShader::Os, info.Os); shader.setRTVarValueByIndex(CompiledShader::P, Vector3(info.P)); shader.setRTVarValueByIndex(CompiledShader::N, info.N); shader.setRTVarValueByIndex(CompiledShader::Ng, info.Ng); shader.setRTVarValueByIndex(CompiledShader::s, info.s); shader.setRTVarValueByIndex(CompiledShader::t, info.t); shader.setRTVarValueByIndex(CompiledShader::I, Vector3((cam.WorldToCamN * ray.direction()).get128())); shader.exec(); Color Ci, thisOi; shader.getOutput(Ci, thisOi); Oi += thisOi; if (isOpaque(Oi)) return Ci; ray.origin = info.P + (ray.direction() * 0.001f); ray.maxT = prevMaxT - ray.maxT; bool nextHit; const Color nextColor = traceNoDepthMod(ray, nextHit, Oi); if (!nextHit) return Ci; return Ci + mulPerElem((Vector3(1) - thisOi), nextColor); }
Intersection<Plane> Plane::find_intersection(const Ray& r) const { if (_span == Span::XY) return find_intersection_for_components(r.origin().z, r.direction().z); if (_span == Span::XZ) return find_intersection_for_components(r.origin().y, r.direction().y); return find_intersection_for_components(r.origin().x, r.direction().x); }
bool BVH::intersect(Ray &ray, IntersectionPtr isect) { if (nodes.empty()) return false; bool hit = false; Vector directionDivider; directionDivider << 1.0f/ray.direction(0), 1.0f/ray.direction(1), 1.0f/ray.direction(2); bool directionIsNegative[3] = {directionDivider(0) < 0, directionDivider(1) < 0, directionDivider(2) < 0}; // follow the ray through the tree's nodes to find intersections unsigned int toVisitOffset = 0; unsigned int nodeNumber = 0; unsigned int toVisit[64]; while(true) { const LinearNodePtr node = nodes[nodeNumber]; // check ray against the node if (intersectSlabs(node->bbox, ray, directionDivider, directionIsNegative)) { if (node->numberPrimitives > 0) { // proceed to intersect ray with primitives in leaf for (int i = 0; i < node->numberPrimitives; ++i) { if (objects[node->primOffset+i]->intersect(ray, isect)) hit = true; } if (toVisitOffset == 0) break; nodeNumber = toVisit[--toVisitOffset]; } else { // put distant node on stack, advance to next node if (directionIsNegative[node->axis]) { toVisit[toVisitOffset++] = nodeNumber + 1; nodeNumber = node->secondChildOffset; } else { toVisit[toVisitOffset++] = node->secondChildOffset; nodeNumber = nodeNumber + 1; } } } else { if (toVisitOffset == 0) break; nodeNumber = toVisit[--toVisitOffset]; } } return hit; }
bool Cone::intersect(const Ray &ray, double &t) { Ray localRay = ray * m_worldToObject; double dx = localRay.direction().x(); double dy = localRay.direction().y(); double dz = localRay.direction().z(); double ox = localRay.origin().x(); double oy = localRay.origin().y(); double oz = localRay.origin().z(); double a = dx * dx - dy * dy + dz * dz; double b = 2.0 * (dx * ox - dy * oy + dy + dz * oz); double c = ox * ox - oy * oy + 2 * oy + oz * oz - 1.0; double t1, t2, t3; // Calculate bottom disc t t3 = -oy / dy; double discX, discZ; discX = ox + dx * t3; discZ = oz + dz * t3; if (discX * discX + discZ * discZ > 1.0) t3 = -1.0; // Didn't hit the disc if (MathUtils::solveQuadratic(a, b, c, t1, t2)) { // Set cone tees to negative if the hit point y isn't between 0 and 1 double hy = oy + dy * t1; if (!(hy >= 0.0 && hy <= 1.0)) t1 = -1.0; hy = oy + dy * t2; if (!(hy >= 0.0 && hy <= 1.0)) t2 = -1.0; bool hit = false; t = std::numeric_limits<double>::max(); if (t1 > MathUtils::dEpsilon) { hit = true; t = t1; } if (t2 < t && t2 > MathUtils::dEpsilon) { hit = true; t = t2; } if (t3 < t && t3 > MathUtils::dEpsilon) { hit = true; t = t3; } return hit; } // Can't hit bottom disc without hitting the infinite cone too return false; }
bool World::intersect(Ray & r, double & bestT, vec3 &outn, MaterialInfo &outm) { bestT = numeric_limits<double>::infinity(); if (_DEBUG_INTERSECT1 && abs(r.direction()[0] - 0.146734796) < 0.05 && abs(r.direction()[1] + 0.146734796) < 0.05 && abs(r.direction()[2] + 0.978231971) < 0.05) int i = 0; //debug statement, stops at a ray aimed at the center of one of the spheres in threespheres.scd if (_DEBUG_INTERSECT2 && abs(r.direction()[0] + 0.114776942) < 0.02 && abs(r.direction()[1] - 0.0619082097) < 0.02 && abs(r.direction()[2] + 0.991460351) < 0.02) int i = 0; // debug statement, stops at a ray aimed for the left eye of the bunny in ellipsoids.scd if (_ASSIGNMENT <= 5 || _FINAL_PROJ) { // iterate through spheres to see if any of them are intersected for (vector<Sphere>::iterator sphere = _spheres.begin(); sphere != _spheres.end(); sphere++) { double intersect = sphere->intersect(r); if (intersect < bestT) { //cout << "intersect found" << endl; bestT = intersect; //cout << intersect << " "; vec4 pos = r.getPos(intersect); //cout << pos[0] << "," << pos[1] << "," << pos[2] << " "; outn = vec3(sphere->calculateNormal(pos), VW); //cout << outn[0] << "," << outn[1] << "," << outn[2] << endl; outm = sphere->getMaterial(); //AS4 stuff //if (sphere == _spheres.begin()) { // outm.k[MAT_KSM] *= ksmMod; // outm.k[MAT_KSP] *= kspMod; // if (outm.k[MAT_KSP] < 1.0) outm.k[MAT_KSP] = 1.0; //} } } for (vector<Cube>::iterator cube = _cubes.begin(); cube != _cubes.end(); cube++) { double intersect = cube->intersect(r); if (intersect < bestT) { bestT = intersect; vec4 pos = r.getPos(intersect); outn = vec3(cube->calculateNormal(pos), VW); outm = cube->getMaterial(); outm.color = cube->calculateColor(pos); } } return bestT < numeric_limits<double>::infinity(); } else return _bb->intersect(r, bestT, outn, outm); }
Ray Raytracer::make_reflection_ray(const Vector3d &normal, const Ray &ray, const Point3d &intersection) { Ray reflection(intersection, normalize( vector_subtract(ray.direction(), scalar_multiply(normal, 2 * dot_product(ray.direction(), normal))))); return reflection; }
bool MaterialOneSideSpecular::OutputRay( const Ray& incident, DifferentialGeometry* dg, RandomDeviate& rand, Ray* outputRay ) const { if( dg->shapeFrontSide && !isFront.getValue() ) return ( false ); if( !dg->shapeFrontSide && isFront.getValue() ) return ( false ); double randomNumber = rand.RandomDouble(); if ( randomNumber >= reflectivity.getValue() ) return false;//return 0; //Compute reflected ray (local coordinates ) outputRay->origin = dg->point; NormalVector normalVector; double sSlope = sigmaSlope.getValue() / 1000; if( sSlope > 0.0 ) { NormalVector errorNormal; if ( distribution.getValue() == 0 ) { double phi = gc::TwoPi * rand.RandomDouble(); double theta = sSlope * rand.RandomDouble(); errorNormal.x = sin( theta ) * sin( phi ) ; errorNormal.y = cos( theta ); errorNormal.z = sin( theta ) * cos( phi ); } else if (distribution.getValue() == 1 ) { errorNormal.x = sSlope * tgf::AlternateBoxMuller( rand ); errorNormal.y = 1.0; errorNormal.z = sSlope * tgf::AlternateBoxMuller( rand ); } Vector3D r = dg->normal; Vector3D s = Normalize( dg->dpdu ); Vector3D t = Normalize( dg->dpdv ); Transform trasform( s.x, s.y, s.z, 0.0, r.x, r.y, r.z, 0.0, t.x, t.y, t.z, 0.0, 0.0, 0.0, 0.0, 1.0); NormalVector normalDirection = trasform.GetInverse()( errorNormal ); normalVector = Normalize( normalDirection ); } else { normalVector = dg->normal; } double cosTheta = DotProduct( normalVector, incident.direction() ); outputRay->setDirection( Normalize( incident.direction() - 2.0 * normalVector * cosTheta ) ); return true; }
/** * slab method: http://www.siggraph.org/education/materials/HyperGraph/raytrace/rtinter3.htm * http://www.cs.utah.edu/~awilliam/box/box.pdf */ bool cgray::rt::AABB::intersect(const Ray & ray, IntersectInfo & info) { // r.dir is unit direction vector of ray Vector3f dir_frac(0,0,0); if (-M_EPSILON < ray.direction()[0] && ray.direction()[0] < M_EPSILON) { if (min_[0] > ray.origin()[0] || ray.origin()[0] > max_[0]) { return false; } } if (-M_EPSILON < ray.direction()[1] && ray.direction()[1] < M_EPSILON) { if (min_[1] > ray.origin()[1] || ray.origin()[1] > max_[1]) { return false; } } if (-M_EPSILON < ray.direction()[2] && ray.direction()[2] < M_EPSILON) { if (min_[2] > ray.origin()[2] || ray.origin()[2] > max_[2]) { return false; } } dir_frac[0] = 1.0f / ray.direction()[0]; dir_frac[1] = 1.0f / ray.direction()[1]; dir_frac[2] = 1.0f / ray.direction()[2]; // lb is the corner of AABB with minimal coordinates - left bottom, rt is maximal corner // r.org is origin of ray float t1 = (min_[0] - ray.origin()[0])*dir_frac[0]; float t2 = (max_[0] - ray.origin()[0])*dir_frac[0]; float t3 = (min_[1] - ray.origin()[1])*dir_frac[1]; float t4 = (max_[1] - ray.origin()[1])*dir_frac[1]; float t5 = (min_[2] - ray.origin()[2])*dir_frac[2]; float t6 = (max_[2] - ray.origin()[2])*dir_frac[2]; float tmin = std::max(std::max(std::min(t1, t2), std::min(t3, t4)), std::min(t5, t6)); float tmax = std::min(std::min(std::max(t1, t2), std::max(t3, t4)), std::max(t5, t6)); // if tmax < 0, ray (line) is intersecting AABB, but whole AABB is behing us if (tmax < 0) { return false; } // if tmin > tmax, ray doesn't intersect AABB if (tmin > tmax) { return false; } // set intersection info info.hit_point = ray.origin() + ray.direction() * tmin; info.hit_shape = std::make_shared<AABB>(*this); info.is_hit = true; info.dist = tmin; info.normal = getNormal(info.hit_point); info.ray = ray; return true; }
// returns true if it has collisions inside aabb bool KDTree::intersect(KDTreeNode *child, const Ray &ray, KDTreeHitInfo& hit, vec3 startPoint) { bool collision = false; if (child->isLeaf()) { for (auto& node : child->objects) { if (node.intersectRay(ray, hit)){ vec3 collisionPos = hit.collisionPoint; collision = child->aabb.contains(collisionPos); } } } else { float directionDelta = ray.direction()[child->splittingAxis]; if (directionDelta < 0 && ray.origin()[child->splittingAxis] < child->splittingPlane) { // only consider left child collision = intersect(child->leftChild, ray, hit, startPoint); } else if (directionDelta > 0 && ray.origin()[child->splittingAxis] > child->splittingPlane) { // only consider right child collision = intersect(child->rightChild, ray, hit, startPoint); } else { // collision with splitting plane if (directionDelta > 0) { // if direction is from min to max (left to right) collision = intersect(child->leftChild, ray, hit, startPoint); if (!collision) { float fNear, fFar; int aNear, aFar; if (child->rightChild->aabb.intersect(ray, fNear, fFar,aNear, aFar)) { vec3 splitPlaneIntersect = ray.origin() + ray.direction() * fNear; Ray newRay{splitPlaneIntersect, ray.direction()}; collision = intersect(child->rightChild, newRay, hit, startPoint); } } } else { // if direction is from min to max (left to right) collision = intersect(child->rightChild, ray, hit, startPoint); if (!collision) { float fNear, fFar; int aNear, aFar; if (child->leftChild->aabb.intersect(ray, fNear, fFar,aNear, aFar)) { vec3 splitPlaneIntersect = ray.origin() + ray.direction() * fNear; Ray newRay{splitPlaneIntersect, ray.direction()}; collision = intersect(child->leftChild, newRay, hit, startPoint); } } } } } return collision; }
bool Triangle::intersect(const Ray& ray, float& distance, float baryCoord[3]) const { static const float EPS = 1e-5f; // See RTR2 ch. 13.7 for the algorithm. const Vector3& e1 = edge01(); const Vector3& e2 = edge02(); const Vector3 p(ray.direction().cross(e2)); const float a = e1.dot(p); if (abs(a) < EPS) { // Determinant is ill-conditioned; abort early return false; } const float f = 1.0f / a; const Vector3 s(ray.origin() - vertex(0)); const float u = f * s.dot(p); if ((u < 0.0f) || (u > 1.0f)) { // We hit the plane of the m_geometry, but outside the m_geometry return false; } const Vector3 q(s.cross(e1)); const float v = f * ray.direction().dot(q); if ((v < 0.0f) || ((u + v) > 1.0f)) { // We hit the plane of the triangle, but outside the triangle return false; } const float t = f * e2.dot(q); if ((t > 0.0f) && (t < distance)) { // This is a new hit, closer than the previous one distance = t; baryCoord[0] = 1.0 - u - v; baryCoord[1] = u; baryCoord[2] = v; return true; } else { // This hit is after the previous hit, so ignore it return false; } }
bool Cylinder::intersectCap(const Ray &localRay, double &t) { if (localRay.direction().y() < 0.0) t = (0.5 * m_length - localRay.origin().y()) / localRay.direction().y(); else if (localRay.direction().y() > 0.0) t = (-0.5 * m_length - localRay.origin().y()) / localRay.direction().y(); else return false; QVector4D p = localRay.along(t); if (p.x() * p.x() + p.z() * p.z() < m_rSq) return true; return false; }
bool Sphere::hit( const Ray &r, double tmin, double tmax, SurfaceHitRecord &rec ) const { //*********************************************** //*********** WRITE YOUR CODE HERE ************** //*********************************************** Vector3d rayOrigin = r.origin() - center; // origin with respect to the sphere double a = 1; double b = 2 * dot(r.direction(), rayOrigin); double c = dot(rayOrigin, rayOrigin) - pow(radius, 2); double discriminant = pow(b, 2) - 4 * a * c; if (discriminant < 0) { return false; } double t1 = (-b + sqrt(discriminant)) / (2 * a); double t2 = (-b - sqrt(discriminant)) / (2 * a); double t0 = min(t1, t2); if (t0 < tmin || t0 > tmax) { return false; } rec.mat_ptr = matp; rec.p = r.pointAtParam(t0); rec.normal = (rec.p - center) / (rec.p - center).length(); rec.t = t0; return true; }
bool SceneNode::intersect(const Ray& ray, Intersection& i) const { // Transform the ray from WCS->MCS for this node Ray r(m_invtrans * ray.origin(), m_invtrans * ray.direction()); bool intersects = false; for(auto child : m_children) { Intersection j; if(child->intersect(r, j)) { // We need to see if this intersection point is closer than the previous intersection point // If it is than replace the previous intersection if(std::isinf(i.q[0]) || std::isinf(i.q[1]) || std::isinf(i.q[2]) || (j.q-r.origin()).length() < (i.q-r.origin()).length()) i = j; intersects = true; } } // If intersection occurs than transform the intersection point and the normal from MCS->WCS // We have to convert the intersection point from MCS->WCS and the normal from MCS->WCS // Normals must be multiplied by the transpose of the inverse to throw away scaling (no translations either, but the normal is // a vector and vectors can't be translated) but preserve rotation if(intersects) { i.q = m_trans * i.q; i.n = transNorm(m_invtrans, i.n); } return intersects; }
Color3 Raytracer::shadeDirectBSDF(const SurfaceSample& intersector, const Ray& ray) const { Color3 lightContribution(0,0,0); for (int i = 0; i < _currentScene->lighting()->lightArray.length(); ++i) { GLight& light = _currentScene->lighting()->lightArray[i]; const Point3& X = intersector.shadingLocation; const Point3& n = intersector.shadingNormal; const Vector3& diff = light.position.xyz() - X; const Vector3 w_i = diff.direction(); const float distance = diff.length(); const Vector3 w_eye = -ray.direction(); const Power3& Phi = light.color.rgb(); if (!isInSpotlight(light, w_i)) { continue; } if (isInShadow(intersector, w_i, distance)) { continue; } // power area const Color3& E_i = w_i.dot(n) * Phi / (4 * pif() * (distance*distance)); const SuperBSDF::Ref bsdf = intersector.material->bsdf(); const Color3& bsdfColor = bsdf->evaluate(intersector.shadingNormal, intersector.texCoord, w_i, w_eye).rgb(); lightContribution += bsdfColor * E_i + intersector.emit; } return lightContribution; }
Color3 Raytracer::shadePixel(const Tri::Intersector& intersector, const Ray& ray, int backwardBouncesLeft) const { Color3 pixelColor; Vector3 position, normal; Vector2 texCoord; intersector.getResult(position, normal, texCoord); SurfaceSample surfaceSample(intersector); if (_settings._useSuperBSDF) { if(_settings._useDirectShading) { pixelColor = shadeDirectBSDF(surfaceSample, ray); } pixelColor += shadeSpecularBSDF(surfaceSample, -ray.direction(), backwardBouncesLeft); if (_settings._usePhotonMap) { pixelColor += shadeIndirectIllumination(surfaceSample); } } else { pixelColor = myShadePixel(intersector, ray, backwardBouncesLeft); } return pixelColor; }
bool Sphere::hit(Ray& ray, HitInfo* hitInfo) { if (!m_boundingBox.doesHit(ray)) { return false; } Vector3 dist = m_center - ray.origin(); float b = ray.direction().dot(dist); float discriminant = m_radiusSq - dist.normSq() + b * b; if (discriminant < 0.0) { return false; } // two possible intersections float t = kNoHit; float t0 = b - sqrt(discriminant); float t1 = b + sqrt(discriminant); if (t0 > 0.0001) { t = t0; } else if (t1 > 0.0001) { t = t1; } Vector3 hitPosition = ray.pointAtDistance(t); Vector3 hitNormal = (hitPosition - m_center) * m_radiusInv; hitInfo->setDistance(t); hitInfo->setNormal(hitNormal); hitInfo->setMaterial(m_material); hitInfo->setPosition(hitPosition); hitInfo->setSurface(this); hitInfo->setRay(&ray); return true; }
std::tuple<bool, Ray> a4_reflect_perturbed(const Ray& reflected, const Vector3D& normal, double glossiness, const std::function<double()>& uniform) { Vector3D r = reflected.direction(); Vector3D na = -r; Vector3D U, V; // Get the basis vectors for the square of size <glossiness>x<glossiness> if(na[2] > na[0] && na[2] > na[1]) U = Vector3D(-na[1], na[0], 0.0); else if(na[1] > na[0]) U = Vector3D(-na[2], 0.0, na[0]); else U = Vector3D(0.0, -na[2], na[1]); U.normalized(); V = na.cross(U).normalized(); // Randomly generate a 2D point on the square double u = -(glossiness * 0.5) + uniform() * glossiness; double v = -(glossiness * 0.5) + uniform() * glossiness; // Use the 2D point and the basis vectors for the square to perturb the reflection ray to point to a location on the square Point3D rp = Point3D(r[0], r[1], r[2]) + u * U + v * V; // Set the new perturbed direction vector for the ray r = Vector3D(rp[0], rp[1], rp[2]); // Check if the perturbed ray is below the surface return std::tuple<bool, Ray>(normal.dot(r) < 0, Ray(reflected.origin(), r)); }
IntersectionPtrList Sphere::intersect( const Ray& ray ) const { // Calculate if there is an intersection const Imath::V3f rayStart = ray.start(); const float d = rayStart.x - m_centre.x; const float e = rayStart.y - m_centre.y; const float f = rayStart.z - m_centre.z; const Imath::V3f rayDir = ray.direction(); const float a = 1; const float b = 2 * ( rayDir.x * d + rayDir.y * e + rayDir.z * f ); const float c = ( d*d + e*e + f*f ) - m_radius*m_radius; const float determinant = b*b - 4 * a * c; if ( determinant < 0 ) { return IntersectionPtrList(); } // a is non-zero so no checks required const float intersectionDistancePlus = ( -b + sqrt( determinant ) ) / ( 2 * a ); const float intersectionDistanceMinus = ( -b - sqrt( determinant ) ) / ( 2 * a ); IntersectionPtrList intersections; // Minus distance should be closer then plus so put it in first intersections.push_back( new SphereIntersection( *this, ray, intersectionDistanceMinus ) ); intersections.push_back( new SphereIntersection( *this, ray, intersectionDistancePlus ) ); return intersections; }
QVector4D Cylinder::surfaceNormal(const QVector4D &p, const Ray &ray) { QVector4D lp = m_worldToObject * p; QMatrix4x4 a = m_worldToObject.transposed(); a.setRow(3, QVector4D(0.0, 0.0, 0.0, 1.0)); if (m_hasCaps && fabs(fabs(lp.y()) - m_length * 0.5) < MathUtils::dEpsilon) { // Return cap normal QVector4D n; if (lp.y() < 0.0) n = QVector4D(0.0, -1.0, 0.0, 0.0); else n = QVector4D(0.0, 1.0, 0.0, 0.0); return (a * n).normalized(); } else { // calculate cylinder normal QVector4D o = QVector4D(0.0, lp.y(), 0.0, 1.0); QVector4D n = lp - o; n = a * n; QVector4D rd = -ray.direction(); if (QVector4D::dotProduct(n, rd) < 0) return -n.normalized(); else return n.normalized(); } }
real Renderable::transformRayLambdaWorldToModel(const Ray &ray, const real lambda) const { this->updateTransforms(); Vec3 model_direction = mTransformInv.transformVector(ray.direction()); return lambda * model_direction.norm(); }
bool Cube::FindIntersection(const Ray& ray, double* t, Point3* point, Vector3* normal) const { const Point3& origin = ray.origin(); const Vector3& direction = ray.direction(); *t = std::numeric_limits<double>::max(); for (int i = 0; i < 3; ++i) { if (direction[i] == 0) // Ray is parallel to plane. continue; for (int j = -1; j <= 1; j += 2) { if (direction[i] * j > 0) // Ray hits the back of the plane. continue; double s = (j - origin[i]) / direction[i]; if (s >= kEpsilon && s < *t) { int k = (i + 1) % 3; double y = origin[k] + direction[k] * s; int l = (i + 2) % 3; double z = origin[l] + direction[l] * s; if (y >= -1 && y <= 1 && z >= -1 && z <= 1) { *t = s; *point = origin + direction * s; *normal = Vector3(); (*normal)[i] = j; } } } } return *t != std::numeric_limits<double>::max(); }