bool Tri::intersect(Ray& _ray, float* thit, Intersection* in) { Ray ray = _ray.transform(inverseTransform); if (!intersectP(ray)) { return false; } if (*thit < t) { return false; } p = ray.getPos() + ray.getDir() * t; w = p - a; vCrossW = glm::cross(v, w); uCrossW = glm::cross(u, w); if (glm::dot(vCrossW, vCrossU) < 0) { return false; } if (glm::dot(uCrossW, uCrossV) < 0) { return false; } beta = glm::length(vCrossW)/denom; gamma = glm::length(uCrossW)/denom; alpha = 1 - beta - gamma; if (!(beta <= 1 && gamma <= 1 && beta + gamma <= 1)) { return false; } *thit = t; in->localGeo.pos = mat4TimesVec3(getTransform(), (ray.getPos() + t * ray.getDir()), 1.0); in->localGeo.normal = getNormal(); //shift position slightly towards normal (epsilon shift) in->localGeo.pos = in->localGeo.pos + in->localGeo.normal * epsilon; in->primitive = this; return true; }
ptc::IntersectDescr Rectangle::intersect( const Ray& ray ) { const double dir_dot = normal_.dot( ray.getDir() ); const bool is_grazing = std::abs( dir_dot ) <= 1e-4; const bool is_wrong_side = !getIsDoubleSided() && dir_dot >= -1e-4; if( is_grazing || is_wrong_side ) { return IntersectDescr( this ); } const Vector center_vec = center_ - ray.getOrigin(); const double distance = -normal_.dot( center_vec ); const double param = distance / -dir_dot; const Vector intersect = ray.getOrigin() + param * ray.getDir(); const Vector intersect_vec = intersect - center_; const bool is_right_vec_ok = std::abs( right_.dot( intersect_vec ) ) <= .5 * width_; const bool is_up_vec_ok = std::abs( up_.dot( intersect_vec ) ) <= .5 * height_; if( is_right_vec_ok && is_up_vec_ok ) { return IntersectDescr( param, intersect, normal_, ray.getDir(), this ); } return IntersectDescr( this ); }
/** * Intersect a Ray with a plane defined by the 4 coefficients Ax + By + Cz + D = 0. * A,B,C are the plane normal */ bool planeIntersect(const Ray& r, const float *plane, PointF& intersection) { Normal normal(plane[0], plane[1], plane[2]); const PointF& rp = r.getPos(); float dotNormalRayDir = Math::dot3(normal, r.getDir()); // Is the ray perpendicular to the plane's normal? if (fabs(dotNormalRayDir) < PLANE_INTERSECTION_THRESHOLD) { return false; } // Determine which side of the plane the point is on float distFromPlane = Math::dot3(normal, rp) + plane[3]; float t = distFromPlane/dotNormalRayDir; // > 0 if ray and normal are in the same direction and // the ray is on the normal side of the plane or // If the ray and normal point in opposite directions and // the ray is not on the normal side of the plane if (t > 0) { return false; } intersection = Math::vec3AXPlusB(r.getDir(), -t, r.getPos()); return true; }
//(r⃗ ·r⃗)t2 +2r⃗ ·(r⃗o −cen⃗ter)t+(r⃗o −cen⃗ter)·(r⃗o −cen⃗ter)−R2 =0 bool Sphere::intersect(const Ray& r, const float tmin, float &t_max){ float t0, t1; // solutions for t if the ray intersects // analytic solution Vector3D L = r.getOrigin() - center; // std::cout << "L " << L << std::endl; float a = r.getDir().dot(r.getDir()); // std::cout << "a " << a << std::endl; float b = 2 * r.getDir().dot(L); // std::cout << "b " << b << std::endl; float c = L.dot(L) - (radius * radius ) ; // std::cout << "c " << c << std::endl; if (!solveQuadratic(a, b, c, t0, t1)) return false; if (t0 > t1) std::swap(t0, t1); if (t0 < 0) { t0 = t1; // if t0 is negative, let's use t1 instead if (t0 < 0) return false; // both t0 and t1 are negative } t_max = t0; return true; }
bool intersect_search(Ray ray, Triangle* trig, int nTriangles, PoI* poi) { float min_hit = 99999; int count = 0; float t_hit; for (count = 0; count < nTriangles; count ++) { Triangle t = trig[count]; //t.scale(2, 1, 1); //scale by x-axis by 2 bool hit = t.hit(ray, &t_hit); if (hit && t_hit < min_hit) { min_hit = t_hit; poi->setCollision(ray.getDir() * min_hit + ray.getPos()); poi->setColor(t.kd); Vector myNorm = t.getNormal(); //if normal faces the wrong way, then needs to do soemthing about it //cos(angle) = dot_product / (a.len * b.len) float cosine = myNorm.Vdot(ray.getDir()) / (myNorm.getMag() * ray.getDir().getMag()); if (cosine < 0) { myNorm = myNorm * -1; } poi->setNormal(t.getNormal()); } } if (min_hit != 99999) { return true; } return false; }
Intersect Sphere::intersect(Ray r) { Intersect::Intersect ret = *new Intersect::Intersect(); std::vector<float> d = r.getDir(); std::vector<float> e = r.getEye(); std::vector<float> eminusp(3); eminusp[0] = e[0] - position[0]; eminusp[1] = e[1] - position[1]; eminusp[2] = e[2] - position[2]; float ddotd = d[0]*d[0]+d[1]*d[1]+d[2]*d[2]; float empdot = eminusp[0]*eminusp[0] + eminusp[1]*eminusp[1] + eminusp[2]*eminusp[2]; float ddoteminusp = d[0]*eminusp[0] + d[1]*eminusp[1] + d[2]*eminusp[2]; float discriminant = sqrt(ddoteminusp * ddoteminusp - ddotd*(empdot - radius*radius)); if (discriminant >= 0) { ret.setHit(true); float scalar = -1.0f; float * scale = &scalar; std::vector<float> scaled(3); scaled = vScale(-1, d); //scaled[0] = d[0]*(-1); //scaled[1] = d[1]*(-1); //scaled[2] = d[2]*(-1); float sdotemp = scaled[0]*eminusp[0] + scaled[1]*eminusp[1] + scaled[2]*eminusp[2]; ret.setPoint(r.project((sdotemp+discriminant)/ddotd)); } return ret; }
bool Sphere::checkRay (const Ray& ray, worldUnit& range, Vector& dist) const { dist = position.diff(ray.getStart()); worldUnit a = ray.getDir().dotProduct(dist); auto squareLength = dist.dotProduct(); worldUnit D = squareRadius - squareLength + a * a; //There is no intersection with sphere if D < 0 if (D < 0.f) { return false; } worldUnit t = SQRT(D); if (squareLength >= squareRadius) { //We are outside sphere a -= t; } else { //We are inside sphere a += t; } if ( (a > 0.0f) && (a < range)) { range = a; return true; } return false; }
RGB SubsurfacePathtracer::subsurface(RayIntersection* p_intersection, Ray *p_ray) { int SSS_SAMPLES = 30; RGB color; float absFactor = 0.01f; for(int i = 0; i < SSS_SAMPLES; i++) { RGB sampleColor; Ray ray = p_intersection->object->getShader()->getSubsurfaceSampledRay(p_intersection->object, p_intersection->point, p_intersection->normal, p_ray->getDir(), p_intersection->uv); RayIntersection intersection; //test any intersection (for inner occulsion) if(ray.nearestIntersection(scene->getObjects(), scene->getObjectCount(), &intersection)) { if(intersection.normal.dot(ray.getDir()) > 0) { sampleColor = p_intersection->object->getShader()->getDiffuseIrradiance(intersection.object, intersection.point, intersection.normal, intersection.uv, ray.getDir(), scene); float absortion = 1 - (intersection.dist * absFactor); if(absortion < 0) { absortion = 0; } //printf("%f\n", sampleColor.r); sampleColor = sampleColor * absortion; color = color + sampleColor; } } } color = color / (float)SSS_SAMPLES; return color; }
Intersect Triangle::intersect(Ray r) { Intersect::Intersect ret = *new Intersect::Intersect(); float a = v1.getX() - v2.getX(); float b = v1.getY() - v2.getY(); float c = v1.getZ() - v2.getZ(); float d = v1.getX() - v3.getX(); float e = v1.getY() - v3.getY(); float f = v1.getZ() - v3.getZ(); float g = r.getDir().at(0); float h = r.getDir().at(1); float i = r.getDir().at(2); float j = v1.getX() - r.getEye().at(0); float k = v1.getY() - r.getEye().at(1); float l = v1.getZ() - r.getEye().at(2); float eiminushf = e*i - h*f; float gfminusdi = g*f - d*i; float dhminuseg = d*h - e*g; float akminusjb = a*k - j*b; float jcminusal = j*c - a*l; float blminuskc = b*l - k*c; float m = a*(eiminushf) + b*(gfminusdi) + c*(dhminuseg); float beta = (j*(eiminushf) + k*(gfminusdi) + l*(dhminuseg))/m; if (beta < 0) {return ret;} float gamma = (i*(akminusjb) + h*(jcminusal) + g*(blminuskc))/m; if (gamma < 0 || beta+gamma > 1) {return ret;} float t = (-1)*(f*(akminusjb) + e*(jcminusal) + d*(blminuskc))/m; std::vector<float> p; std::vector<float> vec1 = v1.toVec(); std::vector<float> vec2 = v2.toVec(); std::vector<float> vec3 = v3.toVec(); std::vector<float> sub1 = vSub(&vec2, &vec1); std::vector<float> sub2 = vSub(&vec3, &vec1); std::vector<float> scaled1 = vScale(&beta, &sub1); std::vector<float> scaled2 = vScale(&gamma, &sub2); std::vector<float> added1 = vAdd(&vec1, &scaled1); p = vAdd(&added1, &scaled2); ret.setPoint(p); return ret; }
Intersect Triangle::intersect(Ray r) { Intersect::Intersect ret = *new Intersect::Intersect(); float a = v1.getX() - v2.getX(); float b = v1.getY() - v2.getY(); float c = v1.getZ() - v2.getZ(); float d = v1.getX() - v3.getX(); float e = v1.getY() - v3.getY(); float f = v1.getZ() - v3.getZ(); float g = r.getDir().at(0); float h = r.getDir().at(1); float i = r.getDir().at(2); float j = v1.getX() - r.getEye().at(0); float k = v1.getY() - r.getEye().at(1); float l = v1.getZ() - r.getEye().at(2); float eiminushf = e*i - h*f; float gfminusdi = g*f - d*i; float dhminuseg = d*h - e*g; float akminusjb = a*k - j*b; float jcminusal = j*c - a*l; float blminuskc = b*l - k*c; float m = a*(eiminushf) + b*(gfminusdi) + c*(dhminuseg); float beta = (j*(eiminushf) + k*(gfminusdi) + l*(dhminuseg))/m; if (beta < 0) { return ret; } float gamma = (i*(akminusjb) + h*(jcminusal) + g*(blminuskc))/m; if (gamma < 0 || beta+gamma > 1) { return ret; } float t = (-1)*(f*(akminusjb) + e*(jcminusal) + d*(blminuskc))/m; std::vector<float> p(3); std::vector<float> vec1 = v1.toVec(); std::vector<float> vec2 = v2.toVec(); std::vector<float> vec3 = v3.toVec(); p[0] = vec1[0] + (vec2[0] - vec1[0])*beta + (vec3[0] - vec1[0])*gamma; p[1] = vec1[1] + (vec2[1] - vec1[1])*beta + (vec3[1] - vec1[1])*gamma; p[2] = vec1[2] + (vec2[2] - vec1[2])*beta + (vec3[2] - vec1[2])*gamma; ret.setPoint(vec1); return ret; }
HitInfo Sphere::intersection(const Ray & ray){ double a = Vector(ray.getDir()).dot(Vector(ray.getDir())); double b = 2*Vector(ray.getStart()).dot(ray.getDir()); double c = Vector(ray.getStart()).dot(Vector(ray.getStart()))-1; double discr = pow(b,2) - 4*a*c; double t1 =(-b-sqrt(discr))/(2*a); double t2 =(-b+sqrt(discr))/(2*a); double t = t2; if (t1<t2){ if(t1 >= 0){ t = t1; } } Point intersect = ray.getPoint(t); return HitInfo(t, intersect, mtrl, Vector(intersect)); }
/** Cast transmitted ray ** @param ray incoming ray ** @param pt intersection point ** @param normal normal of pt ** @param ior2 index of refraction of the object ** @return transmitted ray **/ Ray transmit(Ray ray, Vec pt, Vec normal, float ior1, float ior2){ Vec r = ray.getDir(); float alpha = ior1 / ior2; float c1 = normal.dot(r) * -1; float c2 = sqrt(1 - pow(alpha,2) * (1 - pow(c1,2))); Vec v = r * alpha + normal * (c1 * alpha - c2); Ray t(pt, v, 0, 9999, TransmittedRay); if (debugMode) { printf("transmitted ray origin: "); t.getOrig().print(); printf("transmitted ray direction: "); t.getDir().print(); } return t; }
bool Sphere::intersect(const Ray& ray, RaySurfIntersection& res)const{ res.shp = NULL; //Transform ray to object space const Ray rOb = w2o(ray); const Vector o = Vector(rOb.getOrigin().x, rOb.getOrigin().y, rOb.getOrigin().z); const Vector d = rOb.getDir(); const float A = d.dot(d); const float B = 2.0f * (d.dot(o)); const float C = o.dot(o) - (r * r); struct MathUtils::QuadraticEqnRes<float> slv = MathUtils::solveQuadratic<float>(A, B, C); float tHitFinal = 0.0f; //After the below code this will eventually be set to //the first hit point in front of the camera if(slv.solCount == 0){ return false; }else if(slv.solCount == 1){ tHitFinal = slv.sol1; if(tHitFinal < 0.0f){ //No solutions in front of camera return false; } }else{ //2 solutions //Find smallest t value that is > 0.0f if(slv.sol1 < 0.0f && slv.sol2 < 0.0f){ //No solutions in front of camera return false; }else{ //At least one hit in front of camera slv.sol1 = slv.sol1 < 0.0f ? Constants::MAX_FLOAT_VAL : slv.sol1; slv.sol2 = slv.sol2 < 0.0f ? Constants::MAX_FLOAT_VAL : slv.sol2; tHitFinal = std::min<float>(slv.sol1, slv.sol2); } } //Make sure hit is in front of camera Assert(tHitFinal >= 0.0f); res.tHit = tHitFinal; res.locWS = ray(res.tHit); Vector normalVecAtHit = res.locWS - o2w(Point(0.0f,0.0f,0.0f)); res.n = normalVecAtHit.getNormalized(); res.shp = this; return true; }
CIsect Plane::intersect(const Ray& ray) { float angle = dot(mNormal, ray.getDir()); if (fabs(angle) < FLOAT_ZERO) { return CIsect(false); } float t = (-(dot(ray.getOrg(), mNormal) + mD) / angle); if (t > 0.f) { CIsect res(true, t, this, getNormal(ray, t)); res.Dst.push_back(t); res.InsideIntervals.push_back(Span(t, t)); return res; } return CIsect(false); }
void Collide::raySphereCollide(const Body * ray_, const Body * sphere_) { Ray *ray = (Ray*)ray_; Sphere *sphere = (Sphere*)sphere_; Vector3 vec = ray->getStart() - sphere->getCenter(); setCollide(true); setDistance(0.0f); float fB = vec.Dot(ray->getDir()); float fC = vec.Dot(vec) - sphere->getRadius()*sphere->getRadius(); if (fC > 0.0f && fB > 0.0f) setCollide(false); float fDisc = fB*fB - fC; if (fDisc < 0.0f) setCollide(false); // compute the response vectors Vector3 responseObject1 = ray_->getCenter()- sphere_->getCenter(); Vector3 responseObject2 = sphere_->getCenter() - ray_->getCenter(); setResponseObject1(responseObject1); setResponseObject2(responseObject2); }
bool Tri::intersectP(Ray& ray) { t = (glm::dot(a, planeNormal) - glm::dot(ray.getPos(), planeNormal)) / glm::dot(ray.getDir(), planeNormal); if (t > 0) { return true; } else { return false; } }
Color Scene::shade(Intersection isect, Ray r, int level) { if (!isect.hits()) { return bgColor; } real eps; if (r.in()) { eps = 0.00001; } else { eps = -0.00001; } Texture *txt = isect.object()->getTexture(); Point isectPt = r.pointOn(isect.t()); Color curColor(0.0,0.0,0.0); Color specular(0,0,0); Color diffuse(0,0,0); Color shadowAmt(1,1,1); for (LightList::iterator lt_iter = lights.begin(); lt_iter != lights.end(); ++lt_iter) { Vector specL((*lt_iter)->location()-isectPt); Vector specV(cam.getLocation()-isectPt); Vector specHj((specL+specV)*(1.0/((specL+specV).length()))); Ray shade_ray = (*lt_iter)->getRayTo(r.pointOn(isect.t()+ eps)); ++shadow_rays_cast; Intersection tempI = rtrace(shade_ray, true, isect.object()); if (tempI.hits()) { if (level>0) { shadowAmt -= shade(tempI, shade_ray, level-1); } else { shadowAmt = Color(0.0,0.0,0.0); } } specular += (*lt_iter)->intensity()*std::pow(specHj.dot(isect.normal()), txt->n()); diffuse += (*lt_iter)->intensity()*shade_ray.getDir().dot(isect.normal()); } shadowAmt *= 1.0/real(lights.size()); Color reflective(0.0,0.0,0.0,0.0); if ((level>0) && (txt->kr().intensity()>0.01)) { ++reflective_rays_cast; Ray tempRay(r.pointOn(isect.t()+eps), r.getDir() - 2.0 * (r.getDir().dot(isect.normal())) * isect.normal()); reflective = shade(rtrace(tempRay), tempRay, level-1); } Color refractive(0.0,0.0,0.0); if ((level>0) && (txt->kt().intensity()>0.01)) { real eta; if (r.in()) { eta = 1.0/txt->ior(); } else { eta = txt->ior(); } real ci; if (r.in()) { ci = (r.getDir().dot(-1.0*isect.normal())); } else { ci = (r.getDir().dot(isect.normal())); } real costt = 1.0 - (eta*eta) * (1.0-ci*ci); if (costt<0.0) { refractive = Color(0,0,0); } else { ++refractive_rays_cast; Ray tempRay(r.pointOn(isect.t()+eps), ((eta*ci-std::sqrt(costt))*((r.in()?-1.0:1.0)*isect.normal()) - (eta*r.getDir())), !r.in()); refractive = shade(rtrace(tempRay, isect.object()), tempRay, level-1); } } curColor += txt->ka() + (txt->kd()*diffuse + txt->ks()*specular + txt->kr()*reflective + txt->kt()*refractive) * shadowAmt; return curColor.clamp(); }
Intersection Scene::rtrace(Ray r, bool computeNorm, Object *curObj) { ++rays_cast; Intersection bestIsect(9e99, false); size_t xi, yi, zi; int signx, signy, signz; int exy,exz,ezy; int rdx = int(std::floor(r.getDir().normal().i()*x_max)); int rdy = int(std::floor(r.getDir().normal().j()*y_max)); int rdz = int(std::floor(r.getDir().normal().k()*z_max)); int absRdx(std::abs(rdx)); int absRdy(std::abs(rdy)); int absRdz(std::abs(rdz)); getIdxOfPoint(r.getOrigin().x(), r.getOrigin().y(), r.getOrigin().z(), xi, yi, zi); exy = rdy-rdx; exz = rdz-rdx; ezy = rdy-rdz; signx=1; if (rdx<0.0) signx=-1; signy=1; if (rdy<0.0) signy=-1; signz=1; if (rdz < 0.0) signz=-1; while ((xi<width) && (yi<height) && (zi<depth) && (xi>=0) && (yi>=0) && (zi>=0)) { bestIsect = theGrid[xi][yi][zi]->intersect(r, computeNorm, &intersection_tests, &intersections); if (bestIsect.hits() && (bestIsect.object()!=curObj) && bestIsect.getGridEntry()==theGrid[xi][yi][zi]) { return bestIsect; } if (exy<0) { // Not y adjacent if (exz <0) { // X adjacent xi += signx; exy += absRdy; exz += absRdz; } else { // Z adjacent zi += signz; exz -= absRdx; ezy += absRdy; // Changed from ezy } } else { // Possibly y adjacent if (ezy < 0) { // Z adjacent zi += signz; exz -= absRdx; ezy += absRdy; } else { // Y adjacent yi += signy; exy -= absRdx; ezy -= absRdz; } } } return bestIsect; }
/** Ray Tracer ** @param ray the ray to be traced ** @param depth recursion depth ** @return color value **/ Vec trace(Ray ray, int depth){ if (debugMode) { printf("\nrecursion = %d\n", depth); printf("ray origin = "); ray.getOrig().print(); printf("ray direction = "); ray.getDir().print(); } if (depth == 0) return black; // return background color Vec color, local, reflected, transmitted; Vec pt, normal; float tClosest = ray.getTmax(); // set dis to a maximum value Shape *ObjPtr = NULL; // set the Obj pointer to null // look for intersection point for each object in the scene bool inside = false; for (ShapeIter its = scene.shapes.begin(); its != scene.shapes.end(); its++) { if ((*its) == ray.ObjPtr) continue; float t; if ((*its)->getType() == sphere) { Sphere *shape = dynamic_cast<Sphere*>(*its); if (shape->intersect(ray, t)) { if (t < tClosest && t > ray.getTmin()) { inside = (shape->intersect(ray, t) == -1) ? true : false; tClosest = t; // update tClosest ObjPtr = (*its); // set ObjPtr to point to the object } } } else if((*its)->getType() == polyhedron){ Polyhedron *shape = dynamic_cast<Polyhedron*>(*its); if (shape->intersect(ray, t)) { if (t < tClosest && t > ray.getTmin()) { tClosest = t; ObjPtr = (*its); } } } else if((*its)->getType() == triangleMesh){ TriangleMesh *shape = dynamic_cast<TriangleMesh*>(*its); if (shape->intersect(ray, t)) { if (t < tClosest && t > ray.getTmin()) { tClosest = t; ObjPtr = (*its); } } } } if (ObjPtr != NULL) { SurFinish appearance = ObjPtr->getSurFin(); float Kr = appearance.reflective; // reflectivity float Kt = appearance.transmission; // transmitivity float ior_obj = appearance.ior; // index of refraction pt = ray.calcDest(tClosest); // set the pos variable pt to the nearest intersection point normal = ObjPtr->calcNorm(pt); // normal of intersection point if (normal.dot(ray.getDir()) > 0) normal = normal * (-1); if(inside) normal = normal * (-1); local.setVec(0.0, 0.0, 0.0); // set local shading to black // for each light source in the scene for (LightIter itl = scene.lights.begin(); itl != scene.lights.end(); itl++){ Light *LightPtr = (*itl); // pointer to the light source // calculate local shading according to Phong model local = local + phongModel(pt, normal, LightPtr, ObjPtr, ray) / scene.numL; // Recursively cast reflected and refracted rays if (Kr > 0) { // specular reflective Ray refl = reflect(ray, pt, normal); refl.ObjPtr = ObjPtr; reflected = reflected + trace(refl, depth-1)/scene.numL; } if (Kt > 0 && ior_obj != 0) { // translucent Ray refr = transmit(ray, pt, normal, ior_air, ior_obj); refr.ObjPtr = ObjPtr; transmitted = transmitted + trace(refr, depth-1)/scene.numL; } } // update light color color.setVec(local + reflected * Kr + transmitted * Kt); } // if no intersection else { color.setVec(background); // set color to background color } if (debugMode == 1) { printf("\nPrinting information for depth = %d\n", depth); Vec orig = ray.getOrig(); Vec dir = ray.getDir(); printf("RAY:\n"); printf("origin = %f %f %f\n", orig.x, orig.y, orig.z); printf("direction = %f %f %f\n", dir.x, dir.y, dir.z); printf("INTERSECTION:\n"); printf("intersection point = %f %f %f\n", pt.x, pt.y, pt.z); printf("normal = %f %f %f\n", normal.x, normal.y, normal.z); printf("LIGHT VISIBILITY:\n"); printf("local shading = %f %f %f\n", local.x, local.y, local.z); printf("reflected shading = %f %f %f\n", reflected.x, reflected.y, reflected.z); printf("transmitted shading = %f %f %f\n", transmitted.x, transmitted.y, transmitted.z); printf("PIXEL COLOR:\n"); printf("color = %f %f %f\n", color.x, color.y, color.z); printf("\n"); } return color; }
Spectrum IntegratorHelpers::radianceDirect(const Scene* scene, const Ray& ray, const RaySurfIntersection& hit, const IntegratorHelpers::SpectralStrategy& ss) { //Memory for output spectrum //TODO: Remove all dynamic memory allocations from rendering inner loop //...for now this is still in here for east of implementation float* buf = new float[ss.numSpectralSamples]; for(int i = 0; i < ss.numSpectralSamples; i++){ buf[i] = 0.0f; } //Return spectrum Spectrum retColor(buf, ss.nmMin, ss.nmMax, ss.nmStep, ss.numSpectralSamples); //Create relavent params const Vector omega_o(-ray.getDir()); const Vector vecN(hit.n.x, hit.n.y, hit.n.z); const AccelStructure* geom = scene->getSceneGeom(); //Scene acceleration structure const bool isEmitter = hit.shp->isEmitter(); const Point hitLocWS(hit.locWS); //Determine the maximum number of light samples we will make //and allocate this memory OUTSIDE of the light loop int NLightSampsMax = -1; for(size_t i = 0; i < scene->getNumLights(); i++){ NLightSampsMax = std::max<int>( NLightSampsMax, scene->getLight(i)->getRecNumVisibilitySamples()); } Point* samps = new Point[NLightSampsMax]; //Process each light individually for(size_t i = 0; i < scene->getNumLights(); i++){ Light* l = scene->getLight(i); //Skip sampling the light itself if the geometry is an emitter if(isEmitter && hit.shp->getEmitter() == l){ continue; } //Sample the light source potentially many times const int N = l->getRecNumVisibilitySamples(); l->getSamples(samps, N); //Loop over all light samples const float invNumSamps = 1.0f / float(N); for(int j = 0; j < N; j++){ //Check if we can see the light VisibilityTester visTest(hitLocWS, samps[j], l->getGeom(), geom, DFLT_RAY_MOVE_EPSILON); //visTest.r is a ray to the light from hitLocWS //Get the incident radiance from the light at the hit location Spectrum L = l->sampleIncidentRadiance(hitLocWS, vecN, samps[j]); //TODO: "continue" here if the spectrum is black...is this any faster? //If we saw the light, add its contribution bool sawLight = visTest.visible(NULL); if(sawLight){ //Vector to light const Vector omega_i(visTest.r.getDir()); //Geomety term (solid angle) const Vector Nvec = hit.n; const float G = GeomUtils::absDotProd(omega_i, Nvec); //Technically, the above G is not correct! TODO //const Vector v = (samps[j] - hitLocWS); //const float r = v.magnitude(); //const float G = GeomUtils::absDotProd(omega_i, Nvec) / (r*r); //Transform vectors into local BRDF frame /* Vector w_i_brdfCS = BRDFCoordHelpers::worldCSToBrdfCS(omega_i, Nvec, hit.tangent, Nvec.cross(hit.tangent)); Vector w_o_brdfCS = BRDFCoordHelpers::worldCSToBrdfCS(omega_o, Nvec, hit.tangent, Nvec.cross(hit.tangent)); */ //Evaluate BRDF term at each wavelength float nm = ss.nmMin; BRDF* brdf = hit.shp->getBRDF(); for(int i = 0; i < ss.numSpectralSamples; i++){ buf[i] = brdf->f(omega_i, omega_o, nm); //buf[i] = brdf->f(w_i_brdfCS, w_o_brdfCS, nm); nm += ss.nmStep; } //Create a "spectrum" of BRDF values Spectrum brdfSpec(buf, ss.nmMin, ss.nmMax, ss.nmStep, ss.numSpectralSamples); //Light term retColor = retColor + (L * G * invNumSamps * brdfSpec); } } } //All done! delete[] samps; samps = NULL; delete[] buf; buf = NULL; return retColor; }
RGB SubsurfacePathtracer::trace(Ray p_ray, Vector3d cameraPos, int p_depth) { RGB radiance(0,0,0); RGB localRadiance(0,0,0); RayIntersection nearestRayInt; p_depth++; bool intersected = false; if(scene->kdTree == NULL) { intersected = p_ray.nearestIntersection(scene->getObjects(), scene->getObjectCount(), &nearestRayInt); } else { intersected = scene->kdTree->nearestIntersection(&p_ray, &nearestRayInt); } if(intersected) { if(!(nearestRayInt.object->getShader()->isLight() && p_ray.getDiffuse())) { //local ilumination: Vector3d viewVec = cameraPos - nearestRayInt.point; viewVec.normalize(); localRadiance = nearestRayInt.object->getShader()->getDiffuseRadiance(nearestRayInt.object, nearestRayInt.point, nearestRayInt.normal, nearestRayInt.uv, viewVec, scene); radiance = localRadiance; if(nearestRayInt.object->getShader()->hasSubsurface()) { radiance = radiance + subsurface(&nearestRayInt, &p_ray); //return subsurface(&nearestRayInt, &p_ray); } int outVecsCount = 0; RGB indirectRadiance; if(p_depth == 1) { for(int i = 0; i < 5; i++) { if(p_depth < maxDepth) { Ray outRays[10]; RGB values[10]; outVecsCount = nearestRayInt.object->getShader()->getBRDFSampledRays(nearestRayInt.object, nearestRayInt.point, nearestRayInt.normal, nearestRayInt.uv, viewVec, p_ray.getDir(), outRays, values); for(int s = 0; s < outVecsCount; s++) { Ray ray = outRays[s]; indirectRadiance = indirectRadiance + (trace(ray, cameraPos, p_depth) * values[s]) ; } } indirectRadiance; } indirectRadiance = indirectRadiance / 5; } else { if(p_depth < maxDepth) { Ray outRays[10]; RGB values[10]; outVecsCount = nearestRayInt.object->getShader()->getBRDFSampledRays(nearestRayInt.object, nearestRayInt.point, nearestRayInt.normal, nearestRayInt.uv, viewVec, p_ray.getDir(), outRays, values); for(int s = 0; s < outVecsCount; s++) { Ray ray = outRays[s]; indirectRadiance = indirectRadiance + (trace(ray, cameraPos, p_depth) * values[s]) ; } } } if(outVecsCount > 0) { radiance = radiance + indirectRadiance; } } } else if(scene->getBackground() != NULL) { radiance = scene->getBackground()->getRadianceAt(p_ray.getPoint(), p_ray.getPointAt(FAR_AWAY)); } return radiance; }
float Object::bound_box(Ray ray) const { float t, thit = HUGEREAL; float xmin, xmax, ymin, ymax, zmin, zmax; Vector Q; Vector i(1,0,0), j(0,1,0), k(0,0,1); Vector base = ray.getBase(); Vector dir = ray.getDir(); xmin = this->vmin.x; xmax = this->vmax.x; ymin = this->vmin.y; ymax = this->vmax.y; zmin = this->vmin.z; zmax = this->vmax.z; t = ray.intersect_plane(i, this->vmax); if(t > 0.001) { Q = base + dir.scale(t); if( (ymin <= Q.y) && (Q.y <= ymax) && (zmin <= Q.z) && (Q.z <= zmax) ) { thit = t; return thit; } } t = ray.intersect_plane(i.scale(-1), this->vmin); if(t > 0.001) { Q = base + dir.scale(t); if( (ymin <= Q.y) && (Q.y <= ymax) && (zmin <= Q.z) && (Q.z <= zmax) ) { thit = t; return thit; } } t = ray.intersect_plane(j, this->vmax); if(t > 0.001) { Q = base + dir.scale(t); if( (xmin <= Q.x) && (Q.x <= xmax) && (zmin <= Q.z) && (Q.z <= zmax) ) { thit = t; return thit; } } t = ray.intersect_plane(j.scale(-1), this->vmin); if(t > 0.001) { Q = base + dir.scale(t); if( (xmin <= Q.x) && (Q.x <= xmax) && (zmin <= Q.z) && (Q.z <= zmax) ) { thit = t; return thit; } } t = ray.intersect_plane(k, this->vmax); if(t > 0.001) { Q = base + dir.scale(t); if( (xmin <= Q.x) && (Q.x <= xmax) && (ymin <= Q.y) && (Q.y <= ymax) ) { thit = t; return thit; } } t = ray.intersect_plane(k.scale(-1), this->vmin); if(t > 0.001) { Q = base + dir.scale(t); if( (xmin <= Q.x) && (Q.x <= xmax) && (ymin <= Q.y) && (Q.y <= ymax) ) { thit = t; return thit; } } return thit; }
CIsect Cylinder::intersect(const Ray& ray) { const Vec3D& origin = ray.getOrg(); const Vec3D& direction = ray.getDir(); const Vec3D& CO = origin - mBottom; const Vec3D& u = direction - mAxis * (dot(direction, mAxis)); const Vec3D& v = CO - mAxis * (dot(CO, mAxis)); CIsect res = CIsect(true); // Let a, b and c be coefficients of some square equation const float a = dot(u, u); float root = 0.f; float closest = -1.f; float rayExit = -1.f; if (fabs(a) > FLOAT_ZERO) { const float b = 2 * dot(u, v); const float c = dot(v, v) - mRadius2; float D = b * b - 4 * a * c; // Complete miss if (D < 0.f) { return CIsect(false); } D = sqrtf(D); // Calculate roots and take closest float denom = 1 / (2 * a); root = (-b - D) * denom; if (root >= 0.f) { Vec3D toBottom = ray.apply(root) - mBottom; Vec3D toTop = ray.apply(root) - mTop; if (dot(mAxis, toBottom) > 0.f && dot(mAxis, toTop) < 0.f) { res.Dst.push_back(root); closest = root; } } root = (-b + D) * denom; if (root > 0.f) { // Awful copy paste :( Vec3D toBottom = ray.apply(root) - mBottom; Vec3D toTop = ray.apply(root) - mTop; if (dot(mAxis, toBottom) > 0.f && dot(mAxis, toTop) < 0.f) { res.Dst.push_back(root); if (closest < 0.f) { root = closest; } else if (root < closest) { rayExit = closest; closest = root; } else { rayExit = root; } } } } // dot(va, (q - p1)) = 0 t = (dot(va, p1) - dot(va, p)) / dot(va, v) // Find intersection with caps // Bottom one float axisToDir = dot(mAxis, direction); if (fabs(axisToDir) < FLOAT_ZERO) { if (closest > 0.f) { res.Distance = closest; res.Object = this; res.Normal = getNormal(ray, closest); if (rayExit < 0.f) { res.InsideIntervals.push_back(Span(0.f, closest)); res.Dst.insert(res.Dst.begin(), 0.f); } else { res.InsideIntervals.push_back(Span(closest, rayExit)); } return res; } return CIsect(false); } float axisToOrg = dot(mAxis, origin); //root = (dot(mAxis, mBottom) - axisToOrg) / axisToDir; float CODotAxis = dot(CO, mAxis); root = -CODotAxis / axisToDir; if (root > 0.f) { Vec3D toBottom = ray.apply(root) - mBottom; if (dot(toBottom, toBottom) < mRadius2) { res.Dst.push_back(root); // Awful copy paste :( if (closest < 0.f) { closest = root; } else if (root < closest) { rayExit = closest; closest = root; } else { rayExit = root; } } } // Top one //root = (dot(mAxis, mTop) - axisToOrg) / axisToDir; float CTDotAxis = dot(origin - mTop, -mAxis); root = CTDotAxis / axisToDir; if (root > 0.f) { // Awful copy paste :( Vec3D toTop = ray.apply(root) - mTop; if (dot(toTop, toTop) < mRadius2) { res.Dst.push_back(root); if (closest < 0.f) { closest = root; } else if (root < closest) { rayExit = closest; closest = root; } else { rayExit = root; } } } if (closest >= 0.f) { res.Distance = closest; res.Object = this; res.Normal = getNormal(ray, closest); if (rayExit < 0.f) { res.InsideIntervals.push_back(Span(0.f, closest)); res.Dst.insert(res.Dst.begin(), 0.f); } else { res.InsideIntervals.push_back(Span(closest, rayExit)); } return res; } return CIsect(false); }
bool Tracer::scatterSpecular(const IntersectDescr& node, Ray& ray) const { ray = Ray( node.point_, ray.getDir().reflect( node.normal_ ) ); return true; }
float Object::Shadow_box(Ray ray) const // Bounding box function for shadows { float t, thit = 1.0; float xmin, xmax, ymin, ymax, zmin, zmax; Vector Q; Vector i(1,0,0), j(0,1,0), k(0,0,1); Vector base = ray.getBase(); Vector dir = ray.getDir(); xmin = this->vmin.x; xmax = this->vmax.x; ymin = this->vmin.y; ymax = this->vmax.y; zmin = this->vmin.z; zmax = this->vmax.z; t = ray.intersect_plane(i, this->vmax); if( (t > 0.0) && (t < 1.0) ) { Q = base + dir.scale(t); if( (ymin <= Q.y) && (Q.y <= ymax) && (zmin <= Q.z) && (Q.z <= zmax) ) { thit = t; return thit; } } t = ray.intersect_plane(i.scale(-1), this->vmin); if( (t > 0.0) && (t < 1.0) ) { Q = base + dir.scale(t); if( (ymin <= Q.y) && (Q.y <= ymax) && (zmin <= Q.z) && (Q.z <= zmax) ) { thit = t; return thit; } } t = ray.intersect_plane(j, this->vmax); if( (t > 0.0) && (t < 1.0) ) { Q = base + dir.scale(t); if( (xmin <= Q.x) && (Q.x <= xmax) && (zmin <= Q.z) && (Q.z <= zmax) ) { thit = t; return thit; } } t = ray.intersect_plane(j.scale(-1), this->vmin); if( (t > 0.0) && (t < 1.0) ) { Q = base + dir.scale(t); if( (xmin <= Q.x) && (Q.x <= xmax) && (zmin <= Q.z) && (Q.z <= zmax) ) { thit = t; return thit; } } t = ray.intersect_plane(k, this->vmax); if( (t > 0.0) && (t < 1.0) ) { Q = base + dir.scale(t); if( (xmin <= Q.x) && (Q.x <= xmax) && (ymin <= Q.y) && (Q.y <= ymax) ) { thit = t; return thit; } } t = ray.intersect_plane(k.scale(-1), this->vmin); if( (t > 0.0) && (t < 1.0) ) { Q = base + dir.scale(t); if( (xmin <= Q.x) && (Q.x <= xmax) && (ymin <= Q.y) && (Q.y <= ymax) ) { thit = t; return thit; } } return thit; }