// 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; }
RGB Scene::trace(Ray ray, double ray_intensity, int trace_depth) { RGB result(0.0, 0.0, 0.0); if (trace_depth > MAX_DEPTH) return (result); if (ray_intensity < MIN_INTENSITY) return (result); Intersection min_hit; min_hit.dist = MAX_DIST; bool intersected = false; for(int i = 0; i < active_prims; i++) { Intersection current_hit; if(prim_refs[i]->get_intersect(ray, current_hit) && current_hit.dist < min_hit.dist) { min_hit = current_hit; intersected = true; } } //std::cout << "intersection pos:" << intersect.pos.x[0] << " " << intersect.pos.x[1] << " " << intersect.pos.x[2] << "\n"; //if(!intersected) std::cout << "wtf negz no hit\n"; // returns pure black if (!intersected) return (result); // slight adjustment to prevent floating-point inaccuracy from // causing unwanted collisions min_hit.pos += min_hit.normal * 0.0001; //if (intersected) std::cout << "adjusted min_hition pos:" << min_hit.pos.x[0] << " " << min_hit.pos.x[1] << " " << min_hit.pos.x[2] << "\n"; for (int i = 0; i < active_lights; i++) { Vec3 lightray; // deposits lightray in lightray variable bool shadowed = check_shadowing(light_refs[i], min_hit.pos, lightray); if (!shadowed) { // currently ignores color of light result += min_hit.shape_ref->get_diff_mat() * std::max( dot(min_hit.normal, lightray), 0.0 ); // reflection Vec3 R = lightray - min_hit.normal * 2 * dot( lightray, min_hit.normal ); double specdot = dot( R, min_hit.dir ); if (specdot > 0) result += min_hit.shape_ref->get_spec_mat() * pow( specdot, 20 ); } //if(shadowed) std::cout <<" wtf negz shadowed at:" << min_hit.pos.x[0] << " " << min_hit.pos.x[1] << " " << min_hit.pos.x[2] << "\n"; //else std::cout << "plane normal: " << min_hit.dir.x[0] << " " << min_hit.dir.x[1] << " " << min_hit.dir.x[2] << "\n"; //else std::cout << "dot result: " << dot(min_hit.dir, lposdir) << "\n"; } // reflection double obj_refl = min_hit.shape_ref->get_reflection(); if (obj_refl > 0.0) { Vec3 refl_dir = ray.dir - min_hit.normal * 2 * dot( ray.dir, min_hit.normal ); Ray refl_ray ( min_hit.pos, refl_dir ); result += trace( refl_ray, obj_refl * ray_intensity, trace_depth + 1 ); } // refraction double obj_transp = min_hit.shape_ref->get_transparency(); if (obj_transp > 0.0) { // check that when transp not 0, refr not 0. double obj_refr = min_hit.shape_ref->get_refraction(); // check htis double cos_term = dot( ray.dir, min_hit.normal ) ; double nr = (cos_term < 0.0) ? (1 / obj_refr) : (obj_refr); double sin0t2 = nr*nr * (1 - pow(cos_term, 2)); if (sin0t2 < 1.0) { Vec3 refracted_dir = ray.dir * nr - min_hit.normal * (nr * abs(cos_term) - sqrt(1 - sin0t2)); assert(refracted_dir.mag() > 0.0); Vec3 irpos = (cos_term < 0.0) ? (min_hit.pos - min_hit.normal * 0.0002) : (min_hit.pos); Ray refr_ray ( irpos, refracted_dir); result += trace( refr_ray, obj_transp * ray_intensity, trace_depth + 1 ); } } for (int i = 0; i < 3; i++) result.x[i] = std::min(result.x[i], 1.0); assert(ray_intensity <= 1.0); return (result * ray_intensity); }