|
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