|
| 1 | +# Lab 05: Ray Tracing - Becoming a Virtual Photographer |
| 2 | + |
| 3 | +In previous labs, you've learned how to instruct the GPU to draw shapes and apply textures using a process called rasterization. Now, we're going to take a completely different approach to creating images: **Ray Tracing**. |
| 4 | + |
| 5 | +Imagine you are a photographer in a virtual world. To take a picture, you don't just throw objects at the screen. Instead, you decide where each pixel's color comes from by tracing the path of a light ray _backwards_ from your camera, through the pixel, and out into the scene. What that ray hits determines the color. This is the essence of ray tracing, a technique famous for creating stunningly realistic images. |
| 6 | + |
| 7 | +In this lab, you'll build the core of a ray tracer from scratch. You'll be the photographer, the lighting designer, and the architect of your own 3D world. |
| 8 | + |
| 9 | + |
| 10 | + |
| 11 | +[Repository Link](https://github.com/2110479-Computer-Graphics/Lab05-Raytracing) |
| 12 | + |
| 13 | +### Prerequisites: The Tools of a Virtual Photographer |
| 14 | + |
| 15 | +Before we build our camera, we need to understand our "film" and the fundamental theory behind our new photography method. |
| 16 | + |
| 17 | +#### The PPM File: Your Digital Film |
| 18 | + |
| 19 | +In past labs, we let OpenGL and the GPU handle the complex task of displaying our image on the screen. For this ray tracer, we are going to generate the image file ourselves, pixel by pixel. To keep things simple, we'll use the **PPM (Portable Pixmap) file format**. |
| 20 | + |
| 21 | +Why PPM? It's a beautifully simple, text-based image format. You can literally open a `.ppm` file in a text editor and see the pixels! A PPM file looks like this: |
| 22 | + |
| 23 | +<div style="align-items: center; display: flex; flex-direction: column; gap: 1rem;"> |
| 24 | + |
| 25 | + |
| 26 | + |
| 27 | +</div> |
| 28 | + |
| 29 | +``` |
| 30 | +P3 |
| 31 | +# P3 means this is an ASCII PPM file |
| 32 | +# The next line is the width and height of the image |
| 33 | +3 2 |
| 34 | +# The next line is the maximum color value |
| 35 | +255 |
| 36 | +# Below are the pixel RGB triplets (Red, Green, Blue) |
| 37 | +255 0 0 # Red pixel |
| 38 | +0 255 0 # Green pixel |
| 39 | +0 0 255 # Blue pixel |
| 40 | +255 255 0 # Yellow pixel |
| 41 | +255 255 255 # White pixel |
| 42 | +0 0 0 # Black pixel |
| 43 | +``` |
| 44 | + |
| 45 | +Our C++ program will calculate the RGB color for every single pixel in our scene and write it to a `.ppm` file in this exact format. You can then open this file with most image viewers (like GIMP, IrfanView, or specialized online viewers). |
| 46 | + |
| 47 | +#### The Core Idea: From Pixels to Light Rays |
| 48 | + |
| 49 | +The most important concept to grasp is the shift from **rasterization** to **ray tracing**. |
| 50 | + |
| 51 | +- **Rasterization (What you've done before)**: You take 3D objects (triangles) and project them onto a 2D screen to figure out which pixels they cover. It's an "object-first" approach, processed incredibly fast by the GPU. |
| 52 | +- **Ray Tracing (What you'll do now)**: You start with a 2D pixel on the screen and cast a ray from the camera out into the 3D world to see what it hits. It's a "pixel-first" approach, which we will implement on the CPU. This method excels at simulating how light really works, making reflections, shadows, and refractions much easier to achieve realistically. |
| 53 | + |
| 54 | +### Part 1: Setting Up the Camera (Your Virtual Eye) |
| 55 | + |
| 56 | +A photographer can't take a picture without a camera. Our virtual camera's job is to shoot out rays of light into the scene. Each pixel in our final image corresponds to one initial ray. |
| 57 | + |
| 58 | +#### Step 1.1: Understanding the Viewport |
| 59 | + |
| 60 | +Think of the final image as a screen or "viewport" positioned in front of your camera. To figure out the color of a specific pixel, we cast a **ray** from the camera's origin, through that pixel's position on the viewport, and into the world. |
| 61 | + |
| 62 | +- **Examine `camera.cpp`**: Look at the `get_ray()` method. This function is the heart of your camera. It takes the coordinates of a pixel (`u`, `v`) and calculates the direction of the ray that should pass through it. |
| 63 | +- **Experiment**: Try modifying the camera's position, the point it's looking at, or its field-of-view (aperture). Observe how changing your "lens" or "position" alters the final rendered image. |
| 64 | + |
| 65 | +### Part 2: What Did the Ray Hit? (Ray-Sphere Intersection) |
| 66 | + |
| 67 | +You've cast a ray out into the world. Now what? The ray travels in a straight line until it hits an object. Your next task is to detect that collision, or **intersection**. |
| 68 | + |
| 69 | +We'll start with the simplest 3D shape: a sphere. To find if a line (our ray) and a sphere intersect, we can use a bit of algebra. The ray can be described by the equation $$P(t) = A + t\vec{b}$$, where A is the ray's origin and $$\vec{b}$$ is its direction. The sphere is defined by all points a certain radius, _r_, from its center, _C_. |
| 70 | + |
| 71 | +By solving for _t_, we can find the exact point of intersection. |
| 72 | + |
| 73 | +- **Analyze `sphere.cpp`**: This file contains the code that solves this exact problem. You'll see a function that implements the quadratic equation to find if, and where, the ray hits the sphere. |
| 74 | +- **Play with it**: Create spheres of different sizes and at different locations in your `main.cpp` file to see your intersection logic at work. |
| 75 | + |
| 76 | +### Part 3: What Does It Look Like? (Implementing Materials) |
| 77 | + |
| 78 | +Once a ray hits an object, we need to know its color. This is determined by the object's **material**. How does it interact with light? Does it absorb it, scatter it, or reflect it like a mirror? |
| 79 | + |
| 80 | +```mermaid |
| 81 | +graph TD |
| 82 | + A["Ray from Camera"] --> B{"Did it hit anything?"}; |
| 83 | + B -- Yes --> C{"What material is it?"}; |
| 84 | + C --> D["Lambertian (Matte)<br/>Scatters light randomly"]; |
| 85 | + C --> E["Metal (Shiny)<br/>Reflects light like a mirror"]; |
| 86 | + B -- No --> F["Set pixel to background color (e.g., sky)"]; |
| 87 | + D --> G["Calculate final pixel color"]; |
| 88 | + E --> G["Calculate final pixel color"]; |
| 89 | +``` |
| 90 | + |
| 91 | +#### Step 3.1: The Matte Painter (Lambertian Material) |
| 92 | + |
| 93 | +A **Lambertian**, or diffuse, material represents a perfect matte surface, like a piece of colored chalk or a painted wall. When light hits it, it scatters in all random directions. The result is a surface with a uniform, flat appearance. |
| 94 | + |
| 95 | +- **Study `materials/lambertian.cpp`**: Understand how it uses the object's surface normal (the direction the surface is facing) to calculate this scattered ray. |
| 96 | + |
| 97 | +#### Step 3.2: The Polished Chrome (Metal Material) |
| 98 | + |
| 99 | +A **Metal** material is specular, or reflective. It acts like a mirror. A ray that hits it bounces off in a predictable direction, just like a ball bouncing off a wall. We can also add a "roughness" parameter, which introduces a bit of random fuzziness to the reflections, simulating a brushed or sand-blasted metal surface. |
| 100 | + |
| 101 | +- **Examine `materials/metal.cpp`**: See how it calculates the perfect reflection vector and how the `roughness` parameter perturbs that vector to create blurry reflections. |
| 102 | + |
| 103 | +### Part 4: Building Your World (Scene Composition) |
| 104 | + |
| 105 | +Now you have all the pieces: a camera, objects (spheres), and materials (Lambertian and Metal). It's time to be an architect and compose a scene! |
| 106 | + |
| 107 | +- **Work in `main.cpp`**: This is your playground. |
| 108 | + 1. Create a "world" that can hold a list of objects. |
| 109 | + 2. Instantiate several spheres. |
| 110 | + 3. Assign different materials to them. Try a mix of matte and metallic objects. |
| 111 | + 4. Position them in an interesting way. Maybe one sphere is large and acts as the "ground." |
| 112 | + |
| 113 | +### Part 5: The Final Image (Rendering Pipeline & Polish) |
| 114 | + |
| 115 | +This is where everything comes together. The complete process, from your camera to the final pixel color, is the **rendering pipeline**. For each pixel in your image: |
| 116 | + |
| 117 | +1. **Generate a Ray**: Create the initial ray from the camera. |
| 118 | +2. **Test for Intersection**: Loop through all objects in the scene and find the closest one the ray hits. |
| 119 | +3. **Calculate Color**: If you hit an object, ask its material how the light scatters or reflects. This might create new rays that bounce around the scene! |
| 120 | +4. **Set Pixel Color**: The color returned from the material is the final color for that pixel. |
| 121 | + |
| 122 | +#### Advanced Feature: Anti-Aliasing |
| 123 | + |
| 124 | +If you cast only one ray per pixel, you might notice sharp, jagged edges ("jaggies"). To fix this, we can use **anti-aliasing**. Instead of sending one ray through the center of a pixel, we send multiple, slightly offset rays and average the resulting colors. This produces a much smoother and more realistic final image. |
| 125 | + |
| 126 | +### Part 6: Your Creative Project (Deliverables) |
| 127 | + |
| 128 | +Now it's your turn to be the artist and engineer. |
| 129 | + |
| 130 | +### Example |
| 131 | + |
| 132 | + |
| 133 | + |
| 134 | +#### Task A: The Basic Scene |
| 135 | + |
| 136 | +- Fill all `TODO` sections in provided files. |
| 137 | +- Render an image with at least three spheres. |
| 138 | +- Use both `Lambertian` and `Metal` materials to show you understand both. |
| 139 | +- Include a large sphere to act as a ground plane. |
| 140 | + |
| 141 | +#### Task B: Material & Shape Exploration |
| 142 | + |
| 143 | +- **Create Your Own Material**: Go beyond Metal and Lambertian. Implement a new material. Some ideas: |
| 144 | + - **Glass/Dielectric (`refract`)**: A transparent material that bends light. |
| 145 | + - **Emissive (`light`)**: A material that glows and gives off its own light. |
| 146 | +- **Create Your Own Shape**: Don't just use spheres. Implement the intersection logic for a new geometric primitive. Some ideas: |
| 147 | + - An infinite **Plane**. |
| 148 | + - An **Axis-Aligned Bounding Box (AABB)**. |
| 149 | + |
| 150 | +Good luck, and have fun creating your first photorealistic images! |
| 151 | + |
| 152 | +--- |
| 153 | + |
| 154 | +### Resources |
| 155 | + |
| 156 | +- [Ray Tracing in One Weekend by Peter Shirley](https://raytracing.github.io/books/RayTracingInOneWeekend.html) |
| 157 | +- _Real-Time Rendering_ (Akenine-Möller et al.) |
| 158 | +- _Computer Graphics: Principles and Practice_ |
0 commit comments