|
2975 | 2975 |
|
2976 | 2976 | <div class='together'>
|
2977 | 2977 | Now that we have boxes, we need to rotate them a bit to have them match the _real_ Cornell box. In
|
2978 |
| -ray tracing, this is usually done with an _instance_. An instance is a copy of a geometric |
| 2978 | +ray tracing, this is usually done with an _instance_. An instance is a copy of a geometric |
2979 | 2979 | primitive that has been placed into the scene. This instance is entirely independent of the other
|
2980 |
| -copies of the primitive and can be moved or rotated around. In this case our geometric primitive is |
2981 |
| -our box hittable, and we want to rotate it somehow. This is especially easy in ray tracing because |
2982 |
| -we don’t move anything; instead we move the rays in the opposite direction. For example, consider a |
2983 |
| -_translation_ (often called a _move_). We could take the pink box at the origin and add 2 to all its |
2984 |
| -x components, or (as we almost always do in ray tracing) leave the box where it is, but in its hit |
2985 |
| -routine subtract 2 off the x-component of the ray origin. |
| 2980 | +copies of the primitive and can be moved or rotated. In this case, our geometric primitive is our |
| 2981 | +hittable `box` object, and we want to rotate it. This is especially easy in ray tracing because we |
| 2982 | +don’t actually need to move objects in the scene; instead we move the rays in the opposite |
| 2983 | +direction. For example, consider a _translation_ (often called a _move_). We could take the pink box |
| 2984 | +at the origin and add two to all its x components, or (as we almost always do in ray tracing) leave |
| 2985 | +the box where it is, but in its hit routine subtract two off the x-component of the ray origin. |
2986 | 2986 |
|
2987 | 2987 | ![Figure [ray-box]: Ray-box intersection with moved ray vs box](../images/fig-2.08-ray-box.jpg)
|
2988 | 2988 |
|
|
2996 | 2996 | this is to think of moving the incident ray backwards the offset amount, determining if an
|
2997 | 2997 | intersection occurs, and then moving that intersection point forward the offset amount.
|
2998 | 2998 |
|
2999 |
| -If we have an intersection along the offset ray, then we know that the incident ray will hit the |
3000 |
| -translated object. However, our offset ray is not the original ray, so if we just take the |
3001 |
| -intersection we found along the offset ray then our intersection will actually be wrong by the |
3002 |
| -offset amount, so we have to shift the intersection point back onto the original ray by the offset |
3003 |
| -amount. Let's add the code to make this happen. |
| 2999 | +We need to move the intersection point forward the offset amount so that the intersection is |
| 3000 | +actually in the path of the incident ray. If we forgot to move the intersection point forward then |
| 3001 | +the intersection would be in the path of the offset ray, which isn't correct. Let's add the code to |
| 3002 | +make this happen. |
3004 | 3003 |
|
3005 | 3004 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
3006 | 3005 | class translate : public hittable {
|
|
3067 | 3066 | [Listing [translate-class]: <kbd>[hittable.h]</kbd> Hittable translation class]
|
3068 | 3067 | </div>
|
3069 | 3068 |
|
3070 |
| -We need to remember to offset the bounding box, otherwise the incident ray might be looking in the |
3071 |
| -wrong place and trivially reject the intersection. The expression `object->bounding_box() + offset` |
3072 |
| -above requires some additional support. |
| 3069 | +We also need to remember to offset the bounding box, otherwise the incident ray might be looking in |
| 3070 | +the wrong place and trivially reject the intersection. The expression |
| 3071 | +`object->bounding_box() + offset` above requires some additional support. |
3073 | 3072 |
|
3074 | 3073 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
3075 | 3074 | class aabb {
|
|
3152 | 3151 | $$ z' = \sin(\theta) \cdot y + \cos(\theta) \cdot z $$
|
3153 | 3152 | </div>
|
3154 | 3153 |
|
3155 |
| -For a simple operation like a translation, thinking of the operation as a simple movement of the |
3156 |
| -initial ray is a fine way to reason about what's going on. But, for a more complex operation like a |
3157 |
| -rotation, it can be easy to accidentally get your terms crossed (or forget a negative sign), so it's |
3158 |
| -better to consider a rotation as a change of coordinates. The pseudocode for the `translate::hit` |
3159 |
| -function above describes the function in terms of _moving_: |
| 3154 | +Thinking of translation as a simple movement of the initial ray is a fine way to reason about what's |
| 3155 | +going on. But, for a more complex operation like a rotation, it can be easy to accidentally get your |
| 3156 | +terms crossed (or forget a negative sign), so it's better to consider a rotation as a change of |
| 3157 | +coordinates. |
3160 | 3158 |
|
3161 |
| - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ |
3162 |
| - bool hit(const ray& r, interval ray_t, hit_record& rec) const override { |
3163 |
| - // Move the ray backwards by the offset |
3164 |
| - |
3165 |
| - // Determine where (if any) an intersection occurs along the offset ray |
| 3159 | +The pseudocode for the `translate::hit` function above describes the function in terms of _moving_: |
3166 | 3160 |
|
3167 |
| - // Move the intersection point forwards by the offset |
3168 |
| - } |
3169 |
| - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
3170 |
| - [Listing [translate-hit-move]: <kbd>[hittable.h]</kbd> The moving translate hit code] |
| 3161 | +1. Move the ray backwards by the offset |
| 3162 | +2. Determine where (if any) an intersection occurs along the offset ray |
| 3163 | +3. Move the intersection point forwards by |
3171 | 3164 |
|
3172 | 3165 | But this can also be thought of in terms of a _changing of coordinates_:
|
3173 | 3166 |
|
3174 |
| - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ |
3175 |
| - bool hit(const ray& r, interval ray_t, hit_record& rec) const override { |
3176 |
| - // Change the ray from world space to object space |
| 3167 | +1. Change the ray from world space to object space |
| 3168 | +2. Determine where (if any) an intersection occurs in object space |
| 3169 | +3. Change the intersection point from object space to world space |
3177 | 3170 |
|
3178 |
| - // Determine where (if any) an intersection occurs in object space |
3179 |
| - |
3180 |
| - // Change the intersection point from object space to world space |
3181 |
| - } |
3182 |
| - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
3183 |
| - [Listing [translate-hit-coord]: <kbd>[hittable.h]</kbd> The change of coordinates translate hit code] |
3184 | 3171 |
|
3185 | 3172 | <div class='together'>
|
3186 | 3173 | Rotating an object will not only change the point of intersection, but will also change the surface
|
3187 |
| -normal vector, which will change the direction of reflections and refractions. So we need to change the |
3188 |
| -normal as well. Fortuneatly, we can just treat the normal like a vector, and so use the same |
3189 |
| -formulas as above. |
| 3174 | +normal vector, which will change the direction of reflections and refractions. So we need to change |
| 3175 | +the normal as well. Fortunately, the normal will rotate similarly to a vector, so we can use the |
| 3176 | +same formulas as above. While normals and vectors may appear identical for an object undergoing |
| 3177 | +rotation and translation, an object undergoing scaling requires special attention to keep the |
| 3178 | +normals orthogonal to the surface. We won't cover that here, but you should research surface normal |
| 3179 | +transformations if you implement scaling. |
| 3180 | + |
| 3181 | +We need to start by changing the ray from world space to object space, which for rotation means |
| 3182 | +rotating by $-\theta$. |
3190 | 3183 |
|
3191 |
| -For a y-rotation class we have: |
| 3184 | + $$ x' = \cos(\theta) \cdot x - \sin(\theta) \cdot z $$ |
| 3185 | + $$ z' = \sin(\theta) \cdot x + \cos(\theta) \cdot z $$ |
| 3186 | + |
| 3187 | +We can now create a class for y-rotation: |
3192 | 3188 |
|
3193 | 3189 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
3194 | 3190 | class rotate_y : public hittable {
|
|
3234 | 3230 | [Listing [rot-y-hit]: <kbd>[hittable.h]</kbd> Hittable rotate-Y hit function]
|
3235 | 3231 |
|
3236 | 3232 | </div>
|
3237 |
| -The code for solving from world space to object space might at first appear incorrect because we are |
3238 |
| -rotating the opposite way. The negative sign of the `sin_theta` terms are flipped. While we want to |
3239 |
| -rotate around the y-axis by $\theta$, the formula used has our world space to object space solving |
3240 |
| -for $-\theta$. What we have above is actually correct. It's the exact same thing that we did above |
3241 |
| -for translation. Changing from world space to object space required us to change by |
3242 |
| -$-\text{offset}$. Changing from world space to object space for rotation requires us to rotate by |
3243 |
| -$-\theta$. And, just as before with translation, where the change from object space to world space |
3244 |
| -required a change of $+\text{offset}$, the change in rotation from object space to world space |
3245 |
| -requires $+\theta$. |
3246 |
| - |
3247 |
| -With all of that said, we can now flesh out the rest of the class: |
| 3233 | +... and now for the rest of the class: |
3248 | 3234 |
|
3249 | 3235 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
3250 | 3236 | class rotate_y : public hittable {
|
|
0 commit comments