Commit 352b7111 authored by TheNumbat's avatar TheNumbat
Browse files

update a3 docs

parent 21be98a3
...@@ -17,11 +17,13 @@ Now, you need to implement the `hit` routine for both `Triangle` and `Sphere`. ` ...@@ -17,11 +17,13 @@ Now, you need to implement the `hit` routine for both `Triangle` and `Sphere`. `
In order to correctly implement `hit` you need to understand some of the fields in the Ray structure defined in `lib/ray.h`. In order to correctly implement `hit` you need to understand some of the fields in the Ray structure defined in `lib/ray.h`.
* `point`: represents the 3D point of origin of the ray * `point`: the 3D point of origin of the ray
* `dir`: represents the 3D direction of the ray (this direction will be normalized) * `dir`: the 3D direction of the ray (always normalized)
* `time_bounds`: correspond to the minimum and maximum points on the ray with its x-component as the lower bound and y-component as the upper bound. That is, intersections that lie outside the [`ray.time_bounds.x`, `ray.time_bounds.y`] range should not be considered valid intersections with the primitive. * `dist_bounds`: the minimum and maximum distance along the ray. Primitive intersections that lie outside the [`ray.dist_bounds.x`, `ray.dist_bounds.y`] range should be disregarded.
* `depth`: the recursive depth of the ray (Used in task 5).
* `throughput`: the fraction of incoming light along this ray that will contribute to the final image (Used in task 5).
One important detail of the Ray structure is that `time_bounds` is a mutable field of the Ray. This means that this fields can be modified by constant member functions such as `Triangle::hit`. When finding the first intersection of a ray and the scene, you almost certainly want to update the ray's `time_bounds` value after finding each hit with scene geometry. By bounding the ray as tightly as possible, your ray tracer will be able to avoid unnecessary tests with scene geometry that is known to not be able to result in a closest hit, resulting in higher performance. One important detail of the ray structure is that `dist_bounds` is a mutable field. This means that it can be modified even in `const` rays, for example within `Triangle::hit`. When finding the first intersection of a ray and the scene, you will want to update the ray's `dist_bounds` value after finding each hit with scene geometry. By bounding the ray as tightly as possible, your ray tracer will be able to avoid unnecessary tests with scene geometry that is known to not be able to result in a closest hit, resulting in higher performance.
--- ---
...@@ -35,25 +37,24 @@ There are two important details you should be aware of about intersection: ...@@ -35,25 +37,24 @@ There are two important details you should be aware of about intersection:
* When finding the first-hit intersection with a triangle, you need to fill in the `Trace` structure with details of the hit. The structure should be initialized with: * When finding the first-hit intersection with a triangle, you need to fill in the `Trace` structure with details of the hit. The structure should be initialized with:
* `hit`: a boolean representing if there is a hit or not * `hit`: a boolean representing if there is a hit or not.
* `time`: the ray's _t_-value of the hit point * `distance`: the distance from the origin of the ray to the hit point.
* `position`: the exact position of the hit point. This can be easily computed by the `time` above as with the ray's `point` and `dir`. * `position`: the position of the hit point. This may also be computed from `distance` and the query ray.
* `normal`: the normal of the surface at the hit point. This normal should be the interpolated normal (obtained via interpolation of the per-vertex normals according to the barycentric coordinates of the hit point) * `normal`: the normal of the surface at the hit point. If the intersection is with a triangle, the normal should be interpolated from per-vertex normals according to the barycentric coordinates of the hit point.
* `origin`: the origin of the query ray (ignore).
<!-- * When intersection occurs with the back-face of a triangle (the side of the triangle opposite the direction of the normal) you should flip the returned normal to point in that direction. That is, always return a normal pointing in the direction the ray came from! --> * `material`: the material ID of the hit object (ignore).
Once you've successfully implemented triangle intersection, you will be able to render many of the scenes in the media directory. However, your ray tracer will be very slow! Once you've successfully implemented triangle intersection, you will be able to render many of the scenes in the media directory. However, your ray tracer will be very slow!
While you are working with `student/tri_mesh.cpp`, you should implement `Triangle::bbox` as well, which are important for task 3. **While you are working with `student/tri_mesh.cpp`, you should implement `Triangle::bbox` as well, which are important for task 3.**
### **Step 2: Intersecting Spheres** ### **Step 2: Intersecting Spheres**
You also need to implement the `hit` routines for the `Sphere` class in `student/sphapes.cpp`. Remember that your intersection tests should respect the ray's `time_bound`. Because spheres always represent closed surfaces, you should not flip back-facing normals you did with triangles. You also need to implement the `hit` routines for the `Sphere` class in `student/sphapes.cpp`. Remember that your intersection tests should respect the ray's `dist_bound`. Because spheres always represent closed surfaces, you should not flip back-facing normals you did with triangles.
Note: take care **not** to use the `Vec3::normalize()` method when computing your Note: take care **not** to use the `Vec3::normalize()` method when computing your
normal vector. You should instead use `Vec3::unit()`, since `Vec3::normalize()` normal vector. You should instead use `Vec3::unit()`, since `Vec3::normalize()`
will actually change the `Vec3` object passed in rather than returning a will actually change the `Vec3` calling object rather than returning a
normalized version. normalized version.
--- ---
......
...@@ -18,4 +18,4 @@ intersection point, for ray-triangle intersection. ...@@ -18,4 +18,4 @@ intersection point, for ray-triangle intersection.
A few final notes and thoughts: A few final notes and thoughts:
If the denominator _dot((e1 x d), e2)_ is zero, what does that mean about the relationship of the ray and the triangle? Can a triangle with this area be hit by a ray? Given _u_ and _v_, how do you know if the ray hits the triangle? Don't forget that the intersection point on the ray should be within the ray's `time_bound`. If the denominator _dot((e1 x d), e2)_ is zero, what does that mean about the relationship of the ray and the triangle? Can a triangle with this area be hit by a ray? Given _u_ and _v_, how do you know if the ray hits the triangle? Don't forget that the intersection point on the ray should be within the ray's `dist_bounds`.
...@@ -19,16 +19,20 @@ Shadows occur when another scene object blocks light emitted from scene light so ...@@ -19,16 +19,20 @@ Shadows occur when another scene object blocks light emitted from scene light so
Your job is to implement the logic needed to compute whether hit point is in shadow with respect to the current light source sample. Below are a few notes: Your job is to implement the logic needed to compute whether hit point is in shadow with respect to the current light source sample. Below are a few notes:
* In the starter code, when we call `light.sample(hit.position)`, it returns us a `Light_sample sample` at the hit point . (You might want to take a look at `rays/light.h` for the definition of `struct Light_sample` and `class light`.) A `Light_sample` contains fields `radiance`, `pdf`, `direction`, and `distance`. In particular, `sample.direction` is the direction from the hit point to the light source, and `sample.distance` is the distance from the hit point to the light source. * In the starter code, when we call `light.sample(hit.position)`, it returns us a `Light_Sample` at the hit point . (You might want to take a look at `rays/light.h` for the definition of `struct Light_Sample` and `class light`.) A `Light_Sample` contains fields `radiance`, `pdf`, `direction`, and `distance`. In particular, `sample.direction` is the direction from the hit point to the light source, and `sample.distance` is the distance from the hit point to the light source.
* A common ray tracing pitfall is for the "shadow ray" shot into the scene to accidentally hit the same objecr as `r` (the surface is erroneously determined to be occluded because the shadow ray is determined to hit the surface!). We recommend that you make sure the origin of the shadow ray is offset from the surface to avoid these erroneous "self-intersections". For example, consider setting the origin of the shadow ray to be `hit.position + epsilon * sample.direction` instead of simply `hit.position`. `EPS_F` is defined in for this purpose(see `lib/mathlib.h`). * A common ray tracing pitfall is for the "shadow ray" shot into the scene to accidentally hit the same object as the original ray. That is, the surface is erroneously determined to be occluded because the shadow ray hits itself! To fix this, you can set the minimum valid intersection distance (`dist_bound.x`) to a small positive value, for example `EPS_F`. `EPS_F` is defined in for this purpose(see `lib/mathlib.h`).
* Another common pitfall is forgetting that it doesn't matter if the shadow ray hits any scene geometry after reaching the light. Note that the light's distance from the hit point is given by `sample.distance`, and you can again limit the distance we check for intersections with `dist_bound`. Also consider the fact that using the _exact_ distance bound can have the same issues as shadow self-intersections.
* Another common pitfall is forgetting that it doesn't matter if the shadow ray hits any scene geometry after reaching the light. Note that the light's distance from the hit point is given by `sample.distance`. Also note that `Ray` has a member called `time_bound`...
* You will find it useful to debug your shadow code using the `DirectionalLight` since it produces hard shadows that are easy to reason about. * You will find it useful to debug your shadow code using the `DirectionalLight` since it produces hard shadows that are easy to reason about.
* You would want to comment out the line `Spectrum radiance_out = Spectrum(0.5f);` and initialize the `radiance_out` to a more reasonable value. Hint: is there supposed to have any amount of light before we even start considering each light sample?
* You must comment out the line `Spectrum radiance_out = Spectrum(0.5f);` and initialize the `radiance_out` to a more reasonable value. Hint: is there supposed to have any amount of light before we even start considering each light sample?
At this point you should be able to render very striking images. At this point you should be able to render very striking images.
If you've got shadow rays working and want a moderate performance boost, you can modify your BVH traversal for shadow rays (and only shadow rays) to return immediately upon any valid hit. This is sufficient because we don't actually need the closest hit to see if the shadow ray is occluded - just whether there was any valid hit at all.
## Sample results: ## Sample results:
At this point, you can add all kinds of lights among the options you have when you create "New Light" in Layout mode, except for Sphere Light and Environment Map which you will implement in task 7 (Note that you can still fill in `Sphere::Uniform::sample` in `Samplers.cpp` now to view the result of a mesh under Sphere Light). At this point, you can add all kinds of lights among the options you have when you create "New Light" in Layout mode, except for Sphere Light and Environment Map which you will implement in task 7 (Note that you can still fill in `Sphere::Uniform::sample` in `Samplers.cpp` now to view the result of a mesh under Sphere Light).
......
...@@ -11,6 +11,8 @@ For debugging purposes: ...@@ -11,6 +11,8 @@ For debugging purposes:
You can set the `bool normal_colors` to true in `student/debug.h` to check if the normals that you have computed at the hit point are correct or not for debugging purposes. You can set the `bool normal_colors` to true in `student/debug.h` to check if the normals that you have computed at the hit point are correct or not for debugging purposes.
You can also toggle the option at runtime by opening the Edit > Debug Data menu. These UI options are documented and implemented in `student/debug.cpp`, so feel free to add your own!
Here are some reference results: Here are some reference results:
<img src="new_results/cbox_normal.png" style="height:200px"> <img src="new_results/norm1.png" style="height:200px"> <img src="new_results/cbox_normal.png" style="height:200px"> <img src="new_results/norm1.png" style="height:200px">
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment