|
581 | 581 | If you're wondering why we don't just use `aspect_ratio` when computing `viewport_width`, it's
|
582 | 582 | because the value set to `aspect_ratio` is the ideal ratio, it may not be the _actual_ ratio between
|
583 | 583 | `image_width` and `image_height`. If `image_height` was allowed to be real valued--rather than just
|
584 |
| -an integer--then it would fine to use `aspect_ratio`. But the _actual_ ratio between `image_width` |
585 |
| -and `image_height` can vary based on two parts of the code. First, `integer_height` is rounded down |
586 |
| -to the nearest integer, which can increase the ratio. Second, we don't allow `integer_height` to be |
587 |
| -less than one, which can also change the actual aspect ratio. |
| 584 | +an integer--then it would be fine to use `aspect_ratio`. But the _actual_ ratio between |
| 585 | +`image_width` and `image_height` can vary based on two parts of the code. First, `image_height` is |
| 586 | +rounded down to the nearest integer, which can increase the ratio. Second, we don't allow |
| 587 | +`image_height` to be less than one, which can also change the actual aspect ratio. |
588 | 588 |
|
589 | 589 | Note that `aspect_ratio` is an ideal ratio, which we approximate as best as possible with the
|
590 | 590 | integer-based ratio of image width over image height. In order for our viewport proportions to
|
|
777 | 777 | If we want to allow the sphere center to be at an arbitrary point $(C_x, C_y, C_z)$, then the
|
778 | 778 | equation becomes a lot less nice:
|
779 | 779 |
|
780 |
| - $$ (x - C_x)^2 + (y - C_y)^2 + (z - C_z)^2 = r^2 $$ |
| 780 | + $$ (C_x - x)^2 + (C_y - y)^2 + (C_z - z)^2 = r^2 $$ |
781 | 781 |
|
782 | 782 | In graphics, you almost always want your formulas to be in terms of vectors so that all the
|
783 | 783 | $x$/$y$/$z$ stuff can be simply represented using a `vec3` class. You might note that the vector
|
784 |
| -from center $\mathbf{C} = (C_x, C_y, C_z)$ to point $\mathbf{P} = (x,y,z)$ is |
785 |
| -$(\mathbf{P} - \mathbf{C})$. If we use the definition of the dot product: |
| 784 | +from point $\mathbf{P} = (x,y,z)$ to center $\mathbf{C} = (C_x, C_y, C_z)$ is |
| 785 | +$(\mathbf{C} - \mathbf{P})$. |
786 | 786 |
|
787 |
| - $$ (\mathbf{P} - \mathbf{C}) \cdot (\mathbf{P} - \mathbf{C}) |
788 |
| - = (x - C_x)^2 + (y - C_y)^2 + (z - C_z)^2 |
| 787 | +If we use the definition of the dot product: |
| 788 | + |
| 789 | + $$ (\mathbf{C} - \mathbf{P}) \cdot (\mathbf{C} - \mathbf{P}) |
| 790 | + = (C_x - x)^2 + (C_y - y)^2 + (C_z - z)^2 |
789 | 791 | $$
|
790 | 792 |
|
791 | 793 | Then we can rewrite the equation of the sphere in vector form as:
|
792 | 794 |
|
793 |
| - $$ (\mathbf{P} - \mathbf{C}) \cdot (\mathbf{P} - \mathbf{C}) = r^2 $$ |
| 795 | + $$ (\mathbf{C} - \mathbf{P}) \cdot (\mathbf{C} - \mathbf{P}) = r^2 $$ |
794 | 796 |
|
795 | 797 | We can read this as “any point $\mathbf{P}$ that satisfies this equation is on the sphere”. We want
|
796 |
| -to know if our ray $\mathbf{P}(t) = \mathbf{A} + t\mathbf{b}$ ever hits the sphere anywhere. If it |
| 798 | +to know if our ray $\mathbf{P}(t) = \mathbf{Q} + t\mathbf{d}$ ever hits the sphere anywhere. If it |
797 | 799 | does hit the sphere, there is some $t$ for which $\mathbf{P}(t)$ satisfies the sphere equation. So
|
798 | 800 | we are looking for any $t$ where this is true:
|
799 | 801 |
|
800 |
| - $$ (\mathbf{P}(t) - \mathbf{C}) \cdot (\mathbf{P}(t) - \mathbf{C}) = r^2 $$ |
| 802 | + $$ (\mathbf{C} - \mathbf{P}(t)) \cdot (\mathbf{C} - \mathbf{P}(t)) = r^2 $$ |
801 | 803 |
|
802 | 804 | which can be found by replacing $\mathbf{P}(t)$ with its expanded form:
|
803 | 805 |
|
804 |
| - $$ ((\mathbf{A} + t \mathbf{b}) - \mathbf{C}) |
805 |
| - \cdot ((\mathbf{A} + t \mathbf{b}) - \mathbf{C}) = r^2 $$ |
| 806 | + $$ (\mathbf{C} - (\mathbf{Q} + t \mathbf{d})) |
| 807 | + \cdot (\mathbf{C} - (\mathbf{Q} + t \mathbf{d})) = r^2 $$ |
806 | 808 |
|
807 | 809 | We have three vectors on the left dotted by three vectors on the right. If we solved for the full
|
808 | 810 | dot product we would get nine vectors. You can definitely go through and write everything out, but
|
809 | 811 | we don't need to work that hard. If you remember, we want to solve for $t$, so we'll separate the
|
810 | 812 | terms based on whether there is a $t$ or not:
|
811 | 813 |
|
812 |
| - $$ (t \mathbf{b} + (\mathbf{A} - \mathbf{C})) |
813 |
| - \cdot (t \mathbf{b} + (\mathbf{A} - \mathbf{C})) = r^2 $$ |
| 814 | + $$ (-t \mathbf{d} + (\mathbf{C} - \mathbf{Q})) \cdot (-t \mathbf{d} + (\mathbf{C} - \mathbf{Q})) |
| 815 | + = r^2 |
| 816 | + $$ |
814 | 817 |
|
815 | 818 | And now we follow the rules of vector algebra to distribute the dot product:
|
816 | 819 |
|
817 |
| - $$ t^2 \mathbf{b} \cdot \mathbf{b} |
818 |
| - + 2t \mathbf{b} \cdot (\mathbf{A}-\mathbf{C}) |
819 |
| - + (\mathbf{A}-\mathbf{C}) \cdot (\mathbf{A}-\mathbf{C}) = r^2 |
| 820 | + $$ t^2 \mathbf{d} \cdot \mathbf{d} |
| 821 | + - 2t \mathbf{d} \cdot (\mathbf{C} - \mathbf{Q}) |
| 822 | + + (\mathbf{C} - \mathbf{Q}) \cdot (\mathbf{C} - \mathbf{Q}) = r^2 |
820 | 823 | $$
|
821 | 824 |
|
822 | 825 | Move the square of the radius over to the left hand side:
|
823 | 826 |
|
824 |
| - $$ t^2 \mathbf{b} \cdot \mathbf{b} |
825 |
| - + 2t \mathbf{b} \cdot (\mathbf{A}-\mathbf{C}) |
826 |
| - + (\mathbf{A}-\mathbf{C}) \cdot (\mathbf{A}-\mathbf{C}) - r^2 = 0 |
| 827 | + $$ t^2 \mathbf{d} \cdot \mathbf{d} |
| 828 | + - 2t \mathbf{d} \cdot (\mathbf{C} - \mathbf{Q}) |
| 829 | + + (\mathbf{C} - \mathbf{Q}) \cdot (\mathbf{C} - \mathbf{Q}) - r^2 = 0 |
827 | 830 | $$
|
828 | 831 |
|
829 | 832 | It's hard to make out what exactly this equation is, but the vectors and $r$ in that equation are
|
830 | 833 | all constant and known. Furthermore, the only vectors that we have are reduced to scalars by dot
|
831 | 834 | product. The only unknown is $t$, and we have a $t^2$, which means that this equation is quadratic.
|
832 |
| -You can solve for a quadratic equation by using the quadratic formula: |
| 835 | +You can solve for a quadratic equation $ax^2 + bx + c = 0$ by using the quadratic formula: |
833 | 836 |
|
834 | 837 | $$ \frac{-b \pm \sqrt{b^2 - 4ac}}{2a} $$
|
835 | 838 |
|
836 |
| -Where for ray-sphere intersection the $a$/$b$/$c$ values are: |
| 839 | +So solving for $t$ in the ray-sphere intersection equation gives us these values for $a$, $b$, and |
| 840 | +$c$: |
837 | 841 |
|
838 |
| - $$ a = \mathbf{b} \cdot \mathbf{b} $$ |
839 |
| - $$ b = 2 \mathbf{b} \cdot (\mathbf{A}-\mathbf{C}) $$ |
840 |
| - $$ c = (\mathbf{A}-\mathbf{C}) \cdot (\mathbf{A}-\mathbf{C}) - r^2 $$ |
| 842 | + $$ a = \mathbf{d} \cdot \mathbf{d} $$ |
| 843 | + $$ b = -2 \mathbf{d} \cdot (\mathbf{C} - \mathbf{Q}) $$ |
| 844 | + $$ c = (\mathbf{C} - \mathbf{Q}) \cdot (\mathbf{C} - \mathbf{Q}) - r^2 $$ |
841 | 845 |
|
842 | 846 | Using all of the above you can solve for $t$, but there is a square root part that can be either
|
843 | 847 | positive (meaning two real solutions), negative (meaning no real solutions), or zero (meaning one
|
|
854 | 858 |
|
855 | 859 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
856 | 860 | bool hit_sphere(const point3& center, double radius, const ray& r) {
|
857 |
| - vec3 oc = r.origin() - center; |
| 861 | + vec3 oc = center - r.origin(); |
858 | 862 | auto a = dot(r.direction(), r.direction());
|
859 |
| - auto b = 2.0 * dot(oc, r.direction()); |
| 863 | + auto b = -2.0 * dot(r.direction(), oc); |
860 | 864 | auto c = dot(oc, oc) - radius*radius;
|
861 | 865 | auto discriminant = b*b - 4*a*c;
|
862 | 866 | return (discriminant >= 0);
|
|
936 | 940 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
937 | 941 | double hit_sphere(const point3& center, double radius, const ray& r) {
|
938 | 942 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
939 |
| - vec3 oc = r.origin() - center; |
| 943 | + vec3 oc = center - r.origin(); |
940 | 944 | auto a = dot(r.direction(), r.direction());
|
941 |
| - auto b = 2.0 * dot(oc, r.direction()); |
| 945 | + auto b = -2.0 * dot(r.direction(), oc); |
942 | 946 | auto c = dot(oc, oc) - radius*radius;
|
943 | 947 | auto discriminant = b*b - 4*a*c;
|
944 | 948 |
|
|
983 | 987 |
|
984 | 988 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
985 | 989 | double hit_sphere(const point3& center, double radius, const ray& r) {
|
986 |
| - vec3 oc = r.origin() - center; |
| 990 | + vec3 oc = center - r.origin(); |
987 | 991 | auto a = dot(r.direction(), r.direction());
|
988 |
| - auto b = 2.0 * dot(oc, r.direction()); |
| 992 | + auto b = -2.0 * dot(r.direction(), oc); |
989 | 993 | auto c = dot(oc, oc) - radius*radius;
|
990 | 994 | auto discriminant = b*b - 4*a*c;
|
991 | 995 |
|
|
1000 | 1004 |
|
1001 | 1005 | First, recall that a vector dotted with itself is equal to the squared length of that vector.
|
1002 | 1006 |
|
1003 |
| -Second, notice how the equation for `b` has a factor of two in it. Consider what happens to the |
1004 |
| -quadratic equation if $b = 2h$: |
| 1007 | +Second, notice how the equation for `b` has a factor of negative two in it. Consider what happens to |
| 1008 | +the quadratic equation if $b = -2h$: |
1005 | 1009 |
|
1006 | 1010 | $$ \frac{-b \pm \sqrt{b^2 - 4ac}}{2a} $$
|
1007 | 1011 |
|
1008 |
| - $$ = \frac{-2h \pm \sqrt{(2h)^2 - 4ac}}{2a} $$ |
| 1012 | + $$ = \frac{-(-2h) \pm \sqrt{(-2h)^2 - 4ac}}{2a} $$ |
| 1013 | + |
| 1014 | + $$ = \frac{2h \pm 2\sqrt{h^2 - ac}}{2a} $$ |
| 1015 | + |
| 1016 | + $$ = \frac{h \pm \sqrt{h^2 - ac}}{a} $$ |
1009 | 1017 |
|
1010 |
| - $$ = \frac{-2h \pm 2\sqrt{h^2 - ac}}{2a} $$ |
| 1018 | +This simplifies nicely, so we'll use it. So solving for $h$: |
1011 | 1019 |
|
1012 |
| - $$ = \frac{-h \pm \sqrt{h^2 - ac}}{a} $$ |
| 1020 | + $$ b = -2 \mathbf{d} \cdot (\mathbf{C} - \mathbf{Q}) $$ |
| 1021 | + $$ b = -2h $$ |
| 1022 | + $$ h = \frac{b}{-2} = \mathbf{d} \cdot (\mathbf{C} - \mathbf{Q}) $$ |
1013 | 1023 |
|
1014 | 1024 | <div class='together'>
|
1015 | 1025 | Using these observations, we can now simplify the sphere-intersection code to this:
|
1016 | 1026 |
|
1017 | 1027 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
1018 | 1028 | double hit_sphere(const point3& center, double radius, const ray& r) {
|
1019 |
| - vec3 oc = r.origin() - center; |
| 1029 | + vec3 oc = center - r.origin(); |
1020 | 1030 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
1021 | 1031 | auto a = r.direction().length_squared();
|
1022 |
| - auto half_b = dot(oc, r.direction()); |
| 1032 | + auto h = dot(r.direction(), oc); |
1023 | 1033 | auto c = oc.length_squared() - radius*radius;
|
1024 |
| - auto discriminant = half_b*half_b - a*c; |
| 1034 | + auto discriminant = h*h - a*c; |
1025 | 1035 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
1026 | 1036 |
|
1027 | 1037 | if (discriminant < 0) {
|
1028 | 1038 | return -1.0;
|
1029 | 1039 | } else {
|
1030 | 1040 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
1031 |
| - return (-half_b - sqrt(discriminant) ) / a; |
| 1041 | + return (h - sqrt(discriminant)) / a; |
1032 | 1042 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
1033 | 1043 | }
|
1034 | 1044 | }
|
|
1096 | 1106 | sphere(point3 _center, double _radius) : center(_center), radius(_radius) {}
|
1097 | 1107 |
|
1098 | 1108 | bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const override {
|
1099 |
| - vec3 oc = r.origin() - center; |
| 1109 | + vec3 oc = center - r.origin(); |
1100 | 1110 | auto a = r.direction().length_squared();
|
1101 |
| - auto half_b = dot(oc, r.direction()); |
| 1111 | + auto h = dot(r.direction(), oc); |
1102 | 1112 | auto c = oc.length_squared() - radius*radius;
|
1103 | 1113 |
|
1104 |
| - auto discriminant = half_b*half_b - a*c; |
| 1114 | + auto discriminant = h*h - a*c; |
1105 | 1115 | if (discriminant < 0) return false;
|
1106 | 1116 | auto sqrtd = sqrt(discriminant);
|
1107 | 1117 |
|
1108 | 1118 | // Find the nearest root that lies in the acceptable range.
|
1109 |
| - auto root = (-half_b - sqrtd) / a; |
| 1119 | + auto root = (h - sqrtd) / a; |
1110 | 1120 | if (root <= ray_tmin || ray_tmax <= root) {
|
1111 |
| - root = (-half_b + sqrtd) / a; |
| 1121 | + root = (h + sqrtd) / a; |
1112 | 1122 | if (root <= ray_tmin || ray_tmax <= root)
|
1113 | 1123 | return false;
|
1114 | 1124 | }
|
|
1621 | 1631 | ...
|
1622 | 1632 |
|
1623 | 1633 | // Find the nearest root that lies in the acceptable range.
|
1624 |
| - auto root = (-half_b - sqrtd) / a; |
| 1634 | + auto root = (h - sqrtd) / a; |
1625 | 1635 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
1626 | 1636 | if (!ray_t.surrounds(root)) {
|
1627 | 1637 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
1628 |
| - root = (-half_b + sqrtd) / a; |
| 1638 | + root = (h + sqrtd) / a; |
1629 | 1639 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
1630 | 1640 | if (!ray_t.surrounds(root))
|
1631 | 1641 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
|
0 commit comments