Skip to content

Commit 4d50ef5

Browse files
committed
Reorganize the quads chapter
This does two things: - Moves the planar coordinates derivation into its own skippable section. - Moves the alternate 2D primitives discussion to its own section at the end of the quad chapter, and points to the `alternate-2D-primitves` tag for triangles, ellipses, and annuli. Resolves #1204 Resolves #1205
1 parent 416f7b6 commit 4d50ef5

File tree

1 file changed

+75
-45
lines changed

1 file changed

+75
-45
lines changed

books/RayTracingTheNextWeek.html

Lines changed: 75 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -2601,19 +2601,73 @@
26012601

26022602
$$ \mathbf{P} = \mathbf{Q} + \alpha \mathbf{u} + \beta \mathbf{v} $$
26032603

2604-
If $\mathbf{u}$ and $\mathbf{v}$ were guaranteed to be orthogonal to each other (forming a 90° angle
2605-
between them), then this would be a simple matter of using the dot product to project $\mathbf{P}$
2606-
onto each of the basis vectors $\mathbf{u}$ and $\mathbf{v}$. However, since we are not restricting
2604+
Pulling a rabbit out of my hat, the planar coordinates $\alpha$ and $\beta$ are given by the
2605+
following equations:
2606+
2607+
$$ \alpha = \mathbf{w} \cdot (\mathbf{p} \times \mathbf{v}) $$
2608+
$$ \beta = \mathbf{w} \cdot (\mathbf{u} \times \mathbf{p}) $$
2609+
2610+
where
2611+
2612+
$$ \mathbf{w} = \frac{\mathbf{n}}{\mathbf{n} \cdot (\mathbf{u} \times \mathbf{v})}
2613+
= \frac{\mathbf{n}}{\mathbf{n} \cdot \mathbf{n}}$$
2614+
2615+
The vector $\mathbf{w}$ is constant for a given quadrilateral, so we'll cache that value.
2616+
2617+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
2618+
class quad : public hittable {
2619+
public:
2620+
quad(const point3& _Q, const vec3& _u, const vec3& _v, shared_ptr<material> m)
2621+
: Q(_Q), u(_u), v(_v), mat(m)
2622+
{
2623+
auto n = cross(u, v);
2624+
normal = unit_vector(n);
2625+
D = dot(normal, Q);
2626+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
2627+
w = n / dot(n,n);
2628+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
2629+
2630+
set_bounding_box();
2631+
}
2632+
...
2633+
2634+
private:
2635+
point3 Q;
2636+
vec3 u, v;
2637+
shared_ptr<material> mat;
2638+
aabb bbox;
2639+
vec3 normal;
2640+
double D;
2641+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
2642+
vec3 w;
2643+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
2644+
};
2645+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2646+
[Listing [quad-w]: <kbd>[quad.h]</kbd> Caching the quadrilateral's w value]
2647+
2648+
2649+
Deriving the Planar Coordinates
2650+
--------------------------------
2651+
2652+
(This section covers the derivation of the equations above. Feel free to skip to the next section if
2653+
you're not interested.)
2654+
2655+
Refer back to figure [ray-plane]. If the planar basis vectors $\mathbf{u}$ and $\mathbf{v}$ were
2656+
guaranteed to be orthogonal to each other (forming a 90° angle between them), then solving for
2657+
$\alpha$ and $\beta$ would be a simple matter of using the dot product to project $\mathbf{P}$ onto
2658+
each of the basis vectors $\mathbf{u}$ and $\mathbf{v}$. However, since we are not restricting
26072659
$\mathbf{u}$ and $\mathbf{v}$ to be orthogonal, the math's a little bit trickier.
26082660

2661+
To set things up, consider that
2662+
26092663
$$ \mathbf{P} = \mathbf{Q} + \alpha \mathbf{u} + \beta \mathbf{v}$$
26102664

26112665
$$ \mathbf{p} = \mathbf{P} - \mathbf{Q} = \alpha \mathbf{u} + \beta \mathbf{v} $$
26122666

26132667
Here, $\mathbf{P}$ is the _point_ of intersection, and $\mathbf{p}$ is the _vector_ from
26142668
$\mathbf{Q}$ to $\mathbf{P}$.
26152669

2616-
Cross the above equation with $\mathbf{u}$ and $\mathbf{v}$, respectively:
2670+
Cross the equation for $\mathbf{p}$ with $\mathbf{u}$ and $\mathbf{v}$, respectively:
26172671

26182672
$$ \begin{align*}
26192673
\mathbf{u} \times \mathbf{p} &= \mathbf{u} \times (\alpha \mathbf{u} + \beta \mathbf{v}) \\
@@ -2671,39 +2725,6 @@
26712725
$$ \alpha = \mathbf{w} \cdot (\mathbf{p} \times \mathbf{v}) $$
26722726
$$ \beta = \mathbf{w} \cdot (\mathbf{u} \times \mathbf{p}) $$
26732727

2674-
The vector $\mathbf{w}$ is constant for a given quadrilateral, so we'll cache that value.
2675-
2676-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
2677-
class quad : public hittable {
2678-
public:
2679-
quad(const point3& _Q, const vec3& _u, const vec3& _v, shared_ptr<material> m)
2680-
: Q(_Q), u(_u), v(_v), mat(m)
2681-
{
2682-
auto n = cross(u, v);
2683-
normal = unit_vector(n);
2684-
D = dot(normal, Q);
2685-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
2686-
w = n / dot(n,n);
2687-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
2688-
2689-
set_bounding_box();
2690-
}
2691-
...
2692-
2693-
private:
2694-
point3 Q;
2695-
vec3 u, v;
2696-
shared_ptr<material> mat;
2697-
aabb bbox;
2698-
vec3 normal;
2699-
double D;
2700-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
2701-
vec3 w;
2702-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
2703-
};
2704-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2705-
[Listing [quad-w]: <kbd>[quad.h]</kbd> Caching the quadrilateral's w value]
2706-
27072728

27082729
Interior Testing of The Intersection Using UV Coordinates
27092730
----------------------------------------------------------
@@ -2726,14 +2747,6 @@
27262747

27272748
That's the last piece needed to implement quadrilateral primitives.
27282749

2729-
Pause a bit here and consider that if you use the $(\alpha,\beta)$ coordinates to determine if a
2730-
point lies inside a quadrilateral (parallelogram), it's not too hard to imagine using these same 2D
2731-
coordinates to determine if the intersection point lies inside _any_ other 2D (planar) primitive!
2732-
2733-
We'll leave these additional 2D shape possibilities as an exercise to the reader, depending on your
2734-
desire to explore. Consider triangles, disks, and rings (all of these are surprisingly easy). You
2735-
could even create cut-out stencils based on the pixels of a texture map, or a Mandelbrot shape!
2736-
27372750
In order to make such experimentation a bit easier, we'll factor out the $(\alpha,\beta)$ interior
27382751
test method from the hit method.
27392752

@@ -2866,6 +2879,23 @@
28662879
![<span class='num'>Image 16:</span> Quads](../images/img-2.16-quads.png class='pixel')
28672880

28682881

2882+
Additional 2D Primitives
2883+
-------------------------
2884+
Pause a bit here and consider that if you use the $(\alpha,\beta)$ coordinates to determine if a
2885+
point lies inside a quadrilateral (parallelogram), it's not too hard to imagine using these same 2D
2886+
coordinates to determine if the intersection point lies inside _any_ other 2D (planar) primitive!
2887+
2888+
For example, suppose we change the `is_interior()` function to return true if `sqrt(a*a + b*b) < r`.
2889+
This would then implement disk primitives of radius `r`. For triangles, try
2890+
`a > 0 && b > 0 && a + b < 1`.
2891+
2892+
We'll leave additional 2D shape possibilities as an exercise to the reader, depending on your desire
2893+
to explore. You could even create cut-out stencils based on the pixels of a texture map, or a
2894+
Mandelbrot shape! As a little Easter egg, check out the `alternate-2D-primitves` tag in the source
2895+
repository. This has solutions for triangles, ellipses and annuli (rings) in
2896+
`src/TheNextWeek/quad.h`
2897+
2898+
28692899

28702900
Lights
28712901
====================================================================================================

0 commit comments

Comments
 (0)