Skip to content

Commit 4938a08

Browse files
committed
add: 05 ray tracing
1 parent c32659d commit 4938a08

15 files changed

+2878
-73
lines changed

.vitepress/cache/deps/@theme_index.js

Lines changed: 43 additions & 43 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.vitepress/cache/deps/@theme_index.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.vitepress/cache/deps/_metadata.json

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,67 @@
11
{
2-
"hash": "bfd779e8",
3-
"configHash": "e8571b6f",
4-
"lockfileHash": "3f6b421c",
5-
"browserHash": "20893c6b",
2+
"hash": "e46e6c73",
3+
"configHash": "5cb5fa37",
4+
"lockfileHash": "feaae835",
5+
"browserHash": "9252dc6e",
66
"optimized": {
77
"vue": {
88
"src": "../../../node_modules/vue/dist/vue.runtime.esm-bundler.js",
99
"file": "vue.js",
10-
"fileHash": "c0b47fcc",
10+
"fileHash": "906d191d",
1111
"needsInterop": false
1212
},
1313
"vitepress > @vue/devtools-api": {
14-
"src": "../../../node_modules/@vue/devtools-api/dist/index.js",
14+
"src": "../../../node_modules/.pnpm/@[email protected]/node_modules/@vue/devtools-api/dist/index.js",
1515
"file": "vitepress___@vue_devtools-api.js",
16-
"fileHash": "0f476dd9",
16+
"fileHash": "fb82672f",
1717
"needsInterop": false
1818
},
1919
"vitepress > @vueuse/core": {
20-
"src": "../../../node_modules/@vueuse/core/index.mjs",
20+
"src": "../../../node_modules/.pnpm/@[email protected]/node_modules/@vueuse/core/index.mjs",
2121
"file": "vitepress___@vueuse_core.js",
22-
"fileHash": "3a1dd39d",
22+
"fileHash": "92a9071a",
2323
"needsInterop": false
2424
},
2525
"@braintree/sanitize-url": {
2626
"src": "../../../node_modules/@braintree/sanitize-url/dist/index.js",
2727
"file": "@braintree_sanitize-url.js",
28-
"fileHash": "1ed726b3",
28+
"fileHash": "fefdcce4",
2929
"needsInterop": true
3030
},
3131
"dayjs": {
3232
"src": "../../../node_modules/dayjs/dayjs.min.js",
3333
"file": "dayjs.js",
34-
"fileHash": "de09bece",
34+
"fileHash": "0c0c9b6e",
3535
"needsInterop": true
3636
},
3737
"debug": {
3838
"src": "../../../node_modules/debug/src/browser.js",
3939
"file": "debug.js",
40-
"fileHash": "7efa3e4e",
40+
"fileHash": "7647ce37",
4141
"needsInterop": true
4242
},
4343
"cytoscape-cose-bilkent": {
4444
"src": "../../../node_modules/cytoscape-cose-bilkent/cytoscape-cose-bilkent.js",
4545
"file": "cytoscape-cose-bilkent.js",
46-
"fileHash": "b8213663",
46+
"fileHash": "e05a983b",
4747
"needsInterop": true
4848
},
4949
"cytoscape": {
5050
"src": "../../../node_modules/cytoscape/dist/cytoscape.esm.mjs",
5151
"file": "cytoscape.js",
52-
"fileHash": "833f9957",
52+
"fileHash": "0f0294b2",
5353
"needsInterop": false
5454
},
5555
"@theme/index": {
56-
"src": "../../../node_modules/vitepress/dist/client/theme-default/index.js",
56+
"src": "../../../node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected]/node_modules/vitepress/dist/client/theme-default/index.js",
5757
"file": "@theme_index.js",
58-
"fileHash": "09b2f572",
58+
"fileHash": "cc72bc7c",
5959
"needsInterop": false
6060
}
6161
},
6262
"chunks": {
63-
"chunk-AKQBXH3S": {
64-
"file": "chunk-AKQBXH3S.js"
63+
"chunk-GCHYJK2Z": {
64+
"file": "chunk-GCHYJK2Z.js"
6565
},
6666
"chunk-EAEFJUV4": {
6767
"file": "chunk-EAEFJUV4.js"

.vitepress/cache/deps/chunk-AKQBXH3S.js renamed to .vitepress/cache/deps/chunk-GCHYJK2Z.js

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.vitepress/cache/deps/chunk-AKQBXH3S.js.map renamed to .vitepress/cache/deps/chunk-GCHYJK2Z.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.vitepress/cache/deps/vitepress___@vue_devtools-api.js

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.vitepress/cache/deps/vitepress___@vue_devtools-api.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.vitepress/cache/deps/vitepress___@vueuse_core.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.vitepress/config.mts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ export default withMermaid({
2525
text: "02 - Texture and Shader",
2626
link: "/labs/02-texture-and-shader",
2727
},
28+
{
29+
text: "05 - Ray Tracing",
30+
link: "/labs/05-ray-tracing",
31+
},
2832
],
2933
},
3034
],

labs/05-ray-tracing.md

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
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+
![Github Repository](/public/images/ray-tracing-2.png)
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+
![PPM Image](/public/images/ray-tracing-3.png)
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+
![Example](/public/images/ray-tracing-1.png)
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

Comments
 (0)