|
957 | 957 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
958 | 958 | [Listing [hit-record-uv]: <kbd>[hittable.h]</kbd> Adding U,V coordinates to the `hit_record`]
|
959 | 959 |
|
| 960 | +We will also need to compute $(u,v)$ texture coordinates for hittables. |
| 961 | + |
| 962 | + |
| 963 | +Texture Coordinates for Spheres |
| 964 | +-------------------------------- |
| 965 | +<div class='together'> |
| 966 | +For spheres, this is usually based on some form of longitude and latitude, _i.e._, spherical |
| 967 | +coordinates. So if we have a $(\theta,\phi)$ in spherical coordinates, we just need to scale |
| 968 | +$\theta$ and $\phi$ to fractions. If $\theta$ is the angle down from the pole, and $\phi$ is the |
| 969 | +angle around the axis through the poles, the normalization to $[0,1]$ would be: |
| 970 | + |
| 971 | + $$ u = \frac{\phi}{2\pi} $$ |
| 972 | + $$ v = \frac{\theta}{\pi} $$ |
| 973 | +</div> |
| 974 | + |
| 975 | +<div class='together'> |
| 976 | +To compute $\theta$ and $\phi$, for a given hitpoint, the formula for spherical coordinates of a |
| 977 | +unit radius sphere on the origin is: |
| 978 | + |
| 979 | + $$ x = \cos(\phi) \cos(\theta) $$ |
| 980 | + $$ y = \sin(\phi) \cos(\theta) $$ |
| 981 | + $$ z = \sin(\theta) $$ |
| 982 | +</div> |
| 983 | + |
| 984 | +<div class='together'> |
| 985 | +We need to invert that. Because of the lovely `<cmath>` function `atan2()` which takes any number |
| 986 | +proportional to sine and cosine and returns the angle, we can pass in $x$ and $y$ (the |
| 987 | +$\cos(\theta)$ cancel): |
| 988 | + |
| 989 | + $$ \phi = \text{atan2}(y, x) $$ |
| 990 | +</div> |
| 991 | + |
| 992 | +<div class='together'> |
| 993 | +The $atan2$ returns values in the range $-\pi$ to $\pi$, so we need to take a little care there. |
| 994 | +The $\theta$ is more straightforward: |
| 995 | + |
| 996 | + $$ \theta = \text{asin}(z) $$ |
| 997 | + |
| 998 | +which returns numbers in the range $-\pi/2$ to $\pi/2$. |
| 999 | +</div> |
| 1000 | + |
| 1001 | +<div class='together'> |
| 1002 | +So for a sphere, the $(u,v)$ coord computation is accomplished by a utility function that expects |
| 1003 | +things on the unit sphere centered at the origin. The call inside sphere::hit should be: |
| 1004 | + |
| 1005 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ |
| 1006 | + get_sphere_uv((rec.p-center)/radius, rec.u, rec.v); |
| 1007 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 1008 | + [Listing [get-sphere-uv-call]: <kbd>[sphere.h]</kbd> Sphere UV coordinates from hit] |
| 1009 | +</div> |
| 1010 | + |
| 1011 | +<div class='together'> |
| 1012 | +The utility function is: |
| 1013 | + |
| 1014 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ |
| 1015 | + void get_sphere_uv(const vec3& p, double& u, double& v) { |
| 1016 | + auto phi = atan2(p.z(), p.x()); |
| 1017 | + auto theta = asin(p.y()); |
| 1018 | + u = 1-(phi + pi) / (2*pi); |
| 1019 | + v = (theta + pi/2) / pi; |
| 1020 | + } |
| 1021 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 1022 | + [Listing [get-sphere-uv]: <kbd>[sphere.h]</kbd> get_sphere_uv function] |
| 1023 | +</div> |
| 1024 | + |
960 | 1025 | <div class='together'>
|
961 | 1026 | Now we can make textured materials by replacing the `const color& a` with a texture pointer:
|
962 | 1027 |
|
|
1604 | 1669 | Image Texture Mapping
|
1605 | 1670 | ====================================================================================================
|
1606 | 1671 |
|
1607 |
| -We used the hitpoint p before to index a procedure solid texture like marble. We can also read in an |
1608 |
| -image and use a 2D $(u,v)$ texture coordinate to index into the image. |
| 1672 | +From the hitpoint $\mathbf{P}$, we compute the surface coordinates $(u,v)$. We then use these to |
| 1673 | +index into our procedural solid texture (like marble). We can also read in an image and use the |
| 1674 | +2D $(u,v)$ texture coordinate to index into the image. |
1609 | 1675 |
|
1610 | 1676 | <div class='together'>
|
1611 | 1677 | A direct way to use scaled $(u,v)$ in an image is to round the $u$ and $v$ to integers, and use that
|
|
1619 | 1685 | $$ v = \frac{j}{N_y-1} $$
|
1620 | 1686 | </div>
|
1621 | 1687 |
|
1622 |
| -<div class='together'> |
1623 |
| -This is just a fractional position. For a hittable, we need to also return a $u$ and $v$ in the hit |
1624 |
| -record. |
1625 |
| - |
1626 |
| - |
1627 |
| -Texture Coordinates for Spheres |
1628 |
| --------------------------------- |
1629 |
| -For spheres, this is usually based on some form of longitude and latitude, _i.e._, spherical |
1630 |
| -coordinates. So if we have a $(\theta,\phi)$ in spherical coordinates, we just need to scale |
1631 |
| -$\theta$ and $\phi$ to fractions. If $\theta$ is the angle down from the pole, and $\phi$ is the |
1632 |
| -angle around the axis through the poles, the normalization to $[0,1]$ would be: |
1633 |
| - |
1634 |
| - $$ u = \frac{\phi}{2\pi} $$ |
1635 |
| - $$ v = \frac{\theta}{\pi} $$ |
1636 |
| -</div> |
1637 |
| - |
1638 |
| -<div class='together'> |
1639 |
| -To compute $\theta$ and $\phi$, for a given hitpoint, the formula for spherical coordinates of a |
1640 |
| -unit radius sphere on the origin is: |
1641 |
| - |
1642 |
| - $$ x = \cos(\phi) \cos(\theta) $$ |
1643 |
| - $$ y = \sin(\phi) \cos(\theta) $$ |
1644 |
| - $$ z = \sin(\theta) $$ |
1645 |
| -</div> |
1646 |
| - |
1647 |
| -<div class='together'> |
1648 |
| -We need to invert that. Because of the lovely `<cmath>` function `atan2()` (which takes any number |
1649 |
| -proportional to sine and cosine and returns the angle), we can pass in $x$ and $y$ (the |
1650 |
| -$\cos(\theta)$ cancel): |
1651 |
| - |
1652 |
| - $$ \phi = \text{atan2}(y, x) $$ |
1653 |
| -</div> |
1654 |
| - |
1655 |
| -<div class='together'> |
1656 |
| -The $atan2$ returns values in the range $-\pi$ to $\pi$, so we need to take a little care there. |
1657 |
| -The $\theta$ is more straightforward: |
1658 |
| - |
1659 |
| - $$ \theta = \text{asin}(z) $$ |
1660 |
| - |
1661 |
| -which returns numbers in the range $-\pi/2$ to $\pi/2$. |
1662 |
| -</div> |
1663 |
| - |
1664 |
| -<div class='together'> |
1665 |
| -So for a sphere, the $(u,v)$ coord computation is accomplished by a utility function that expects |
1666 |
| -things on the unit sphere centered at the origin. The call inside sphere::hit should be: |
1667 |
| - |
1668 |
| - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ |
1669 |
| - get_sphere_uv((rec.p-center)/radius, rec.u, rec.v); |
1670 |
| - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
1671 |
| - [Listing [get-sphere-uv-call]: <kbd>[sphere.h]</kbd> Sphere UV coordinates from hit] |
1672 |
| -</div> |
1673 |
| - |
1674 |
| -<div class='together'> |
1675 |
| -The utility function is: |
1676 |
| - |
1677 |
| - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ |
1678 |
| - void get_sphere_uv(const vec3& p, double& u, double& v) { |
1679 |
| - auto phi = atan2(p.z(), p.x()); |
1680 |
| - auto theta = asin(p.y()); |
1681 |
| - u = 1-(phi + pi) / (2*pi); |
1682 |
| - v = (theta + pi/2) / pi; |
1683 |
| - } |
1684 |
| - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
1685 |
| - [Listing [get-sphere-uv]: <kbd>[sphere.h]</kbd> get_sphere_uv function] |
1686 |
| -</div> |
| 1688 | +This is just a fractional position. |
1687 | 1689 |
|
1688 | 1690 |
|
1689 | 1691 | Storing Texture Image Data
|
|
0 commit comments