float PointInShadow(const glm::vec3& point, RayTracerState& state) { Ray shadow_ray(point, position-point); const float z_offset = 10e-4f; float t = -1; float t_min = std::numeric_limits<float>::max(); int k_min=-1; //Loop through all the objects, to find the closest intersection, if any for (unsigned int k=0; k<state.getScene().size(); ++k) { t = state.getScene().at(k)->intersect(shadow_ray); //skipping the cubemap if(t >= (std::numeric_limits<float>::max())) continue; if (t > z_offset && t <= t_min) { k_min = k; t_min = t; } } if (k_min >= 0) { glm::vec3 q = point + shadow_ray.getDirection()*t_min; float light_length = glm::length(position-point); float q_lenght = glm::length(q); if(q_lenght < light_length) return 0.0f; } return 1.0f; }
void LambertianMaterial::shade(Color& result, const RenderContext& context, const Ray& ray, const HitRecord& record, float attenuation, int depth) const { HitRecord temp_record; Point position = record.p; Normal N; record.obj->getNormal(N, record, position); float costheta = dot(N, ray.direction()); if(costheta > 0) { N = -N; } result = context.scene->ambient*Ka; for(int i = 0; i < context.scene->lights.size(); i++) { Vector light_direction; Color light_color; context.scene->lights[i]->getLight(light_color, light_direction, context, position); float cosphi = dot(N, light_direction); Ray shadow_ray(position, light_direction); if(cosphi > 0) { temp_record.reset(); if(!context.scene->object->hit(temp_record, context, shadow_ray)) { result += light_color*(Kd * cosphi); } else { if(temp_record.obj->mat->getName() == "dielectricmaterial") { Color tempColor; temp_record.obj->mat->shade(tempColor, context, shadow_ray, temp_record, attenuation, depth + 1); result += tempColor*(Kd * cosphi); } } } } result *= color; }
vector3f get_light_distribution(primitive *pri, ray &r, kdtree &kdtree) { // distribution vector3f distribution(0.0, 0.0, 0.0); double delta = 1.0 / (shadow_sampling * shadow_sampling); for (int i = 0; i < shadow_sampling; i++) { for (int j = 0; j < shadow_sampling; j++) { vector3f light_pos = get_light_coordinate(i, j); vector3f shadow_dir = light_pos - r.origin; ray shadow_ray(r.origin, shadow_dir); primitive *shadow_pri = get_intersecting_primitive(kdtree, shadow_ray); if (shadow_pri == NULL || (shadow_ray.origin - r.origin).norm() > shadow_dir.norm()) { // clear double dist = shadow_dir.norm() / distance_factor; double phong = pri->get_normal(r.origin) * shadow_ray.direction; distribution += delta * max(0.0, phong) / (dist * dist); } else { double occupacy = shadow_pri->get_material().dif[3]; if (occupacy < 1 - eps2) { // approximated fraction light double cos_value = shadow_pri->get_normal(shadow_ray.origin) * shadow_ray.direction; double fraction_value = (1 - cos_value) * (1 - cos_value) / 4.0; double phong = pri->get_normal(r.origin) * shadow_ray.direction; double dist = shadow_dir.norm() / distance_factor; distribution += delta * max(0.0, phong) * fraction_value * (1 - occupacy) / (dist * dist); } else { // nothing } } } } return distribution; }
// Moeller-Trumbore bool Triangle::hit(const Ray& ray, const Ray_Tracer* rt, float t_min, float t_max, Ray_Hit& rh, bool shadow) const { // Absolute Triangle Vertex Positions V3& v0 = m->verts[inds[0]]; V3& v1 = m->verts[inds[1]]; V3& v2 = m->verts[inds[2]]; // Two edges of triangle V3 e0, e1; e0 = v1 - v0; e1 = v2 - v0; V3 p = ray.s.cross(e1); float deter = e0.dot(p); if (deter > -EPSILON && deter < EPSILON) return false; V3 t = ray.o - v0; // Store the inverse to reduce divisions float inv_deter = 1.0 / deter; float u = t.dot(p) * inv_deter; if (u < 0.0 || u > 1.0) return false; V3 q = t.cross(e0); float v = ray.s.dot(q) * inv_deter; if (v < 0.0 || u + v > 1.0) return false; float t_inter = e1.dot(q) * inv_deter; if (t_inter < t_min || t_inter > t_max) { //std::cout << "Cull: " << t_inter << '\t' <<t_min<< '\t' <<t_max<< std::endl; return false; } rh.t = t_inter; rh.col = 0.2*m->mat.col; rh.shape = m; if (shadow || ray.depth >= rt->depth_limit) return true; /* if (is_light) { rh.col = Color(1.0, 1.0, 1.0); return true; } */ V3 int_loc = ray.at(t_inter); // Shadow for (Shape* light : rt->lights) { // BIG ASSUMPTION THAT ALL LIGHTS ARE SPHERES Sphere* sph = static_cast<Sphere*>(light); // Make ray from intersection to light V3 int_to_light = sph->c - int_loc; float dist_to_light = int_to_light.norm(); int_to_light.normalize(); Ray shadow_ray(int_loc + EPSILON*int_to_light, int_to_light, ray.depth + 1); Ray_Hit shadow_hit; if (rt->kd->hit_helper(true, rt->kd->root, shadow_ray, rt, EPSILON, dist_to_light, shadow_hit, true, 0)) { if (!shadow_hit.shape->is_light) { continue; } } float inner = int_to_light.dot(normal); if (inner > 0.0) { rh.col += sph->mat.col *inner* m->mat.diff * m->mat.col; } } // Reflection V3 refl_dir = ray.s - 2.0f * (normal.dot(ray.s)) * normal; Ray refl_ray(int_loc + EPSILON*refl_dir, refl_dir, ray.depth + 1); Ray_Hit refl_hit; if (rt->kd->hit_helper(true, rt->kd->root, refl_ray, rt, EPSILON, FLT_MAX, refl_hit, false, 0)) { //if (rt->trace(refl_ray, EPSILON, FLT_MAX, refl_hit, false)) { rh.col += m->mat.refl*refl_hit.col * refl_hit.shape->mat.col; } return true; }
//Blinn-Phong shading model Vector3 Specular::shade(Ray& ray, const HitInfo& hit, const Scene& scene) const { Vector3 reflected = Vector3(0.0f, 0.0f, 0.0f); Vector3 L = Vector3(0.0f, 0.0f, 0.0f); //scale down intensity of light in proportion to num of ray bounces Vector3 attenuation = k_s * ( 1 / (ray.numBounces+1)); const Lights *lightlist = scene.lights(); // loop over all of the lights Lights::const_iterator lightIter; for (lightIter = lightlist->begin(); lightIter != lightlist->end(); lightIter++) { //find reflected vector, given normal and incident light direction PointLight* pLight = *lightIter; //light vector points from hit point to light Vector3 l = pLight->position() - hit.P; //why did we use ray.d here instead of l? Would just need to change calculation a bit //to use l reflected = ray.d - 2.0f * (dot(hit.N, ray.d)) * hit.N; if (ray.numBounces < maxBounces) { //trace from reflected vector now Ray reflect(ray.numBounces + 1); reflect.o = hit.P; reflect.d = reflected; HitInfo hitReflect; if (scene.trace(hitReflect, reflect, 0.008f)) { //get color from object hit //printf("Bounced reflected ray hit something!\n"); L += attenuation * hitReflect.material->shade(reflect, hitReflect, scene); } else { //get color from background L += Vector3(0,0,0.5f);//bgColor; } } //Get halfway vector Vector3 h = (L + -1 * ray.d).normalize(); Ray shadow_ray(0); HitInfo hi; shadow_ray.o = hit.P; shadow_ray.d = l; //std::cout<<"M = "<<M<< " hit.N = "<<hit.N<<std::endl; if (scene.trace(hi, shadow_ray, 0.001f, sqrt(l.length2()))) { // We are in shadow } else { //get color of light Vector3 color = pLight->color(); //flip vector from eye so points from hit point back to eye //L += k_s * color * pow(std::max(0.0f, dot(h, hit.N)), shinyExp); //L += attenuation * color * pow(std::max(0.0f, dot(reflected, -ray.d)), shinyExp); //Specular Highlights //This is separate from the reflection calculation because it //needs to be dependent on just the shinyExp //https://en.wikipedia.org/wiki/Specular_highlight //Specular calculation for ABSORBED light L += attenuation * pow(std::max(0.0f, dot(h, hit.N)), 50* shinyExp); //check entering or exiting and change n1/n2 n2/n1 //dot product ray.dot.normal //Specular Refraction //L += attenuation * color * pow(std::max(0.0f, dot(wt, -ray.d)), shinyExp); //std::cout<<"Final Refraction vector = "<<(k_s * color * pow(std::max(0.0f, //dot(wt,ray.d)), shinyExp))<<std::endl; } } return L; }
void BasicDiffuseSpecularShader::shade( Scene & scene, RandomNumberGenerator & rng, RayIntersection & intersection ) { RGBColor diffuse_contrib( 0.0, 0.0, 0.0 ); RGBColor specular_contrib( 0.0, 0.0, 0.0 ); RGBColor direct_contrib( 0.0, 0.0, 0.0 ); Ray new_ray; RayIntersection new_intersection; new_intersection.min_distance = 0.01; Vector4 offset( 0.0, 0.0, 0.0 ); //offset = scale( intersection.normal, 0.01 ); // NOTE - Seems to help new_ray.origin = add( intersection.position, offset ); new_ray.depth = intersection.ray.depth + 1; const unsigned char max_depth = 5; //const unsigned char max_depth = 4; //const unsigned char max_depth = 3; //const unsigned char max_depth = 2; Vector4 from_dir = intersection.fromDirection(); // Asserts intersection.normal.assertIsUnity(); intersection.normal.assertIsDirection(); // Direct lighting // // Area lights //for( Traceable * traceable : scene.lights ) { // // TODO - sample lights //} // Point lights for( const PointLight & light : scene.point_lights ) { Vector4 to_light = subtract( light.position, intersection.position ); float dist_sq_to_light = to_light.magnitude_sq(); Vector4 direction = to_light.normalized(); direction.makeDirection(); // Shoot a ray toward the light to see if we are in shadow Ray shadow_ray( intersection.position, direction ); RayIntersection shadow_isect; shadow_isect.min_distance = 0.01; if( scene.intersect( shadow_ray, shadow_isect ) && sq(shadow_isect.distance) < dist_sq_to_light ) { continue; } // Not in shadow float cos_r_n = fabs( dot( direction, intersection.normal ) ); RGBColor color = light.band_power; color.scale(cos_r_n); color.scale(1.0f / to_light.magnitude_sq()); // distance falloff // TODO: use actual material parameters properly so we can get specular here, too if( intersection.material ) direct_contrib.accum( mult( color, intersection.material->diffuse ) ); else direct_contrib.accum( color ); } // TODO - How best should we choose between diffuse and specular? // FIXME: Should I scale by the cosine for a perfect reflector? if( intersection.ray.depth < max_depth ) { const float diffuse_chance = 0.9; float diff_spec_select = rng.uniform01(); if( intersection.material->perfect_reflector || intersection.material->perfect_refractor ) { auto sample = intersection.material->sampleBxDF( rng, intersection ); new_ray.direction = sample.direction; new_ray.index_of_refraction = sample.new_index_of_refraction; if( scene.intersect( new_ray, new_intersection ) ) { if( new_intersection.distance != FLT_MAX ) { shade( scene, rng, new_intersection ); } specular_contrib.accum( new_intersection.sample.color ); } } else if( diff_spec_select < diffuse_chance ) { // Diffuse rng.uniformSurfaceUnitHalfSphere( intersection.normal, new_ray.direction ); new_ray.direction.makeDirection(); if( scene.intersect( new_ray, new_intersection ) ) { if( new_intersection.distance != FLT_MAX ) shade( scene, rng, new_intersection ); float cos_r_n = dot( new_ray.direction, intersection.normal ); new_intersection.sample.color.scale( cos_r_n ); diffuse_contrib.accum( new_intersection.sample.color ); } } else { // Specular // TODO - sample the specular lobe, not just the mirror direction new_ray.direction = mirror( from_dir, intersection.normal ); new_ray.direction.makeDirection(); if( scene.intersect( new_ray, new_intersection ) ) { if( new_intersection.distance != FLT_MAX ) shade( scene, rng, new_intersection ); float cos_r_n = dot( new_ray.direction, intersection.normal ); new_intersection.sample.color.scale( cos_r_n ); specular_contrib.accum( new_intersection.sample.color ); } } } if( intersection.material ) { intersection.sample.color = mult( diffuse_contrib, intersection.material->diffuse ); intersection.sample.color.accum( mult( specular_contrib, intersection.material->specular ) ); intersection.sample.color.accum( intersection.material->emittance ); intersection.sample.color.accum( direct_contrib ); } else { intersection.sample.color = diffuse_contrib; intersection.sample.color.accum( direct_contrib ); } }