| #ifndef QUAD_H |
| #define QUAD_H |
| //============================================================================================== |
| // To the extent possible under law, the author(s) have dedicated all copyright |
| // and related and neighboring rights to this software to the public domain |
| // worldwide. This software is distributed without any warranty. |
| // |
| // You should have received a copy (see file COPYING.txt) of the CC0 Public |
| // Domain Dedication along with this software. If not, see |
| // <http://creativecommons.org/publicdomain/zero/1.0/>. |
| // |
| // The original source code is from |
| // https://github.com/RayTracing/raytracing.github.io/tree/release/src/TheNextWeek |
| // |
| // Changes to the original code follow the following license. |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| //============================================================================================== |
| |
| #include "rtweekend.h" |
| |
| #include "hittable.h" |
| #include "hittable_list.h" |
| |
| class quad : public hittable { |
| public: |
| __host__ __device__ quad(const point3 &_Q, const vec3 &_u, const vec3 &_v, |
| SharedPtr<material> m) |
| : Q(_Q), u(_u), v(_v), mat(m) { |
| auto n = cross(u, v); |
| normal = unit_vector(n); |
| D = dot(normal, Q); |
| w = n / dot(n, n); |
| |
| set_bounding_box(); |
| } |
| |
| __host__ __device__ virtual void set_bounding_box() { |
| bbox = aabb(Q, Q + u + v).pad(); |
| } |
| |
| __host__ __device__ aabb bounding_box() const override { return bbox; } |
| |
| __host__ __device__ bool hit(const ray &r, interval ray_t, hit_record &rec, |
| unsigned &rng) const override { |
| auto denom = dot(normal, r.direction()); |
| |
| // No hit if the ray is parallel to the plane. |
| if (fabs(denom) < 1e-8) |
| return false; |
| |
| // Return false if the hit point parameter t is outside the ray interval. |
| auto t = (D - dot(normal, r.origin())) / denom; |
| if (!ray_t.contains(t)) |
| return false; |
| |
| // Determine the hit point lies within the planar shape using its plane |
| // coordinates. |
| auto intersection = r.at(t); |
| vec3 planar_hitpt_vector = intersection - Q; |
| auto alpha = dot(w, cross(planar_hitpt_vector, v)); |
| auto beta = dot(w, cross(u, planar_hitpt_vector)); |
| |
| if (!is_interior(alpha, beta, rec)) |
| return false; |
| |
| // Ray hits the 2D shape; set the rest of the hit record and return true. |
| rec.t = t; |
| rec.p = intersection; |
| rec.mat = mat; |
| rec.set_face_normal(r, normal); |
| |
| return true; |
| } |
| |
| __host__ __device__ virtual bool is_interior(double a, double b, |
| hit_record &rec) const { |
| // Given the hit point in plane coordinates, return false if it is outside |
| // the primitive, otherwise set the hit record UV coordinates and return |
| // true. |
| |
| if ((a < 0) || (1 < a) || (b < 0) || (1 < b)) |
| return false; |
| |
| rec.u = a; |
| rec.v = b; |
| return true; |
| } |
| |
| private: |
| point3 Q; |
| vec3 u, v; |
| SharedPtr<material> mat; |
| aabb bbox; |
| vec3 normal; |
| double D; |
| vec3 w; |
| }; |
| |
| __host__ __device__ inline SharedPtr<hittable_list> |
| box(const point3 &a, const point3 &b, SharedPtr<material> mat) { |
| // Returns the 3D box (six sides) that contains the two opposite vertices a & |
| // b. |
| |
| auto sides = makeShared<hittable_list>(); |
| |
| // Construct the two opposite vertices with the minimum and maximum |
| // coordinates. |
| auto min = point3(fmin(a.x(), b.x()), fmin(a.y(), b.y()), fmin(a.z(), b.z())); |
| auto max = point3(fmax(a.x(), b.x()), fmax(a.y(), b.y()), fmax(a.z(), b.z())); |
| |
| auto dx = vec3(max.x() - min.x(), 0, 0); |
| auto dy = vec3(0, max.y() - min.y(), 0); |
| auto dz = vec3(0, 0, max.z() - min.z()); |
| |
| sides->add(makeShared<quad>(point3(min.x(), min.y(), max.z()), dx, dy, |
| mat)); // front |
| sides->add(makeShared<quad>(point3(max.x(), min.y(), max.z()), -dz, dy, |
| mat)); // right |
| sides->add(makeShared<quad>(point3(max.x(), min.y(), min.z()), -dx, dy, |
| mat)); // back |
| sides->add( |
| makeShared<quad>(point3(min.x(), min.y(), min.z()), dz, dy, mat)); // left |
| sides->add( |
| makeShared<quad>(point3(min.x(), max.y(), max.z()), dx, -dz, mat)); // top |
| sides->add(makeShared<quad>(point3(min.x(), min.y(), min.z()), dx, dz, |
| mat)); // bottom |
| |
| return sides; |
| } |
| |
| #endif |