static t_col shoot_ray(t_ray ray, int level_max, t_env *env) { float coef; float t; coef = 1.0; while (coef > 0.0f && level_max--) { t = 20000.0f; get_intersections(env, ray, &t); if (OBJ.cur_sphere != -1) set_val_sphere(env, t, ray); else if (OBJ.cur_tri != -1) set_val_tri(env, t, ray); else if (OBJ.cur_cyl != -1) set_val_cyl(env, t, ray); else if (OBJ.cur_cone != -1) set_val_cone(env, t, ray); else break ; if (env->br == 1) break ; calc_lighting(env, coef); coef *= OBJ.cur_mat.reflection; reflect_ray(env, &ray); } return (OBJ.col); }
Vector Raytracer::shade(Ray const &ray, int &rayDepth, Intersection const &intersection, Material const &material, Scene const &scene) { // - iterate over all lights, calculating ambient/diffuse/specular contribution // - use shadow rays to determine shadows // - integrate the contributions of each light // - include emission of the surface material // - call Raytracer::trace for reflection/refraction colors // Don't reflect/refract if maximum ray recursion depth has been reached! //!!! USEFUL NOTES: attenuate factor = 1.0 / (a0 + a1 * d + a2 * d * d)..., ambient light doesn't attenuate, nor does it affected by shadow //!!! USEFUL NOTES: don't accept shadow intersection far away than the light position //!!! USEFUL NOTES: for each kind of ray, i.e. shadow ray, reflected ray, and primary ray, the accepted furthest depth are different Vector diffuse(0); Vector ambient(0); Vector specular(0); Vector v = -ray.direction.normalized(); Vector n = intersection.normal.normalized(); Vector reflect = (-v + 2 * v.dot(n) * n).normalized(); for (auto lightIter = scene.lights.begin(); lightIter != scene.lights.end(); lightIter++) { // @@@@@@ YOUR CODE HERE // calculate local illumination here, remember to add all the lights together // also test shadow here, if a point is in shadow, multiply its diffuse and specular color by (1 - material.shadow) Vector l = (lightIter->position - intersection.position).normalized(); Vector r = (-l + 2 * n.dot(l)*n).normalized(); Vector view = (scene.camera.position - intersection.position).normalized(); double d = //(intersection.position - ray.origin).length()+ (lightIter->position - intersection.position).length(); double attenuation = 1.0 / (lightIter->ambient[0] + d*lightIter->attenuation[1] +d *d*lightIter->attenuation[2]); Ray shadowRay = Ray(intersection.position + (lightIter->position - intersection.position).normalized()* 1e-6,(lightIter->position - intersection.position).normalized()); Intersection hit = intersection; bool isShadow = false; Vector delAmbient = material.ambient * lightIter->ambient; Vector delDiffuse = material.diffuse * lightIter->diffuse * max(0.0, n.dot(l)) * attenuation; Vector delSpecular = material.specular * lightIter->specular * pow(max(0.0, r.dot(view)), material.shininess) * attenuation; for (int x = 0; x< scene.objects.size(); x++) { if (scene.objects[x]->intersect(shadowRay, hit)) { isShadow = true; } } if (isShadow) { ambient += delAmbient; diffuse += delDiffuse * (1 - material.shadow); specular += delSpecular * (1 - material.shadow); } else { ambient += delAmbient; diffuse += delDiffuse; specular += delSpecular; } } Vector reflectedLight(0); if ((!(ABS_FLOAT(material.reflect) < 1e-6)) && (rayDepth < MAX_RAY_RECURSION)) { // @@@@@@ YOUR CODE HERE // calculate reflected color using trace() recursively Ray reflect_ray(intersection.position + reflect*1e-6, reflect); double depth = DBL_MAX; trace(reflect_ray, rayDepth, scene, reflectedLight, depth); } return material.emission + ambient + diffuse + specular + material.reflect * reflectedLight; }
// 屈折面 Color PathTracer::Radiance_Refraction(const Scene &scene, const Ray &ray, Random &rnd, const int depth, Scene::IntersectionInformation &intersect, const Vector3 &normal, double russian_roulette_prob) { bool into = intersect.hit.normal.dot(normal) > 0.0; Vector3 reflect_dir = ray.dir - normal*2*ray.dir.dot(normal); reflect_dir.normalize(); double n_vacuum = REFRACTIVE_INDEX_VACUUM; double n_obj = intersect.object->material.refraction_rate; double n_ratio = into ? n_vacuum/n_obj : n_obj/n_vacuum; double dot = ray.dir.dot(normal); double cos2t = 1-n_ratio*n_ratio*(1-dot*dot); // 反射方向の直接光の評価 Color reflect_direct; Ray reflect_ray(intersect.hit.position, reflect_dir); Scene::IntersectionInformation reflected_hit; if (m_performNextEventEstimation && scene.CheckIntersection(reflect_ray, reflected_hit)) { reflect_direct = reflected_hit.object->material.emission; } if (cos2t < 0) { // 全反射 Color income = reflect_direct + Radiance(scene, Ray(intersect.hit.position, reflect_dir), rnd, depth+1); Color weight = intersect.object->material.color / russian_roulette_prob; return Vector3(weight.x*income.x, weight.y*income.y, weight.z*income.z); } // 屈折方向 Vector3 refract_dir( ray.dir*n_ratio - intersect.hit.normal * (into ? 1.0 : -1.0) * (dot*n_ratio + sqrt(cos2t)) ); refract_dir.normalize(); const Ray refract_ray(intersect.hit.position, refract_dir); // 屈折方向の直接光の評価 Color refract_direct; if (m_performNextEventEstimation && scene.CheckIntersection(refract_ray, reflected_hit)) { refract_direct = reflected_hit.object->material.emission; } // Fresnel の式 double F0 = (n_obj-n_vacuum)*(n_obj-n_vacuum)/((n_obj+n_vacuum)*(n_obj+n_vacuum)); double c = 1 - ( into ? -dot : -refract_dir.dot(normal) ); // 1-cosθ double Fr = F0 + (1-F0)*pow(c, 5.0); // Fresnel (反射の割合) double n_ratio2 = n_ratio*n_ratio; // 屈折前後での放射輝度の変化率 double Tr = (1-Fr)*n_ratio2; // 屈折直後→直前の割合 Color income, weight; if (depth > 2) { // 反射 or 屈折のみ追跡 const double reflect_prob = 0.1 + 0.8 * Fr; if (rnd.nextDouble() < reflect_prob) { // 反射 income = (reflect_direct + Radiance(scene, Ray(intersect.hit.position, reflect_dir), rnd, depth+1)) * Fr; weight = intersect.texturedHitpointColor / (russian_roulette_prob * reflect_prob); } else { // 屈折 income = (refract_direct + Radiance(scene, refract_ray, rnd, depth+1)) * Tr; weight = intersect.texturedHitpointColor / (russian_roulette_prob * (1 - reflect_prob)); } } else { // 反射と屈折両方追跡 m_omittedRayCount++; income = (reflect_direct + Radiance(scene, Ray(intersect.hit.position, reflect_dir), rnd, depth+1)) * Fr + (refract_direct + Radiance(scene, refract_ray, rnd, depth + 1)) *Tr; weight = intersect.texturedHitpointColor / russian_roulette_prob; } return /*intersect.object->material.emission +*/ Vector3(weight.x*income.x, weight.y*income.y, weight.z*income.z); }