|
594 | 594 | <div class='together'>
|
595 | 595 | If there are any `NaN`s running around there, the compare will return false so we need to be sure
|
596 | 596 | our bounding boxes have a little padding if we care about grazing cases (and we probably should
|
597 |
| -because in a ray tracer all cases come up eventually). With all three dimensions in a loop, and |
598 |
| -passing in the interval $[t_{min}$, $t_{max}]$, we get: |
| 597 | +because in a ray tracer all cases come up eventually). Here's the implementation: |
| 598 | + |
| 599 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ |
| 600 | + class interval { |
| 601 | + public: |
| 602 | + ... |
| 603 | + double size() const { |
| 604 | + return max - min; |
| 605 | + } |
| 606 | + |
| 607 | + interval expand(double delta) const { |
| 608 | + const auto padding = delta/2; |
| 609 | + return interval(min - padding, max + padding); |
| 610 | + } |
| 611 | + ... |
| 612 | + }; |
| 613 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 614 | + [Listing [interval-contains]: <kbd>interval.h</kbd> interval::expand() method] |
| 615 | + |
599 | 616 |
|
600 | 617 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
601 | 618 | #ifndef AABB_H
|
|
618 | 635 | z = interval(fmin(a[2],b[2]), fmax(a[2],b[2]));
|
619 | 636 | }
|
620 | 637 |
|
| 638 | + const interval& axis(int n) const { |
| 639 | + if (n == 1) return y; |
| 640 | + if (n == 2) return z; |
| 641 | + return x; |
| 642 | + } |
| 643 | + |
621 | 644 | bool hit(const ray& r, interval ray_t) const {
|
622 | 645 | for (int a = 0; a < 3; a++) {
|
623 | 646 | auto t0 = fmin((axis(a).min - r.origin()[a]) / r.direction()[a],
|
|
632 | 655 | return true;
|
633 | 656 | }
|
634 | 657 |
|
635 |
| - const interval& axis(int n) const { |
636 |
| - if (n == 1) return y; |
637 |
| - if (n == 2) return z; |
638 |
| - return x; |
639 |
| - } |
640 |
| - |
641 | 658 | public:
|
642 | 659 | interval x, y, z;
|
643 | 660 | };
|
|
2273 | 2290 |
|
2274 | 2291 | $$ Ax + By + Cz + D = 0 $$
|
2275 | 2292 |
|
2276 |
| -where $A,B,C,D$ are just numbers, and $x,y,z$ are the values of a point $\mathbf{P} = (x,y,z)$. |
| 2293 | +where $A,B,C,D$ are just constants, and $x,y,z$ are the values of a point $\mathbf{P} = (x,y,z)$. |
2277 | 2294 | That is, a plane is the set of all points $\mathbf{P} = (x,y,z)$ that satisfy the formula above. It
|
2278 | 2295 | makes things slightly easier to use the alternate formulation:
|
2279 | 2296 |
|
|
2312 | 2329 | All right, we can find the point of intersection between a ray and a plane. This will help us
|
2313 | 2330 | determine whether a ray hits a given quadrilateral, using the plane that contains the (planar)
|
2314 | 2331 | quadrilateral. In fact, we can use this approach to define any planar primitive, like triangles and
|
2315 |
| -disks (more later). |
| 2332 | +disks (more on that later). |
2316 | 2333 |
|
2317 | 2334 | We now have three questions we must answer:
|
2318 | 2335 |
|
|
2335 | 2352 |
|
2336 | 2353 | These values are three-dimensional, even though a quad itself is a two-dimensional object. For
|
2337 | 2354 | example, a quad with corner at the origin and extending two units in the Z direction and one unit in
|
2338 |
| -the Y direction would have $Q = (0,0,0), u = (0,0,2), \text{and } v = (0,1,0)$. |
| 2355 | +the Y direction would have $\mathbf{Q} = (0,0,0), \mathbf{u} = (0,0,2), \text{and } \mathbf{v} = |
| 2356 | +(0,1,0)$. |
2339 | 2357 |
|
2340 | 2358 | The following figure illustrates the quadrilateral components.
|
2341 | 2359 |
|
|
2348 | 2366 | three of these values (and thus the quad itself).
|
2349 | 2367 |
|
2350 | 2368 | Fortunately, this is very simple. Recall that in $Ax + By + Cz = D$, $(A,B,C)$ represents the
|
2351 |
| -normal vector. To get this, we just use the cross product of the two side vectors $u$ and $v$: |
| 2369 | +normal vector. To get this, we just use the cross product of the two side vectors $\mathbf{u}$ and |
| 2370 | +$\mathbf{v}$: |
2352 | 2371 |
|
2353 | 2372 | $$ \mathbf{n} = \text{unit_vector}(\mathbf{u} \times \mathbf{v}) $$
|
2354 | 2373 |
|
2355 | 2374 | The plane is defined as all points $(x,y,z)$ that satisfy the equation $Ax + By + Cz = D$. Well, we
|
2356 | 2375 | know that $\mathbf{Q}$ lies on the plane, so we can use that to find $D$:
|
2357 | 2376 |
|
2358 | 2377 | $$ \begin{align*}
|
2359 |
| - D &= \mathbf{n}_x\mathbf{Q}_x + \mathbf{n}_y\mathbf{Q}_y + \mathbf{n}_z\mathbf{Q}_z \\ |
2360 |
| - &= n \cdot \mathbf{Q} \\ |
| 2378 | + D &= n_x Q_x + n_y Q_y + n_z Q_z \\ |
| 2379 | + &= \mathbf{n} \cdot \mathbf{Q} \\ |
2361 | 2380 | \end{align*}
|
2362 | 2381 | $$
|
2363 | 2382 |
|
2364 |
| -We can now use these two values $\mathbf{n}$ and $D$ to find the point of intersection with a given |
| 2383 | +We can now use the two values $\mathbf{n}$ and $D$ to find the point of intersection between a given |
2365 | 2384 | ray and the plane containing the quadrilateral.
|
2366 | 2385 |
|
2367 | 2386 |
|
|
2427 | 2446 | $$ \mathbf{u} \times \mathbf{p} = \beta(\mathbf{u} \times \mathbf{v}) $$
|
2428 | 2447 | $$ \mathbf{v} \times \mathbf{p} = \alpha(\mathbf{v} \times \mathbf{u}) $$
|
2429 | 2448 |
|
2430 |
| -To solve for the coefficients $\alpha$ and $\beta$, we can take the dot product of both sides of the |
2431 |
| -above equations with the plane normal $\mathbf{n} = \mathbf{u} \times \mathbf{v}$, reducing both |
2432 |
| -sides to scalars. |
| 2449 | +Now to solve for the coefficients $\alpha$ and $\beta$. If you're new to vector math, you might try |
| 2450 | +to divide by $\mathbf{u} \times \mathbf{v}$ and $\mathbf{v} \times \mathbf{u}$, but you can't divide |
| 2451 | +by vectors. Instead, we can take the dot product of both sides of the above equations with the plane |
| 2452 | +normal $\mathbf{n} = \mathbf{u} \times \mathbf{v}$, reducing both sides to scalars, which we _can_ |
| 2453 | +divide by. |
2433 | 2454 |
|
2434 | 2455 | $$ \mathbf{n} \cdot (\mathbf{u} \times \mathbf{p})
|
2435 | 2456 | = \mathbf{n} \cdot \beta(\mathbf{u} \times \mathbf{v}) $$
|
|
2484 | 2505 |
|
2485 | 2506 | That's the last piece needed to implement quadrilateral primitives.
|
2486 | 2507 |
|
| 2508 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ |
| 2509 | + ... |
| 2510 | + class aabb { |
| 2511 | + public: |
| 2512 | + ... |
| 2513 | + aabb(const aabb& box0, const aabb& box1) { |
| 2514 | + x = interval(box0.x, box1.x); |
| 2515 | + y = interval(box0.y, box1.y); |
| 2516 | + z = interval(box0.z, box1.z); |
| 2517 | + } |
| 2518 | + |
| 2519 | + |
| 2520 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight |
| 2521 | + aabb pad() { |
| 2522 | + // Return an AABB that has no side narrower than some delta, padding if necessary. |
| 2523 | + const double delta = 0.0001; |
| 2524 | + interval new_x = (x.size() >= delta) ? x : x.expand(delta); |
| 2525 | + interval new_y = (y.size() >= delta) ? y : y.expand(delta); |
| 2526 | + interval new_z = (z.size() >= delta) ? z : z.expand(delta); |
| 2527 | + |
| 2528 | + return aabb(new_x, new_y, new_z); |
| 2529 | + } |
| 2530 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 2531 | + [Listing [aabb]: <kbd>[aabb.h]</kbd> New aabb::pad() method] |
| 2532 | + |
| 2533 | + |
2487 | 2534 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
2488 | 2535 | #ifndef QUAD_H
|
2489 | 2536 | #define QUAD_H
|
|
0 commit comments