glm::vec3 Transparent::shade(const ShadeRec& sr)const { glm::vec3 L(Phong::shade(sr)); glm::vec3 incoming = -sr.ray.getDirection(); glm::vec3 reflected; glm::vec3 fr = reflectiveBrdf->sampleF(sr,incoming,reflected); Ray reflectedRay(sr.hitPoint,reflected); if(specularBtfd->tir(sr)) { //comment this out to remove the reflection and get cool effects L += sr.world.getTracer()->traceRay(reflectedRay,sr.depth + 1); //kr = 1.0 } else { glm::vec3 transmitted; glm::vec3 ft = specularBtfd->sampleF(sr,incoming,transmitted); Ray transmittedRay(sr.hitPoint,transmitted); glm::vec3 reflectedColor = sr.world.getTracer()->traceRay(reflectedRay,sr.depth + 1) * fabs(glm::dot(sr.normal,reflected)); fr.x *= reflectedColor.x; fr.y *= reflectedColor.y; fr.z *= reflectedColor.z; glm::vec3 transmittedColor = sr.world.getTracer()->traceRay(transmittedRay,sr.depth + 1) * fabs(glm::dot(sr.normal,transmitted)); ft.x *= transmittedColor.x; ft.y *= transmittedColor.y; ft.z *= transmittedColor.z; L += fr + ft; } return L; }
Vec sample(Vec const& N, Vec const& in, Vec const& color, float sampleX, float sampleY, Vec& out, bool& specular) const { // generate ray in hemisphere out = reflectedRay(N, in); specular = true; return Vec(1.f, 1.f, 1.f); }
Vec4d Raytracer::shade(const RayIntersection& intersection, size_t depth) const { // This offset must be added to intersection points for further // traced rays to avoid noise in the image const Vec3d offset(intersection.normal() * Math::safetyEps()); Vec4d color(0,0,0,1); std::shared_ptr<const Renderable> renderable = intersection.renderable(); std::shared_ptr<const Material> material = renderable->material(); for(size_t i=0;i <mScene->lights().size();++i) { const Light &light = *(mScene->lights()[i].get()); //Shadow ray from light to hit point. const Vec3d L = (intersection.position() + offset) - light.position(); const Ray shadowRay(light.position(), L); //Shade only if light in visible from intersection point. if (!mScene->anyIntersection(shadowRay,L.length())) color += material->shade(intersection,light); } // limit recursion depth if (depth >= mMaxDepth) return color; Vec3d dir = reflect(intersection.ray().direction(), intersection.normal()); Ray reflectedRay(intersection.position() + offset, dir); double reflectance = material->reflectance(); color = color * (1 - reflectance) + reflectance * trace(reflectedRay, depth - 1) + Vec4d(0.0,0.0,0.0,1.0); return color; }
Point3D RayScene::GetColor(Ray3D ray,int rDepth,Point3D cLimit){ if (rDepth == 0) {return Point3D();} if (cLimit[0] > 1 && cLimit[1] > 1 && cLimit[2] > 1) {return Point3D();} RayIntersectionInfo iInfo; double resp = group->intersect(ray, iInfo, -1); if (resp > 0) { //Calculating reflection values. Point3D reflectedDirection = Reflect(ray.direction, iInfo.normal); Ray3D reflectedRay(iInfo.iCoordinate+(reflectedDirection.unit()*0.0001), reflectedDirection.unit()); //Calculating and finding the refraction values. Point3D refractedDirection; double refIndex; if (ray.direction.dot(iInfo.normal) < 0) { refIndex = iInfo.material->refind; } else { refIndex = 1/iInfo.material->refind; } int refract = Refract(ray.direction.unit(), iInfo.normal.unit(), refIndex, refractedDirection); Ray3D refractedRay(iInfo.iCoordinate+(refractedDirection.unit()*0.0001), refractedDirection.unit()); Point3D refractedTransparency = iInfo.material->transparent; //Calculating light contributions to the point. Point3D diffuse = Point3D(0,0,0); Point3D specular = Point3D(0,0,0); for (int i=0; i<lightNum; i++) { RayIntersectionInfo iInfo2 = iInfo; int iSectCount = 0; Point3D diffuseResp = lights[i]->getDiffuse(camera->position, iInfo2); Point3D specularResp = lights[i]->getSpecular(camera->position, iInfo2); Point3D transparency = lights[i]->transparency(iInfo2, group, cLimit); diffuse += diffuseResp*transparency; specular += specularResp*transparency; } Point3D response = iInfo.material->ambient*ambient+iInfo.material->emissive + diffuse + specular + GetColor(reflectedRay, rDepth-1, cLimit/iInfo.material->specular) + GetColor(refractedRay, rDepth-1, cLimit/iInfo.material->specular)*refractedTransparency; for (int i = 0; i <3; i++) { if (response[i] < 0) { response[i] = 0; } if (response[i] > 1) { response[i] = 1; } } return response; } else if (ray.position[0]==camera->position[0] && ray.position[1]==camera->position[1] && ray.position[2]==camera->position[2]) { return background; } else return Point3D(); }
// Light that bounces multiple times before reaching the eye Rgb Reflector::indirectRadiance(Intersection *intersection, Ray ray, Scene *scene, int depth) { Vector3 towardsViewer = ray.getDirection().normalized(); Vector3 normal = intersection->getSurface()->computeSurfaceNormal(intersection->getIntersectionPoint()).normalized(); Ray reflectedRay(intersection->getIntersectionPoint(), towardsViewer.reflect(normal), ray.getRefractiveIndex(), ray.getMaxDepth()); return kReflectivity * scene->trace(reflectedRay, EPSILON, depth + 1).getPixelColor(); }
RTRay RTRayTracer::genReflectionRay(RTVector d, RTVector n,RTVector closestPoint) { RTVector reflectionDir = (n*2*n.dot(d))-d; reflectionDir.normalize(); reflectionDir=-reflectionDir; double bias = 1e-4; RTVector aux(closestPoint+n*bias); RTPoint vertice(aux.getX(),aux.getY(),aux.getZ()); RTRay reflectedRay(vertice,reflectionDir); return reflectedRay; }
Vec refractedRay(Vec const& N, Vec const& I, float n) { float cosi = dot(I,N); float rad = 1-(1-cosi*cosi)/(n*n); if (rad < 0) { // total internal reflection //std::cout << "T.I.R.\n"; return reflectedRay(N, I); } float Nc = sqrt(rad) - cosi/n; float Ic = 1/n; //std::cout << Ic << ' , ' << Nc << '\n'; return - Ic * I - Nc * N; }
glm::vec3 Matte::pathShade(const ShadeRec& sr)const { glm::vec3 incoming = -sr.ray.getDirection(); glm::vec3 reflected; float pdf; glm::vec3 fr = diffuseBrdf->sampleF(sr,incoming,reflected,pdf); Ray reflectedRay(sr.hitPoint,reflected); glm::vec3 reflectedColor = sr.world.getTracer()->traceRay(reflectedRay,sr.depth + 1); fr.x *= reflectedColor.x; fr.y *= reflectedColor.y; fr.z *= reflectedColor.z; return fr * glm::dot(sr.normal,reflected) / pdf; }
// Light that bounces multiple times before reaching the eye Rgb Dielectric::indirectRadiance(Intersection *intersection, Ray ray, Scene *scene, int depth) { /* * IDEA: Set index of refraction to be the same as the airs. In this event, should go straight through * and the towardsViewer and refracted vector should differ in sign value (ie, they will be pointing * in opposite directions, but parallel) */ //TODO: Might as well store the surface normal with the intersection Vector3 towardsViewer = -ray.getDirection().normalized(); Vector3 normal = intersection->getSurface()->computeSurfaceNormal(intersection->getIntersectionPoint()).normalized(); Ray reflectedRay(intersection->getIntersectionPoint(), -towardsViewer.reflect(normal), ray.getRefractiveIndex(), ray.getMaxDepth()); // Add refracted ray bool isReflected = false; Vector3 refractedDirection = towardsViewer.refract(normal, ray.getRefractiveIndex(), refractiveIndex, isReflected); Ray refractedRay(intersection->getIntersectionPoint(), refractedDirection, refractiveIndex, ray.getMaxDepth()); // Compute fresnel double fresnel = computeFresnel(towardsViewer, normal, ray.getRefractiveIndex(), refractiveIndex); Rgb radiance; if (fresnel >= 1.0 || isReflected == true) { radiance = scene->trace(reflectedRay, EPSILON, depth + 1).getPixelColor(); } else { Rgb refractedColor = scene->trace(refractedRay, EPSILON, depth + 1).getPixelColor(); Rgb reflectedColor = scene->trace(reflectedRay, EPSILON, depth + 1).getPixelColor(); radiance.u.a[0] = (1.0 - fresnel) * refractedColor.u.a[0] + (fresnel) * reflectedColor.u.a[0]; radiance.u.a[1] = (1.0 - fresnel) * refractedColor.u.a[1] + (fresnel) * reflectedColor.u.a[1]; radiance.u.a[2] = (1.0 - fresnel) * refractedColor.u.a[2] + (fresnel) * reflectedColor.u.a[2]; } return kAbsorption * radiance; }
float3 trace(const Ray& ray, int depth) { Hit hit = firstIntersect(ray); // If ray hits nothing, we return the aurora borealis if(hit.t < 0) { return ray.dir * ray.dir * float3(0,1,0.6); } float3 lightSum = {0,0,0}; for(LightSource *l : lightSources) { float3 li = l->getLightDirAt(ray.origin); float dist = l->getDistanceFrom(hit.position); int maxDepth = 5; // Deals with shadows Ray shadowRay(hit.position + (hit.normal*0.1), li); Hit shadowHit = firstIntersect(shadowRay); if(shadowHit.t > 0 && shadowHit.t < dist) continue; // Handles types of materials differently if(depth > maxDepth) return lightSum; if(hit.material->reflective){ // for smooth surface float3 reflectionDir = hit.material->reflect(ray.dir, hit.normal); Ray reflectedRay(hit.position + hit.normal*0.1, reflectionDir ); lightSum += trace(reflectedRay, depth+1) * hit.material->getReflectance(ray.dir, hit.normal); } if(hit.material->refractive) { // for smooth surface float3 refractionDir = hit.material->refract(ray.dir, hit.normal); Ray refractedRay(hit.position - hit.normal*0.1, refractionDir ); lightSum += trace(refractedRay, depth+1) * (float3(1,1,1) - hit.material->getReflectance(ray.dir, hit.normal)); } else { // for rough surface lightSum += hit.material->shade(hit.normal, -ray.dir, l->getLightDirAt(hit.position), l->getPowerDensityAt(hit.position)); } } return lightSum; }
bool Scene::traceRay(Ray& ray, RenderOption option, float refractiveIndex, int level, Color* acc, HitInfo* hitInfo) { if (level > kMaxTraceLevel) { return false; } *acc = kColorBlack; if (m_rootGroup->hit(ray, hitInfo)) { Vector3 hitPosition = hitInfo->position; Vector3 hitNormal = hitInfo->normal; MaterialRef hitMaterial = hitInfo->material; if (option & RenderMaterialAmbience) { Color materialColor; if (hitMaterial->texture()) { materialColor = hitMaterial->texture()->texelAt(hitInfo->uv); } else { materialColor = hitMaterial->color(); } *acc += hitMaterial->ambient() * materialColor * (1.0f - hitMaterial->transparency()); } for (unsigned int i = 0; i < m_lights.size(); i++) { LightRef light = m_lights[i]; *acc += light->luminanceOfMaterialAt(*hitInfo, this, option) * (1.0f - hitMaterial->transparency()); if (option & RenderReflection) { if (hitMaterial->reflectivity() > 0.0f && level < kMaxTraceLevel) { float reflection = 2.0 * ray.direction().dot(hitNormal); Vector3 reflectionDirection = (ray.direction() - (hitNormal * reflection)).normalize(); Ray reflectedRay(hitPosition, reflectionDirection); HitInfo reflectionInfo; Color reflectedColor = kColorBlack; if (traceRay(reflectedRay, option, refractiveIndex, level + 1, &reflectedColor, &reflectionInfo)) { reflectedColor = reflectedColor * hitMaterial->reflectivity(); *acc += reflectedColor * (1.0f - hitMaterial->transparency()); } } } if (option & RenderTransparency) { if (hitMaterial->transparency() > 0.0f && level < kMaxTraceLevel) { float n = refractiveIndex / hitMaterial->refractiveIndex(); float cosA = -ray.direction().dot(hitNormal); float cosB = sqrtf(1.0f - n * n * (1 - cosA * cosA)); if (cosB > 0.0f) { Vector3 refracDirection = (n * ray.direction()) + (n * cosA - cosB) * hitNormal; Vector3 refracRayOrigin = hitPosition + refracDirection * EPSILON; Ray refracRay(refracRayOrigin, refracDirection); HitInfo refracInfo; Color refracColor = kColorBlack; if (traceRay(refracRay, option, refractiveIndex, level + 1, &refracColor, &refracInfo)) { refracColor = refracColor * hitMaterial->transparency(); Color absorbance = hitMaterial->color() * 0.15f * -refracInfo.distance; Color transparency = Color(expf(absorbance.red), expf(absorbance.green), expf(absorbance.blue)); refracColor = refracColor * transparency; *acc += refracColor; } } } } } } return true; }
glm::vec3 Dielectric::shade(const ShadeRec& sr)const { glm::vec3 L; //glm::vec3 L = Phong::shade(sr); glm::vec3 reflected; glm::vec3 incoming(-sr.ray.getDirection()); glm::vec3 fr = fresnelBrdf->sampleF(sr,incoming,reflected); Ray reflectedRay(sr.hitPoint,reflected); float t = 0.0f; glm::vec3 Lr, Lt; float nDotR = glm::dot(sr.normal,reflected); if(fresnelBtdf->tir(sr)) { if(nDotR < 0.0) { //reflected ray is inside Lr = sr.world.getTracer()->traceRay(reflectedRay,t,sr.depth + 1); glm::vec3 colorFilter = glm::pow(colorFilterIn,glm::vec3(t)); L.x += colorFilter.x * Lr.x; L.y += colorFilter.y * Lr.y; L.z += colorFilter.z * Lr.z; } else { //reflected ray is outside Lr = sr.world.getTracer()->traceRay(reflectedRay,t,sr.depth + 1); glm::vec3 colorFilter = glm::pow(colorFilterOut,glm::vec3(t)); L.x += colorFilter.x * Lr.x; L.y += colorFilter.y * Lr.y; L.z += colorFilter.z * Lr.z; } } else { //no total internal reflection glm::vec3 transmitted; glm::vec3 ft = fresnelBtdf->sampleF(sr,incoming,transmitted); Ray transmittedRay(sr.hitPoint,transmitted); float nDotT = glm::dot(sr.normal,transmitted); if(nDotT > 0.0) { //reflected ray is inside Lr = sr.world.getTracer()->traceRay(reflectedRay,t,sr.depth +1) * fabs(nDotR); Lr.x *= fr.x; Lr.y *= fr.y; Lr.z *= fr.z; glm::vec3 colorFilterR = glm::pow(colorFilterIn,glm::vec3(t)); L.x += colorFilterR.x * Lr.x; L.y += colorFilterR.y * Lr.y; L.z += colorFilterR.z * Lr.z; //transmitted ray is outside Lt = sr.world.getTracer()->traceRay(transmittedRay,t,sr.depth +1) * fabs(nDotT); Lt.x *= ft.x; Lt.y *= ft.y; Lt.z *= ft.z; glm::vec3 colorFilterT = glm::pow(colorFilterOut, glm::vec3(t)); L.x += colorFilterT.x * Lt.x; L.y += colorFilterT.y * Lt.y; L.z += colorFilterT.z * Lt.z; } else { //reflected ray is outisde Lr = sr.world.getTracer()->traceRay(reflectedRay,t,sr.depth +1) * fabs(nDotR); Lr.x *= fr.x; Lr.y *= fr.y; Lr.z *= fr.z; glm::vec3 colorFilterR = glm::pow(colorFilterOut,glm::vec3(t)); colorFilterR.x *= Lr.x; colorFilterR.y *= Lr.y; colorFilterR.z *= Lr.z; L += colorFilterR; //transmitted ray is inside Lt = sr.world.getTracer()->traceRay(transmittedRay,t,sr.depth +1) * fabs(nDotT); Lt.x *= ft.x; Lt.y *= ft.y; Lt.z *= ft.z; glm::vec3 colorFilterT = glm::pow(colorFilterIn,glm::vec3(t)); colorFilterT.x *= Lt.x; colorFilterT.y *= Lt.y; colorFilterT.z *= Lt.z; L += colorFilterT; } } return L; }
Geometry* Raytracer::Raytrace(Ray &r, Color &col, int depth, float &dist) { if(depth > TRACEDEPTH) return NULL; dist = MAX_DIST; Vector intersection, L, N, V, R, sampleDir, samplePos; Geometry *geom = NULL; //int result = 0; int res; float dot, diff, spec, shade = 0.0f, ldist, rdist, tempdist, ambient; float step = 1.0f / lrflti(shadowQuality); Color diffuse, specular, reflection, accumulator; Ray shadow, ambientRay; bool inShade; //find the nearest intersection vector<Geometry *> &gv = sc->GetObjects(); for(vector<Geometry *>::iterator git = gv.begin(); git != gv.end(); git++) { if((*git)->GetType() == Geometry::BVHACCEL) { BVH *bvh = static_cast<BVH *>(*git); Geometry *ng = NULL; res = bvh->IntersectRecursive(r, dist, &ng); if(res) { geom = ng; } } else { res = (*git)->Intersect(r, dist); if(res) { geom = *git; //result = res; } } } //if there's no hit, terminate the ray if(!geom) return NULL; if(geom->IsLight()) { col = geom->GetMaterial().GetColor() * geom->GetLightIntensity(); } else { //determine the point of intersection intersection = r.origin + (r.direction * dist); //accumulate the lighting vector<Geometry *> &lov = sc->GetObjects(); for(vector<Geometry *>::iterator lit = lov.begin(); lit != lov.end(); lit++) { if(((*lit)->IsLight()) && ((*lit)->GetType() == Geometry::SPHERE)) { L = ((Sphere *)(*lit))->GetPosition() - intersection; ldist = L.Length(); L /= ldist; if(geom->GetType() == Geometry::SDFUNC) { N = geom->GetNormal(intersection); shadow.origin = intersection + N * (10.0f * EPSILON); } else { shadow.origin = intersection + L * EPSILON; } //shadow if(shadowQuality == 1) { Geometry *lcache = (*lit)->GetLightCacheItem(omp_get_thread_num()); shade = 1.0f; shadow.direction = L; //try shadow cache first bool lightCacheHit = false; if(lcache && (lcache->Intersect(shadow, ldist))) { lightCacheHit = true; shade = 0.0f; } //now iterate through the geometry if(!lightCacheHit) { vector<Geometry *> &sov = sc->GetObjects(); for(vector<Geometry *>::iterator sit = sov.begin(); sit != sov.end(); sit++) { if((*sit != *lit) && (*sit != lcache) && ((*sit)->Intersect(shadow, ldist))) { (*lit)->SetLightCacheItem(*sit, omp_get_thread_num()); shade = 0.0f; break; } } } } else { shade = 0.0f; int i; //apparently parallel shadows slows it down //#pragma omp parallel for default(none) shared(light, intersection, ldist, numItems, step) private(i, inShade, tempdist, shadowObj, s) firstprivate(shadow) reduction(+:shade) schedule(dynamic, 1) for(i = 0; i < shadowQuality; i++) { Geometry *lcache = (*lit)->GetLightCacheItem(omp_get_thread_num()); shadow.direction = (*lit)->GeneratePoint() - intersection; shadow.direction.Normalize(); inShade = false; tempdist = ldist; //try shadow cache first bool lightCacheHit = false; if(lcache && (lcache->Intersect(shadow, tempdist))) { lightCacheHit = true; shade = 0.0f; } //now iterate through the geometry if(!lightCacheHit) { vector<Geometry *> &sov = sc->GetObjects(); for(vector<Geometry *>::iterator sit = sov.begin(); sit != sov.end(); sit++) { if((*sit != *lit) && (*sit != lcache) && ((*sit)->Intersect(shadow, tempdist))) { (*lit)->SetLightCacheItem(*sit, omp_get_thread_num()); inShade = true; break; } } } //update the shading if(!inShade) { shade += step; } } } //make sure the point isn't in a shadow if(shade != 0.0f) { N = geom->GetNormal(intersection); //diffuse if(geom->GetMaterial().GetDiffuse() > 0) { dot = N.Dot(L); if(dot > 0) { diff = dot * geom->GetMaterial().GetDiffuse(); diffuse = geom->GetMaterial().GetColor() * (*lit)->GetMaterial().GetColor() * diff; } } //specular if(geom->GetMaterial().GetSpecular() > 0) { V = r.direction; R = L - N * L.Dot(N) * 2.0f; dot = V.Dot(R); if(dot > 0) { spec = powf(dot, 20.0f) * geom->GetMaterial().GetSpecular(); specular = geom->GetMaterial().GetSpecularColor() * (*lit)->GetMaterial().GetColor() * spec; } } col += (diffuse + specular) * shade; //col += geom->GetMaterial().GetColor(); } } } //end light loop //calculate ambient lighting if(occlusion > 0) { //setup needed for both types of AO ambient = 0.0f; //we can use really fake and fast AO for SDFs if(geom->GetType() == Geometry::SDFUNC) { //this type of AO calculation needs far less "rays" occlusion /= 12; if(occlusion == 0) occlusion = 1; //from Rendering Worlds With Two Triangles paper //ao = 1 - k * sum(1, 5, 1/(2^i) * (pink(i) - yellow(i))); // pink(i) = distance from intersection point to sample point along the normal // = delta * i // yellow(i) = distance from sample point to surface // = distfield(intersection + delta * i * n) N = geom->GetNormal(intersection); SDF *sdf = reinterpret_cast<SDF *>(geom); float sum = 0.0f; float k = 0.3f; // magic number for choosing overall strength of AO float scale = 1.0f; float delta = 0.1f; // magic number for sample distances for(int i = 1; i <= occlusion; i++) { scale *= 0.5f; float pink = delta * static_cast<float>(i); Vector sample = intersection + (N * pink); float yellow = sdf->distance(sample); sum += scale * fmax(pink - yellow, 0.0f); //note that pink >= yellow since the intersection point is the furthest possible you could go } ambient = k * (1.0f - sum); } else { //initialize the ambient light float u, v, sqrtv, angle, ambdist; bool intersected; Vector sampleDir; float invsamples = 1.0f / lrflti(occlusion); //shoot out cosine weighted rays for(int i = 0; i < occlusion; i++) { u = lrflti(rand()) * MAX_RAND_DIVIDER * TWOPI; v = lrflti(rand()) * MAX_RAND_DIVIDER; sqrtv = sqrtf(v); sampleDir = Vector(cosf(u) * sqrtv, sinf(u) * sqrtv, sqrtf(1.0f - v)); N = geom->GetNormal(intersection); angle = N.Dot(sampleDir); if(angle < 0) { sampleDir *= -1.0f; angle = -angle; } intersected = false; if(geom->GetType() == Geometry::SDFUNC) { ambientRay.origin = intersection + N * (10.0f * EPSILON); } else { ambientRay.origin = intersection + sampleDir * EPSILON; } ambientRay.direction = sampleDir; ambdist = MAXDEPTH; vector<Geometry *> &aov = sc->GetObjects(); for(vector<Geometry *>::iterator aoit = aov.begin(); aoit != aov.end(); aoit++) { if((!(*aoit)->IsLight()) && ((*aoit)->Intersect(ambientRay, ambdist))) { intersected = true; break; } } if(!intersected) { ambient += invsamples * angle; } } } col += geom->GetMaterial().GetColor() * geom->GetMaterial().GetDiffuse() * ambient; } //get reflection if(geom->GetMaterial().GetReflectivity() > 0) { if(depth < TRACEDEPTH) { /*N = geom->GetNormal(intersection); R = r.direction - N * (2.0f * N.Dot(r.direction)); Raytrace(Ray(intersection + R * EPSILON, R), reflection, depth + 1, rdist); col += reflection * geom->GetMaterial().GetColor() * geom->GetMaterial().GetReflectivity();*/ N = geom->GetNormal(intersection); R = r.direction - N * (2.0f * N.Dot(r.direction)); samplePos = intersection + R * EPSILON; Ray reflectedRay(samplePos, R); Raytrace(reflectedRay, accumulator, depth + 1, rdist); for(int i = 1; i < reflectionBlur; i++) { float x = ((0.2f * lrflti(rand())) / RAND_MAX) - 0.1f; float y = ((0.2f * lrflti(rand())) / RAND_MAX) - 0.1f; float z = ((0.2f * lrflti(rand())) / RAND_MAX) - 0.1f; sampleDir = R + Vector(x, y, z); sampleDir.Normalize(); Ray sampleRay(samplePos, sampleDir); Raytrace(sampleRay, reflection, depth + 1, rdist); accumulator += reflection; } if(reflectionBlur > 1) accumulator /= lrflti(reflectionBlur); col += accumulator * geom->GetMaterial().GetColor() * geom->GetMaterial().GetReflectivity(); } } } return geom; }
Vec3f Ray::getColor(const vector <tinyobj::shape_t> &shapes, const vector <tinyobj::material_t> &materials, Vec3f lightSource) { if (DBG) cout << "[getColor] depth = " << depth << endl; //get triangle that intersect the ray Vec3f triangle[3]; pair <int, int> triangleId = this->getIntersectTriangle(shapes, triangle); DBG && cout << "\t[triangleId] " << triangleId.first << ' ' << triangleId.second << endl; if (triangleId.first == -1) { DBG && cout << "\t[return] no intersection" << endl; return Vec3f(0.0, 0.0, 0.0); } Vec3f reversedDirection = this->direction * -1; if (dot(reversedDirection, getNormalwithRayComes(triangle, this->direction)) < 0) { DBG && cout << "[return] " << endl; return Vec3f(0.0, 0.0, 0.0); } //check if position and lightsource are in different sides of the triangle Vec3f intersection; Vec3f color_direct; unsigned int iMaterial = shapes[triangleId.first].mesh.material_ids[triangleId.second]; if (lineCutTrianglePlane(triangle, this->direction, this->position, lightSource)) { DBG && cout << "\t[message] lineCutTrianglePlane" << endl; color_direct = Vec3f(0.0, 0.0, 0.0); } else { //calculate intersection this->intersect_remake(triangle, intersection); //check reflected ray Ray reflectedRay(intersection, lightSource - intersection, bshRoot, 0, triangleId); if (reflectedRay.canReach(lightSource, shapes) == false) { DBG && cout << "\t[message] reflected ray cannot reach lightsource" << endl; color_direct = Vec3f(0.0, 0.0, 0.0); } else { //calculate color_direct float radian_direct = ggx(this->position, lightSource, intersection, triangle, 1.0, 0.8, 0.8, 2.0); // color_direct = Vec3f( (materials[iMaterial].diffuse[0] + materials[iMaterial].specular[0]) * radian_direct, // (materials[iMaterial].diffuse[1] + materials[iMaterial].specular[1]) * radian_direct, // (materials[iMaterial].diffuse[2] + materials[iMaterial].specular[2]) * radian_direct); color_direct = Vec3f( (materials[iMaterial].diffuse[0]) * radian_direct, (materials[iMaterial].diffuse[1]) * radian_direct, (materials[iMaterial].diffuse[2]) * radian_direct); DBG && cout << "\t[color] " << color_direct << endl; } } Vec3f color_indirect(0.0, 0.0, 0.0); int counter = 0; if (depth < MAX_DEPTH) { for (int iRay = 0; iRay < NUMBER_OF_RAYS; ++iRay) { Ray ray = this->getRandomRay_Sphere(intersection, triangle, depth + 1, triangleId); // if (triangleId.first == 4) // ray = this->getMirrorRay(intersection, triangle, depth + 1, triangleId); // Ray ray = this->getRandomRay_Sphere(intersection, triangle, depth + 1, triangleId); // Ray ray = this->getInConeRay(intersection, triangle, depth + 1, triangleId); // Ray ray = this->getUniformRay_Plane(intersection, triangle, depth + 1, triangleId, iRay, NUMBER_OF_RAYS); // Ray ray = this->getMirrorRay(intersection, triangle, depth + 1, triangleId); Vec3f color = ray.getColor(shapes, materials, lightSource); float cos_theta = dot(ray.direction, getNormalwithRayComes(triangle, this->direction)); Vec3f w = lightSource - intersection; Vec3f w0 = this->position - intersection; Vec3f n = getNormalwithRayComes(triangle, this->direction); w.normalize(); w0.normalize(); n.normalize(); float f_s = brdf_GGX(w, w0, n, 0.8, 0.8); float f_d = f_Lambert(2.0); // float f_d = 0; color_indirect += color * (f_s + f_d) * fabs(cos_theta); // color_indirect += color * (f_s + f_d); counter++; } if (counter > 0) color_indirect /= counter; DBG && cout << "\t[color_indirect] = " << color_indirect << endl; } DBG && cout << "\t[counter] " << counter << endl; DBG && cout << "\t[color] " << color_direct << endl; // color_direct = (color_direct * 0.5) + (color_indirect * 0.5); color_direct += (1.0f * color_indirect); for (int i = 0; i < 3; ++i) color_direct[i] = min(color_direct[i], 1.0f); if (this->depth == 1) DBG && cout << "final color = " << color_direct << endl; // return color_direct + Vec3f(materials[iMaterial].ambient[0], // materials[iMaterial].ambient[1], // materials[iMaterial].ambient[2]); return color_direct; }
glm::vec3 tracer::Pathtracer::radiance(const Ray& ray, std::mt19937& engine, unsigned depth, bool considerEmission, bool debug) { std::uniform_real_distribution<float> distribution(0.0f, 1.0f); float distance, minimumDistance = std::numeric_limits<float>::max(); Intersection tmp, isect; for (auto it = m_scene.begin(); it != m_scene.end(); ++it) { if ((*it)->intersect(ray, tmp)) { tmp.valid = true; if (debug) { std::cout << "testing intersection " << tmp.point << ", distance" << glm::distance2(ray.org, tmp.point) << std::endl; } if ((distance = glm::distance2(ray.org, tmp.point)) < minimumDistance) { minimumDistance = distance; isect = tmp; } } } if (isect.valid) { if (debug) { std::cout << "found intersection @ " << isect.point << ", normal: " << isect.normal << std::endl; } // russian roulette const material::Material& material = isect.object->getMaterial(); glm::vec3 objectColor = material.color; float p = MAX(objectColor.r, objectColor.g, objectColor.b); if (++depth > 5) { if (distribution(engine) < p) { objectColor = objectColor / p; } else { if (considerEmission) { return material.emission; } else { return glm::vec3(0.0f); } } } if (material.type == material::Material::Type_diffuse) { if (debug) { std::cout << "shading diffuse material" << std::endl; } // construct orthonormal system float r1 = 2 * M_PI * distribution(engine); float r2 = distribution(engine); float r2s = sqrt(r2); glm::vec3 w = isect.normal; glm::vec3 u = glm::normalize( glm::cross( (fabs(w.x) > 0.1f ? ey : ex), w ) ); glm::vec3 v = glm::normalize( glm::cross(w, u) ); glm::vec3 d = glm::normalize((float)(cos(r1) * r2s) * u + (float)(sin(r1) * r2s) * v + (float)sqrt(1-r2) * w); Ray scatteredRay(isect.point+epsilon*isect.normal, d); if (debug) { std::cout << "tracing next ray: " << scatteredRay << std::endl; } // compose output color glm::vec3 color = (considerEmission ? material.emission : glm::vec3(0.0f)); // add direct lighting contribution color += sampleDirectLighting(isect.point, isect.normal, objectColor, engine); // add indirect lighting contribution color += objectColor * radiance(scatteredRay, engine, depth, false, debug); return color; } else if (material.type == material::Material::Type_reflective) { if (debug) { std::cout << "shading reflective material" << std::endl; } Ray reflectedRay(isect.point+epsilon*isect.normal, glm::reflect(ray.dir, isect.normal)); return material.emission + objectColor * radiance(reflectedRay, engine, depth, true, debug); } else { error("Unhandled material type detected"); return m_scene.getBackgroundColor(); } } else { if (debug) { std::cout << "found no intersection" << std::endl; } return m_scene.getBackgroundColor(); } }
// Do recursive ray tracing! You'll want to insert a lot of code here // (or places called from here) to handle reflection, refraction, etc etc. vec3f RayTracer::traceRay( Scene *scene, const ray& r, const vec3f& thresh, int depth ) { isect i; vec3f colorC; if (scene->intersect(r, i)) { // YOUR CODE HERE // An intersection occurred! We've got work to do. For now, // this code gets the material for the surface that was intersected, // and asks that material to provide a color for the ray. // This is a great place to insert code for recursive ray tracing. // Instead of just returning the result of shade(), add some // more steps: add in the contributions from reflected and refracted // rays. const Material& m = i.getMaterial(); vec3f intensity = m.shade(scene, r, i); if (depth == 0) return intensity; if (thresh.length() < AdaptiveThreshold) return intensity; vec3f Qpt = r.at(i.t); vec3f minusD = -1 * r.getDirection(); vec3f cosVector = i.N * (minusD * i.N); vec3f sinVector = cosVector + r.getDirection(); vec3f newThresh = thresh; // Reflected Ray if (!m.kr(i).iszero()) { vec3f reflectedDirection = cosVector + sinVector; reflectedDirection.normalize(); ray reflectedRay(Qpt, reflectedDirection, ray::REFLECTION); newThresh = prod(newThresh, i.getMaterial().kr(i)); // change the threshold value intensity = intensity + prod(m.kr(i), traceRay(scene, reflectedRay, newThresh, depth - 1)); } //Refracted Ray if (!m.kt(i).iszero()) { double cosineAngle = acos(i.N * r.getDirection()) * 180 / M_PI; double n_i, n_r; double criticalAngle = 360; int iDirection; // bool goingIn = true; // double cosThetaI = 0; if (cosineAngle > 90) // Coming into an object from air { n_i = 1; n_r = m.index(i); iDirection = 1; // cosThetaI = i.N * -1 * r.d; } else // Going out from object to air { n_i = m.index(i); n_r = 1; // goingIn = false; // cosThetaI = i.N * r.d; iDirection = -1; } double n = n_i / n_r; if (1 - n * n * (1 - (minusD * i.N) * (minusD * i.N)) > 0.0) // NO total internal refraction { vec3f sinT = n * sinVector; // vec3f cosT = (-1 * i.N) * sqrt(1 - sinT*sinT); // not sure if there are any differences between the two eqn, please check!!!!!! vec3f cosT = (-1 * i.N) * sqrt(1 - n * n * (1 - (minusD * i.N) * (minusD * i.N))); vec3f refractedDirection = cosT + iDirection*sinT; refractedDirection.normalize(); ray refractedRay(Qpt, iDirection * refractedDirection, ray::REFRACTION); newThresh = prod(newThresh, i.getMaterial().kt(i)); // change the threshold value intensity = intensity + prod(m.kt(i), traceRay(scene, refractedRay, newThresh, depth - 1)); } } colorC = intensity; } else { // No intersection. This ray travels to infinity, so we color // it according to the background color, which in this (simple) case // is just black. colorC = vec3f (0.0, 0.0, 0.0); } return colorC; }