|
386 | 386 | --------------
|
387 | 387 | <div class='together'>
|
388 | 388 | The one thing that all ray tracers have is a ray class, and a computation of what color is seen
|
389 |
| -along a ray. Let’s think of a ray as a function $\mathbf{p}(t) = \mathbf{a} + t \vec{\mathbf{b}}$. |
390 |
| -Here $\mathbf{p}$ is a 3D position along a line in 3D. $\mathbf{a}$ is the ray origin and |
391 |
| -$\vec{\mathbf{b}}$ is the ray direction. The ray parameter $t$ is a real number (`double` in the |
392 |
| -code). Plug in a different $t$ and $p(t)$ moves the point along the ray. Add in negative $t$ and you |
393 |
| -can go anywhere on the 3D line. For positive $t$, you get only the parts in front of $\mathbf{a}$, |
394 |
| -and this is what is often called a half-line or ray. |
| 389 | +along a ray. Let’s think of a ray as a function $\mathbf{P}(t) = \mathbf{A} + t \mathbf{b}$. (Note: |
| 390 | +throughout these books, we'll use uppercase bold letters for points, and lowercase bold letters for |
| 391 | +vectors.) Here $\mathbf{P}$ is a 3D position along a line in 3D. $\mathbf{A}$ is the ray origin and |
| 392 | +$\mathbf{b}$ is the ray direction. The ray parameter $t$ is a real number (`double` in the |
| 393 | +code). Plug in a different $t$ and $\mathbf{P}(t)$ moves the point along the ray. Add in negative |
| 394 | +$t$ and you can go anywhere on the 3D line. For positive $t$, you get only the parts in front of |
| 395 | +$\mathbf{A}$, and this is what is often called a half-line or ray. |
395 | 396 |
|
396 | 397 | ![Figure [lerp]: Linear interpolation](../images/fig.lerp.jpg)
|
397 | 398 |
|
398 | 399 | </div>
|
399 | 400 |
|
400 | 401 | <div class='together'>
|
401 |
| -The function $p(t)$ in more verbose code form I call `ray::at(t)`: |
| 402 | +The function $\mathbf{P}(t)$ in more verbose code form I call `ray::at(t)`: |
402 | 403 |
|
403 | 404 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
404 | 405 | #ifndef RAY_H
|
|
524 | 525 | Adding a Sphere
|
525 | 526 | ====================================================================================================
|
526 | 527 |
|
527 |
| -<div class='together'> |
528 | 528 | Let’s add a single object to our ray tracer. People often use spheres in ray tracers because
|
529 | 529 | calculating whether a ray hits a sphere is pretty straightforward.
|
530 | 530 |
|
531 | 531 |
|
532 | 532 | Ray-Sphere Intersection
|
533 | 533 | ------------------------
|
| 534 | +<div class='together'> |
534 | 535 | Recall that the equation for a sphere centered at the origin of radius $R$ is $x^2 + y^2 + z^2 =
|
535 | 536 | R^2$. Put another way, if a given point $(x,y,z)$ is on the sphere, then $x^2 + y^2 + z^2 = R^2$. If
|
536 | 537 | the given point $(x,y,z)$ is _inside_ the sphere, then $x^2 + y^2 + z^2 < R^2$, and if a given point
|
537 | 538 | $(x,y,z)$ is _outside_ the sphere, then $x^2 + y^2 + z^2 > R^2$.
|
538 | 539 |
|
539 |
| -It gets uglier if the sphere center is at $(\mathbf{c}_x, \mathbf{c}_y, \mathbf{c}_z)$: |
| 540 | +It gets uglier if the sphere center is at $(\mathbf{C}_x, \mathbf{C}_y, \mathbf{C}_z)$: |
540 | 541 |
|
541 |
| - $$ (x-\mathbf{c}_x)^2 + (y-\mathbf{c}_y)^2 + (z-\mathbf{c}_z)^2 = R^2 $$ |
| 542 | + $$ (x-\mathbf{C}_x)^2 + (y-\mathbf{C}_y)^2 + (z-\mathbf{C}_z)^2 = r^2 $$ |
542 | 543 | </div>
|
543 | 544 |
|
544 | 545 | <div class='together'>
|
545 | 546 | In graphics, you almost always want your formulas to be in terms of vectors so all the x/y/z stuff
|
546 | 547 | is under the hood in the `vec3` class. You might note that the vector from center
|
547 |
| -$\mathbf{c} = (\mathbf{c}_x,\mathbf{c}_y,\mathbf{c}_z)$ to point $\mathbf{P} = (x,y,z)$ is |
548 |
| -$(\mathbf{p} - \mathbf{c})$, and therefore |
| 548 | +$\mathbf{C} = (\mathbf{C}_x,\mathbf{C}_y,\mathbf{C}_z)$ to point $\mathbf{P} = (x,y,z)$ is |
| 549 | +$(\mathbf{P} - \mathbf{C})$, and therefore |
549 | 550 |
|
550 |
| - $$ (\mathbf{p} - \mathbf{c}) \cdot (\mathbf{p} - \mathbf{c}) |
551 |
| - = (x-\mathbf{c}_x)^2 + (y-\mathbf{c}_y)^2 + (z-\mathbf{c}_z)^2 |
| 551 | + $$ (\mathbf{P} - \mathbf{C}) \cdot (\mathbf{P} - \mathbf{C}) |
| 552 | + = (x-\mathbf{C}_x)^2 + (y-\mathbf{C}_y)^2 + (z-\mathbf{C}_z)^2 |
552 | 553 | $$
|
553 | 554 | </div>
|
554 | 555 |
|
555 | 556 | <div class='together'>
|
556 | 557 | So the equation of the sphere in vector form is:
|
557 | 558 |
|
558 |
| - $$ (\mathbf{p} - \mathbf{c}) \cdot (\mathbf{p} - \mathbf{c}) = R^2 $$ |
| 559 | + $$ (\mathbf{P} - \mathbf{C}) \cdot (\mathbf{P} - \mathbf{C}) = r^2 $$ |
559 | 560 | </div>
|
560 | 561 |
|
561 | 562 | <div class='together'>
|
562 |
| -We can read this as “any point $\mathbf{p}$ that satisfies this equation is on the sphere”. We want |
563 |
| -to know if our ray $p(t) = \mathbf{a} + t\vec{\mathbf{b}}$ ever hits the sphere anywhere. If it does |
564 |
| -hit the sphere, there is some $t$ for which $p(t)$ satisfies the sphere equation. So we are looking |
565 |
| -for any $t$ where this is true: |
| 563 | +We can read this as “any point $\mathbf{P}$ that satisfies this equation is on the sphere”. We want |
| 564 | +to know if our ray $\mathbf{P}(t) = \mathbf{A} + t\mathbf{b}$ ever hits the sphere anywhere. If it |
| 565 | +does hit the sphere, there is some $t$ for which $\mathbf{P}(t)$ satisfies the sphere equation. So |
| 566 | +we are looking for any $t$ where this is true: |
566 | 567 |
|
567 |
| - $$ (p(t) - \mathbf{c})\cdot(p(t) - \mathbf{c}) = R^2 $$ |
| 568 | + $$ (\mathbf{P}(t) - \mathbf{C})\cdot(\mathbf{P}(t) - \mathbf{C}) = r^2 $$ |
568 | 569 |
|
569 |
| -or expanding the full form of the ray $p(t)$: |
| 570 | +or expanding the full form of the ray $\mathbf{P}(t)$: |
570 | 571 |
|
571 |
| - $$ (\mathbf{a} + t \vec{\mathbf{b}} - \mathbf{c}) |
572 |
| - \cdot (\mathbf{a} + t \vec{\mathbf{b}} - \mathbf{c}) = R^2 $$ |
| 572 | + $$ (\mathbf{A} + t \mathbf{b} - \mathbf{C}) |
| 573 | + \cdot (\mathbf{A} + t \mathbf{b} - \mathbf{C}) = r^2 $$ |
573 | 574 | </div>
|
574 | 575 |
|
575 | 576 | <div class='together'>
|
576 | 577 | The rules of vector algebra are all that we would want here, and if we expand that equation and
|
577 | 578 | move all the terms to the left hand side we get:
|
578 | 579 |
|
579 |
| - $$ t^2 \vec{\mathbf{b}}\cdot\vec{\mathbf{b}} |
580 |
| - + 2t \vec{\mathbf{b}} \cdot \vec{(\mathbf{a}-\mathbf{c})} |
581 |
| - + \vec{(\mathbf{a}-\mathbf{c})} \cdot \vec{(\mathbf{a}-\mathbf{c})} - R^2 = 0 |
| 580 | + $$ t^2 \mathbf{b} \cdot \mathbf{b} |
| 581 | + + 2t \mathbf{b} \cdot (\mathbf{A}-\mathbf{C}) |
| 582 | + + (\mathbf{A}-\mathbf{C}) \cdot (\mathbf{A}-\mathbf{C}) - r^2 = 0 |
582 | 583 | $$
|
583 | 584 | </div>
|
584 | 585 |
|
585 | 586 | <div class='together'>
|
586 |
| -The vectors and $R$ in that equation are all constant and known. The unknown is $t$, and the |
| 587 | +The vectors and $r$ in that equation are all constant and known. The unknown is $t$, and the |
587 | 588 | equation is a quadratic, like you probably saw in your high school math class. You can solve for $t$
|
588 | 589 | and there is a square root part that is either positive (meaning two real solutions), negative
|
589 | 590 | (meaning no real solutions), or zero (meaning one real solution). In graphics, the algebra almost
|
|
664 | 665 | On the earth, this implies that the vector from the earth’s center to you points straight up. Let’s
|
665 | 666 | throw that into the code now, and shade it. We don’t have any lights or anything yet, so let’s just
|
666 | 667 | visualize the normals with a color map. A common trick used for visualizing normals (because it’s
|
667 |
| -easy and somewhat intuitive to assume $\vec{\mathbf{N}}$ is a unit length vector -- so each |
| 668 | +easy and somewhat intuitive to assume $\mathbf{n}$ is a unit length vector -- so each |
668 | 669 | component is between -1 and 1) is to map each component to the interval from 0 to 1, and then map
|
669 | 670 | x/y/z to r/g/b. For the normal, we need the hit point, not just whether we hit or not. Let’s assume
|
670 | 671 | the closest hit point (smallest $t$). These changes in the code let us compute and visualize
|
671 |
| -$\vec{\mathbf{N}}$: |
| 672 | +$\mathbf{n}$: |
672 | 673 |
|
673 | 674 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
674 | 675 | double hit_sphere(const point3& center, double radius, const ray& r) {
|
|
1458 | 1459 |
|
1459 | 1460 | <div class='together'>
|
1460 | 1461 | There are two unit radius spheres tangent to the hit point $p$ of a surface. These two spheres have
|
1461 |
| -a center of $(p + \vec{N})$ and $(p - \vec{N})$, where $\vec{N}$ is the normal of the surface. The |
1462 |
| -sphere with a center at $(p - \vec{N})$ is considered _inside_ the surface, whereas the sphere with |
1463 |
| -center $(p + \vec{N})$ is considered _outside_ the surface. Select the tangent unit radius sphere |
1464 |
| -that is on the same side of the surface as the ray origin. Pick a random point $s$ inside this unit |
1465 |
| -radius sphere and send a ray from the hit point $p$ to the random point $s$ (this is the vector |
1466 |
| -$(s-p)$): |
| 1462 | +a center of $(\mathbf{P} + \mathbf{n})$ and $(\mathbf{P} - \mathbf{n})$, where $\mathbf{n}$ is the |
| 1463 | +normal of the surface. The sphere with a center at $(\mathbf{P} - \mathbf{n})$ is considered |
| 1464 | +_inside_ the surface, whereas the sphere with center $(\mathbf{P} + \mathbf{n})$ is considered |
| 1465 | +_outside_ the surface. Select the tangent unit radius sphere that is on the same side of the surface |
| 1466 | +as the ray origin. Pick a random point $\mathbf{S}$ inside this unit radius sphere and send a ray |
| 1467 | +from the hit point $\mathbf{P}$ to the random point $\mathbf{S}$ (this is the vector |
| 1468 | +$(\mathbf{S}-\mathbf{P})$): |
1467 | 1469 |
|
1468 | 1470 | ![Figure [rand-vector]: Generating a random diffuse bounce ray](../images/fig.rand-vector.jpg)
|
1469 | 1471 |
|
|
2002 | 2004 | </div>
|
2003 | 2005 |
|
2004 | 2006 | <div class='together'>
|
2005 |
| -The reflected ray direction in red is just $\vec{\mathbf{V}} + 2\vec{\mathbf{B}}$. In our design, |
2006 |
| -$\vec{\mathbf{N}}$ is a unit vector, but $\vec{\mathbf{V}}$ may not be. The length of |
2007 |
| -$\vec{\mathbf{B}}$ should be $\vec{\mathbf{V}} \cdot \vec{\mathbf{N}}$. Because $\vec{\mathbf{V}}$ |
2008 |
| -points in, we will need a minus sign, yielding: |
| 2007 | +The reflected ray direction in red is just $\mathbf{v} + 2\mathbf{b}$. In our design, $\mathbf{n}$ |
| 2008 | +is a unit vector, but $\mathbf{v}$ may not be. The length of $\mathbf{b}$ should be $\mathbf{v} |
| 2009 | +\cdot \mathbf{n}$. Because $\mathbf{v}$ points in, we will need a minus sign, yielding: |
2009 | 2010 |
|
2010 | 2011 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
2011 | 2012 | vec3 reflect(const vec3& v, const vec3& n) {
|
|
2237 | 2238 | $$ \sin\theta' = \frac{\eta}{\eta'} \cdot \sin\theta $$
|
2238 | 2239 |
|
2239 | 2240 | On the refracted side of the surface there is a refracted ray $\mathbf{R'}$ and a normal
|
2240 |
| -$\mathbf{N'}$, and there exists an angle, $\theta'$, between them. We can split $\mathbf{R'}$ into |
2241 |
| -the parts of the ray that are parallel to $\mathbf{N'}$ and perpendicular to $\mathbf{N'}$: |
| 2241 | +$\mathbf{n'}$, and there exists an angle, $\theta'$, between them. We can split $\mathbf{R'}$ into |
| 2242 | +the parts of the ray that are parallel to $\mathbf{n'}$ and perpendicular to $\mathbf{n'}$: |
2242 | 2243 |
|
2243 | 2244 | $$ \mathbf{R'} = \mathbf{R'}_{\parallel} + \mathbf{R'}_{\bot} $$
|
2244 | 2245 |
|
2245 | 2246 | If we solve for $\mathbf{R'}_{\parallel}$ and $\mathbf{R'}_{\bot}$ we get:
|
2246 | 2247 |
|
2247 |
| - $$ \mathbf{R'}_{\parallel} = \frac{\eta}{\eta'} (\mathbf{R} + \cos\theta \mathbf{N}) $$ |
2248 |
| - $$ \mathbf{R'}_{\bot} = -\sqrt{1 - |\mathbf{R'}_{\parallel}|^2} \mathbf{N} $$ |
| 2248 | + $$ \mathbf{R'}_{\parallel} = \frac{\eta}{\eta'} (\mathbf{R} + \cos\theta \mathbf{n}) $$ |
| 2249 | + $$ \mathbf{R'}_{\bot} = -\sqrt{1 - |\mathbf{R'}_{\parallel}|^2} \mathbf{n} $$ |
2249 | 2250 |
|
2250 | 2251 | You can go ahead and prove this for yourself if you want, but we will treat it as fact and move on.
|
2251 | 2252 | The rest of the book will not require you to understand the proof.
|
2252 | 2253 |
|
2253 | 2254 | We still need to solve for $\cos\theta$. It is well known that the dot product of two vectors can
|
2254 | 2255 | be explained in terms of the cosine of the angle between them:
|
2255 | 2256 |
|
2256 |
| - $$ \mathbf{A} \cdot \mathbf{B} = |\mathbf{A}| |\mathbf{B}| \cos\theta $$ |
| 2257 | + $$ \mathbf{a} \cdot \mathbf{b} = |\mathbf{a}| |\mathbf{b}| \cos\theta $$ |
2257 | 2258 |
|
2258 |
| -If we restrict $\mathbf{A}$ and $\mathbf{B}$ to be unit vectors: |
| 2259 | +If we restrict $\mathbf{a}$ and $\mathbf{b}$ to be unit vectors: |
2259 | 2260 |
|
2260 |
| - $$ \mathbf{A} \cdot \mathbf{B} = \cos\theta $$ |
| 2261 | + $$ \mathbf{a} \cdot \mathbf{b} = \cos\theta $$ |
2261 | 2262 |
|
2262 | 2263 | We can now rewrite $\mathbf{R'}_{\parallel}$ in terms of known quantities:
|
2263 | 2264 |
|
2264 | 2265 | $$ \mathbf{R'}_{\parallel} =
|
2265 |
| - \frac{\eta}{\eta'} (\mathbf{R} + (\mathbf{-R} \cdot \mathbf{N}) \mathbf{N}) $$ |
| 2266 | + \frac{\eta}{\eta'} (\mathbf{R} + (\mathbf{-R} \cdot \mathbf{n}) \mathbf{n}) $$ |
2266 | 2267 |
|
2267 | 2268 | When we combine them back together, we can write a function to calculate $\mathbf{R'}$:
|
2268 | 2269 |
|
|
2363 | 2364 |
|
2364 | 2365 | and
|
2365 | 2366 |
|
2366 |
| - $$ \cos\theta = \mathbf{R} \cdot \mathbf{N} $$ |
| 2367 | + $$ \cos\theta = \mathbf{R} \cdot \mathbf{n} $$ |
2367 | 2368 |
|
2368 | 2369 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
2369 | 2370 | double cos_theta = ffmin(dot(-unit_direction, rec.normal), 1.0);
|
|
0 commit comments