std::pair< T, T > intersection( const ray<T,2u>& ray, const circle<T>& circle ) { // check for no intersection const T a = dot( ray.direction(), ray.direction() ); const T b = T(2.) * sum( ray.direction() * ( ray.source() - circle.center() ) ); const T c = dot( circle.center(), circle.center() ) + dot( ray.source(), ray.source() ) - T(2.) * dot( ray.source(), circle.center() ) - sqr( circle.radius() ); return solve_quadratic_equation(a,b,c); }
bool sphere::hit(const ray& r, float t_min, float t_max, hit_record& rec) const { vec3 oc = r.origin() - center; float v2 = dot(r.direction(), r.direction()); float voc = dot(oc, r.direction()); // 判別式. float discriminant = voc * voc - v2 * (dot(oc, oc) - radius*radius); if (discriminant > 0) { // 手前. float temp = (-voc - sqrt(discriminant)) / v2; if (temp < t_max && temp > t_min) { rec.t = temp; rec.p = r.org + rec.t * r.dir; rec.normal = (rec.p - center); rec.normal.noramlize(); getUV(rec.u, rec.v, rec.normal); rec.mat_ptr = mat_ptr; return true; } // 奥. temp = (-voc + sqrt(discriminant)) / v2; if (temp < t_max && temp > t_min) { rec.t = temp; rec.p = r.org + rec.t * r.dir; rec.normal = (rec.p - center) / radius; rec.normal.noramlize(); getUV(rec.u, rec.v, rec.normal); rec.mat_ptr = mat_ptr; return true; } } return false; }
bool yz_rect::hit(const ray& r, double t_min, double t_max, hit_record& rec) const { double t = (k - r.origin().x()) / r.direction().x(); if (t<t_min || t>t_max) return false; double y = r.origin().y() + t*r.direction().y(); double z = r.origin().z() + t*r.direction().z(); if (y<y0 || y>y1 || z<z0 || z>z1) return false; rec.u = (y - y0) / (y1 - y0); rec.v = (z - z0) / (z1 - z0); rec.t = t; rec.mat_ptr = mat_ptr; rec.point = r.point_at_parameter(t); rec.normal = vec3(1.0, 0.0, 0.0); return true; }
vec3 color(const ray& r, surface* world, int depth) { hit_record rec; if (world->hit(r, 0.001, DBL_MAX, rec)) { ray scattered; vec3 attenuation; if (depth < MAXDEPTH && rec.mat_ptr->scatter(r, rec, attenuation, scattered)) { return attenuation*color(scattered, world, depth+1); } else { return vec3(0, 0, 0); } } else { vec3 unit_direction = unit_vector(r.direction()); double t = 0.5*(unit_direction.y() + 1.0); return (1.0 - t)*vec3(1.0, 1.0, 1.0) + t*vec3(0.5, 0.7, 1.0); } }
static hdr_color do_shade(scene const& scene, ray const& ray, shading_policy const& policy, unsigned depth, double importance, sampler_prng_engine& prng) { if (!should_continue(depth, importance, policy)) return policy.background; boost::optional<scene::intersection> i = scene.intersect_solid(ray); if (!i) return policy.background; hdr_color result = i->texture(); for (light const& l : scene.lights()) { vector3 const light_dir{l.get_source() - i->position()}; if (auto obstacle = scene.intersect_solid({i->position(), light_dir})) if ((obstacle->position() - i->position()).squaredNorm() < (l.get_source() - i->position()).squaredNorm()) continue; // Obstacle blocks direct path from light to solid result = blend_light( i->solid().material(), result, i->normal(), l.color(), light_dir ); } unit3 const perfect_reflection_dir = reflect(ray.direction(), i->normal()); unit3 const reflection_dir = cos_lobe_perturb( perfect_reflection_dir, i->solid().material().specular_exponent(), prng ); oxatrace::ray const reflected{i->position(), reflection_dir}; double const reflection_importance = i->solid().material().reflectance(); hdr_color const reflection = do_shade( scene, reflected, policy, depth + 1, reflection_importance * importance, prng ); result = blend_reflection(i->solid().material(), result, reflection); return result; }
vec3 color(const ray& r, hitable *world, int depth) { hit_record rec; if (world->hit(r,0.001f, 10000, rec)) { ray scattered; vec3 attenuation; if (depth < 10 && rec.mat_ptr->scatter(r, rec, attenuation, scattered)) { return attenuation * color(scattered, world, depth + 1); } else { // ‰e. return vec3(0,0,0); } } else { // ‹ó. vec3 unit_direction = unit_vector(r.direction()); float t = 0.5 * (unit_direction.y() + 1.0); return (1.0 - t) * vec3(1.0, 1.0, 1.0) + t * vec3(0.5, 0.7, 1.0); } }
ray(const ray<T,Dim>& r) : m_src( r.source() ), m_dir( r.direction() ) { }