|
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