Skip to content

Commit 2da9199

Browse files
authored
Merge pull request #915 from ymherklotz/textit-in-mathblocks
Add \mathit for multiletter math variables
2 parents 8cc0c81 + 58bdb04 commit 2da9199

File tree

4 files changed

+61
-55
lines changed

4 files changed

+61
-55
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ Change Log -- Ray Tracing in One Weekend
2828
- Fix: rect hit returning NaNs and infinities. Superseded with new `quad` primitive (#681)
2929
- Added: New 2D `quad` primitive of arbitrary orientation (#756)
3030
- Added: New `box()` utility function returns `hittable_list` of new `quad` primitives (#780)
31+
- Fix: Add `\mathit` to italic math variables to fix slight kerning issues (#839)
3132

3233
### In One Weekend
3334
- Added: More commentary about the choice between `double` and `float` (#752)

books/RayTracingInOneWeekend.html

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -844,13 +844,13 @@
844844

845845
<div class='together'>
846846
This `hittable` abstract class will have a hit function that takes in a ray. Most ray tracers have
847-
found it convenient to add a valid interval for hits $t_{min}$ to $t_{max}$, so the hit only
848-
“counts” if $t_{min} < t < t_{max}$. For the initial rays this is positive $t$, but as we will see,
849-
it can help some details in the code to have an interval $t_{min}$ to $t_{max}$. One design question
850-
is whether to do things like compute the normal if we hit something. We might end up hitting
851-
something closer as we do our search, and we will only need the normal of the closest thing. I will
852-
go with the simple solution and compute a bundle of stuff I will store in some structure. Here’s
853-
the abstract class:
847+
found it convenient to add a valid interval for hits $t_{\mathit{min}}$ to $t_{\mathit{max}}$, so
848+
the hit only “counts” if $t_{\mathit{min}} < t < t_{\mathit{max}}$. For the initial rays this is
849+
positive $t$, but as we will see, it can help some details in the code to have an interval
850+
$t_{\mathit{min}}$ to $t_{\mathit{max}}$. One design question is whether to do things like compute
851+
the normal if we hit something. We might end up hitting something closer as we do our search, and we
852+
will only need the normal of the closest thing. I will go with the simple solution and compute a
853+
bundle of stuff I will store in some structure. Here’s the abstract class:
854854

855855
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
856856
#ifndef HITTABLE_H
@@ -1807,8 +1807,8 @@
18071807
this is that almost all image viewers assume that the image is “gamma corrected”, meaning the 0 to 1
18081808
values have some transform before being stored as a byte. There are many good reasons for that, but
18091809
for our purposes we just need to be aware of it. To a first approximation, we can use “gamma 2”
1810-
which means raising the color to the power $1/gamma$, or in our simple case ½, which is just
1811-
square-root:
1810+
which means raising the color to the power $1/\mathit{gamma}$, or in our simple case ½, which is
1811+
just square-root:
18121812

18131813
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
18141814
void write_color(std::ostream &out, color pixel_color, int samples_per_pixel) {
@@ -2184,7 +2184,7 @@
21842184
</div>
21852185

21862186
Note we could just as well only scatter with some probability $p$ and have attenuation be
2187-
$albedo/p$. Your choice.
2187+
$\mathit{albedo}/p$. Your choice.
21882188

21892189
If you read the code above carefully, you'll notice a small chance of mischief. If the random unit
21902190
vector we generate is exactly opposite the normal vector, the two will sum to zero, which will

books/RayTracingTheRestOfYourLife.html

Lines changed: 49 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@
388388
Our Buffon Needle example is a way of calculating $\pi$ by solving for the ratio of the area of the
389389
circle and the area of the inscribing square:
390390

391-
$$ \frac{\text{area}(circle)}{\text{area}(square)} = \frac{\pi}{4} $$
391+
$$ \frac{\text{area}(\mathit{circle})}{\text{area}(\mathit{square})} = \frac{\pi}{4} $$
392392

393393
We picked a bunch of random points in the inscribing square and counted the fraction of them that
394394
were also in the unit circle. This fraction was an estimate that tended toward $\frac{\pi}{4}$ as
@@ -397,14 +397,14 @@
397397
$\frac{\pi}{4}$, and we know that the area of a inscribing square is $4r^2$, so we could then use
398398
those two quanties to get the area of a circle:
399399

400-
$$ \frac{\text{area}(circle)}{\text{area}(square)} = \frac{\pi}{4} $$
401-
$$ \frac{\text{area}(circle)}{(2r)^2} = \frac{\pi}{4} $$
402-
$$ \text{area}(circle) = \frac{\pi}{4} 4r^2 $$
403-
$$ \text{area}(circle) = \pi r^2 $$
400+
$$ \frac{\text{area}(\mathit{circle})}{\text{area}(\mathit{square})} = \frac{\pi}{4} $$
401+
$$ \frac{\text{area}(\mathit{circle})}{(2r)^2} = \frac{\pi}{4} $$
402+
$$ \text{area}(\mathit{circle}) = \frac{\pi}{4} 4r^2 $$
403+
$$ \text{area}(\mathit{circle}) = \pi r^2 $$
404404

405405
We choose a circle with radius $r = 1$ and get:
406406

407-
$$ \text{area}(circle) = \pi $$
407+
$$ \text{area}(\mathit{circle}) = \pi $$
408408

409409
Our work above is equally valid as a means to solve for $pi$ as it is a means to solve for the area
410410
of a circle:
@@ -1340,31 +1340,31 @@
13401340
in the _LMS color space_ (long, medium, short).
13411341

13421342
If the light does scatter, it will have a directional distribution that we can describe as a PDF
1343-
over solid angle. I will refer to this as its _scattering PDF_: $pScatter()$. The scattering PDF
1344-
will vary with the outgoing direction: $pScatter(\omega_o)$. The scattering PDF can also vary with
1345-
_incident direction_: $pScatter(\omega_i, \omega_o)$. You can see this varying with incident
1346-
direction when you look at reflections off a road -- they become mirror-like as your viewing angle
1347-
(incident angle) approaches grazing. Lastly, the scattering PDF can also depend on the scattering
1348-
position: $pScatter(\textbf{x}, \omega_i, \omega_o)$. The $\textbf{x}$ is just a vector representing
1349-
the scattering position: $\textbf{x} = (x, y, z)$. The Albedo of an object can also depend on these
1350-
quantities: $A(\textbf{x}, \omega_i, \omega_o)$.
1343+
over solid angle. I will refer to this as its _scattering PDF_: $\mathit{pScatter}()$. The
1344+
scattering PDF will vary with the outgoing direction: $\mathit{pScatter}(\omega_o)$. The scattering
1345+
PDF can also vary with _incident direction_: $\mathit{pScatter}(\omega_i, \omega_o)$. You can see
1346+
this varying with incident direction when you look at reflections off a road -- they become
1347+
mirror-like as your viewing angle (incident angle) approaches grazing. Lastly, the scattering PDF
1348+
can also depend on the scattering position: $\mathit{pScatter}(\textbf{x}, \omega_i, \omega_o)$. The
1349+
$\textbf{x}$ is just a vector representing the scattering position: $\textbf{x} = (x, y, z)$. The
1350+
Albedo of an object can also depend on these quantities: $A(\textbf{x}, \omega_i, \omega_o)$.
13511351

13521352
<div class='together'>
13531353
The color of a surface is found by integrating these terms over the unit hemisphere by the incident
13541354
direction:
13551355

13561356
$$ \text{Color}_o(\textbf{x}, \omega_o) = \int_{\omega_i}
13571357
A(\textbf{x}, \omega_i, \omega_o) \cdot
1358-
pScatter(\textbf{x}, \omega_i, \omega_o) \cdot
1358+
\mathit{pScatter}(\textbf{x}, \omega_i, \omega_o) \cdot
13591359
\text{Color}_i(\textbf{x}, \omega_i) $$
13601360

13611361
We've added a $\text{Color}_i$ term. The scattering PDF and the albedo at the surface of an object
13621362
are acting as filters to the light that is shining on that point. So we need to solve for the light
13631363
that is shining on that point. This is a recursive algorithm, and is the reason our `ray_color`
13641364
function returns the color of the current object multiplied by the color of the next ray.
13651365

1366-
Note that $A()$, $pScatter()$, and $\text{Color}_i()$ may all depend on the wavelength of the light,
1367-
$\lambda$, but I've left it out of the equation because it's complicated enough as it is.
1366+
Note that $A()$, $\mathit{pScatter}()$, and $\text{Color}_i()$ may all depend on the wavelength of
1367+
the light, $\lambda$, but I've left it out of the equation because it's complicated enough as it is.
13681368
</div>
13691369

13701370

@@ -1374,7 +1374,7 @@
13741374
If we apply the Monte Carlo basic formula we get the following statistical estimate:
13751375

13761376
$$ \text{Color}_o = \frac{A(\textbf{x}, \omega_i, \omega_o) \cdot
1377-
pScatter(\textbf{x}, \omega_i, \omega_o) \cdot
1377+
\mathit{pScatter}(\textbf{x}, \omega_i, \omega_o) \cdot
13781378
\text{Color}_i(\textbf{x}, \omega_i)}
13791379
{p(\textbf{x}, \omega_o)} $$
13801380

@@ -1383,11 +1383,11 @@
13831383
</div>
13841384

13851385
For a Lambertian surface we already implicitly implemented this formula for the special case where
1386-
$p()$ is a cosine density. The $pScatter()$ of a Lambertian surface is proportional to
1386+
$p()$ is a cosine density. The $\mathit{pScatter}()$ of a Lambertian surface is proportional to
13871387
$\cos(\theta_o)$, where $\theta_o$ is the angle relative to the surface normal. All two dimensional
1388-
PDFs need to integrate to one over the whole surface (remember that $pScatter()$ is a PDF). We set
1389-
$pScatter(\theta_o < 0) = 0$ so that we don't scatter below the horizon. The integral of
1390-
$\cos(\theta_o)$ over the hemisphere is $\pi$.
1388+
PDFs need to integrate to one over the whole surface (remember that $\mathit{pScatter}()$ is a
1389+
PDF). We set $\mathit{pScatter}(\theta_o < 0) = 0$ so that we don't scatter below the horizon. The
1390+
integral of $\cos(\theta_o)$ over the hemisphere is $\pi$.
13911391

13921392
<div class='together'>
13931393
To integrate over the hemisphere, remember that in spherical coordinates:
@@ -1404,13 +1404,13 @@
14041404
If we have a scattering PDF that is $\cos(\theta_o)$ over the hemisphere, then we need to normalize
14051405
by $\pi$. So for a Lambertian surface the scattering PDF is:
14061406

1407-
$$ pScatter(\omega_o) = \frac{\cos(\theta_o)}{\pi} $$
1407+
$$ \mathit{pScatter}(\omega_o) = \frac{\cos(\theta_o)}{\pi} $$
14081408
</div>
14091409

14101410
<div class='together'>
14111411
We'll assume that the PDF is equal to the scattering PDF:
14121412

1413-
$$ p(\omega_o) = pScatter() = \frac{\cos(\theta_o)}{\pi} $$
1413+
$$ p(\omega_o) = \mathit{pScatter}() = \frac{\cos(\theta_o)}{\pi} $$
14141414

14151415
The numerator and denominator cancel out, and we get:
14161416

@@ -1428,7 +1428,7 @@
14281428
_Bidirectional Reflectance Distribution Function_ (BRDF). It relates pretty simply to our terms:
14291429

14301430
$$ BRDF(\omega_i, \omega_o) = \frac{A(\textbf{x}, \omega_i, \omega_o) \cdot
1431-
pScatter(\textbf{x}, \omega_i, \omega_o)}{\cos(\theta_o)} $$
1431+
\mathit{pScatter}(\textbf{x}, \omega_i, \omega_o)}{\cos(\theta_o)} $$
14321432

14331433
So for a Lambertian surface for example, $BRDF = A / \pi$. Translation between our terms and BRDF is
14341434
easy. For participating media (volumes), our albedo is usually called the _scattering albedo_, and
@@ -1446,27 +1446,29 @@
14461446
<div class='together'>
14471447
Our goal over the next two chapters is to instrument our program to send a bunch of extra rays
14481448
toward light sources so that our picture is less noisy. Let’s assume we can send a bunch of rays
1449-
toward the light source using a PDF $pLight(\omega_o)$. Let’s also assume we have a PDF related to
1450-
$pScatter$, and let’s call that $pSurface(\omega_o)$. A great thing about PDFs is that you can just
1451-
use linear mixtures of them to form mixture densities that are also PDFs. For example, the simplest
1452-
would be:
1449+
toward the light source using a PDF $\mathit{pLight}(\omega_o)$. Let’s also assume we have a PDF
1450+
related to $\mathit{pScatter}$, and let’s call that $\mathit{pSurface}(\omega_o)$. A great thing
1451+
about PDFs is that you can just use linear mixtures of them to form mixture densities that are also
1452+
PDFs. For example, the simplest would be:
14531453

1454-
$$ p(\omega_o) = \frac{1}{2} pSurface(\omega_o) + \frac{1}{2} pLight(\omega_o)$$
1454+
$$ p(\omega_o) = \frac{1}{2} \mathit{pSurface}(\omega_o) + \frac{1}{2}
1455+
\mathit{pLight}(\omega_o)$$
14551456
</div>
14561457

14571458
As long as the weights are positive and add up to one, any such mixture of PDFs is a PDF. Remember,
14581459
we can use any PDF: _all PDFs eventually converge to the correct answer_. So, the game is to figure
14591460
out how to make the PDF larger where the product
14601461

1461-
$$ pScatter(\textbf{x}, \omega_i, \omega_o) \cdot \text{Color}_i(\textbf{x}, \omega_i) $$
1462+
$$ \mathit{pScatter}(\textbf{x}, \omega_i, \omega_o) \cdot
1463+
\text{Color}_i(\textbf{x}, \omega_i) $$
14621464

14631465
is largest. For diffuse surfaces, this is mainly a matter of guessing where
14641466
$\text{Color}_i(\textbf{x}, \omega_i)$ is largest. Which is equivalent to guessing where the most
14651467
light is coming from.
14661468

1467-
For a mirror, $pScatter()$ is huge only near one direction, so $pScatter()$ matters a lot more. In
1468-
fact, most renderers just make mirrors a special case, and make the $pScatter()/p()$ implicit -- our
1469-
code currently does that.
1469+
For a mirror, $\mathit{pScatter}()$ is huge only near one direction, so $\mathit{pScatter}()$
1470+
matters a lot more. In fact, most renderers just make mirrors a special case, and make the
1471+
$\mathit{pScatter}()/p()$ implicit -- our code currently does that.
14701472

14711473

14721474
Returning to the Cornell Box
@@ -1674,7 +1676,7 @@
16741676
material, but Lambertian requires a $\cos(\theta_o)$ sampling pattern. So any differences that we
16751677
see is because we are using a slightly different material. We're going to uniformly scatter random
16761678
directions from the hemisphere and perfectly match the PDF, given by
1677-
$pScatter(\omega_o) = p(\omega_o) = \frac{1}{2\pi}$.
1679+
$\mathit{pScatter}(\omega_o) = p(\omega_o) = \frac{1}{2\pi}$.
16781680

16791681
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
16801682
class lambertian : public material {
@@ -2416,9 +2418,10 @@
24162418
</div>
24172419

24182420
<div class='together'>
2419-
The details of how this is done under the hood varies for $pSurface$ and $pLight$, but that is
2420-
exactly what class hierarchies were invented for! It’s never obvious what goes in an abstract class,
2421-
so my approach is to be greedy and hope a minimal interface works, and for `pdf` this implies:
2421+
The details of how this is done under the hood varies for $\mathit{pSurface}$ and $\mathit{pLight}$,
2422+
but that is exactly what class hierarchies were invented for! It’s never obvious what goes in an
2423+
abstract class, so my approach is to be greedy and hope a minimal interface works, and for `pdf`
2424+
this implies:
24222425

24232426
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
24242427
#ifndef PDF_H
@@ -2735,13 +2738,14 @@
27352738
mixtures of any PDFs to form mixture densities that are also PDFs. Any weighted average of PDFs is
27362739
also a PDF. As long as the weights are positive and add up to any one, we have a new PDF.
27372740

2738-
$$ pMixture() = w_0 p_0() + w_1 p_1() + w_2 p_2() + \ldots + w_{n-1} p_{n-1}() $$
2741+
$$ \mathit{pMixture}() = w_0 p_0() + w_1 p_1() + w_2 p_2() + \ldots + w_{n-1} p_{n-1}() $$
27392742

27402743
$$ 1 = w_0 + w_1 + w_2 + \ldots + w_{n-1} $$
27412744

27422745
For example, we could just average the two densities:
27432746

2744-
$$ pMixture(\omega_o) = \frac{1}{2} pSurface(\omega_o) + \frac{1}{2} pLight(\omega_o)$$
2747+
$$ \mathit{pMixture}(\omega_o) = \frac{1}{2} \mathit{pSurface}(\omega_o) + \frac{1}{2}
2748+
\mathit{pLight}(\omega_o)$$
27452749

27462750
<div class='together'>
27472751
How would we instrument our code to do that? There is a very important detail that makes this not
@@ -2754,7 +2758,7 @@
27542758
pick direction according to pLight
27552759
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
27562760

2757-
But solving for the PDF value of $pMixture$ is slightly more subtle. We can't just
2761+
But solving for the PDF value of $\mathit{pMixture}$ is slightly more subtle. We can't just
27582762

27592763
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
27602764
if (direction is from pSurface)
@@ -2769,10 +2773,10 @@
27692773
correct, we would have to solve backwards to figure which PDF the direction could come from. Which
27702774
honestly sounds like a nightmare, but fortunately we don't need to do that. There are some
27712775
directions that both PDFs could have generated. For example, a direction toward the light could have
2772-
been generated by either $pLight$ _or_ $pSurface$. It is sufficient for us to solve for the pdf
2773-
value of $pSurface$ and of $pLight$ for a random direction and then take the PDF mixture weights to
2774-
solve for the total PDF value for that direction. The mixture density class is actually pretty
2775-
straightforward:
2776+
been generated by either $\mathit{pLight}$ _or_ $\mathit{pSurface}$. It is sufficient for us to
2777+
solve for the pdf value of $\mathit{pSurface}$ and of $\mathit{pLight}$ for a random direction and
2778+
then take the PDF mixture weights to solve for the total PDF value for that direction. The mixture
2779+
density class is actually pretty straightforward:
27762780

27772781
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
27782782
class mixture_pdf : public pdf {

books/acknowledgments.md.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
- Tatsuya Ogawa
6161
- Thiago Ize
6262
- Vahan Sosoyan
63+
- [Yann Herklotz](https://github.com/ymherklotz)
6364
- [ZeHao Chen](https://github.com/oxine)
6465
</div>
6566

0 commit comments

Comments
 (0)