-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscotty3d.html
More file actions
310 lines (285 loc) · 15.9 KB
/
scotty3d.html
File metadata and controls
310 lines (285 loc) · 15.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Scotty3D | Jose Lima</title>
<link rel="stylesheet" href="./assets/css/style.css">
<link href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;600&family=Orbitron:wght@700&display=swap" rel="stylesheet">
</head>
<body>
<!-- Navigation Bar -->
<nav class="navbar">
<div class="nav-left">
<a href="index.html" style="color: inherit; text-decoration: none;">Jose Lima</a>
<div class="subheading">Information Systems @ CMU</div>
</div>
<ul class="nav-links">
<li><a href="about.html">About Me</a></li>
<li><a href="portfolio.html">Projects</a></li>
<li><a href="joselima_resume.pdf">Resume</a></li>
<!-- <li><a href="contact.html">Contact</a></li> -->
</ul>
</nav>
<!-- Hero Section -->
<header class="hero">
<h1>Scotty 3D</h1>
</header>
<!-- Bar 1 -->
<div class="project-meta-bar">
<div class="project-meta-item">
<span class="project-meta-label">Role</span>
<span class="project-meta-value">3D Graphics Engineer</span>
</div>
<span class="project-meta-divider">|</span>
<div class="project-meta-item">
<span class="project-meta-label">Timeline</span>
<span class="project-meta-value">Aug 2025 – Dec 2025</span>
</div>
<span class="project-meta-divider">|</span>
<div class="project-meta-item">
<span class="project-meta-label">Course</span>
<span class="project-meta-value">CMU 15-362: Computer Graphics</span>
</div>
</div>
<!-- Bar 2 -->
<div class="project-meta-bar">
<div class="project-meta-item">
<span class="project-meta-label">Tools</span>
<span class="project-meta-value"> C++, Visual Studio Code, Git</span>
</div>
</div>
<!-- Main Content -->
<main class="main-content">
<section class="section">
<p>
For my Computer Graphics course at Carnegie Mellon University, I worked on assignments in Scotty 3D,
a C++ graphics engine developed for teaching rendering, mesh operations, pathtracing, and animation systems.
</p>
<br>
<h3>Assignment 1: Rendering Foundations</h3>
<p>
The first assignment focused on building the rendering pipeline from the ground up. I implemented the
transformation system that aligns object, parent, and world coordinates through a hierarchical scene graph.
This allowed objects in the scene to move relative to their parents while maintaining a global world-space representation.
</p>
<p>
I then implemented rasterization techniques for rendering primitives such as lines and triangles.
This included enforcing coverage rules, handling triangle winding, and introducing flat shading.
Later, I extended these implementations to support perspective-correct interpolation for accurate
texture mapping and attribute assignment.
</p>
<figure style="margin: 20px auto; text-align:center; max-width:80%;">
<img src="assets/images/A1T4-cubes-after.png" alt="Anti-Aliasing Before and After"
style="width:100%; border-radius:8px;">
<figcaption style="color:#aaa; font-size:0.9rem; margin-top:0.5rem;">
After implementing triangle rasterization
</figcaption>
</figure>
<p>
To improve visual fidelity, I integrated depth testing and blending operations,
enabling proper layering of objects and transparency effects. The final step was adding
super-sampling to reduce aliasing, which produced smoother images by averaging multiple
samples per pixel. Below is my render submission for this assignment.
</p>
<figure style="margin: 20px auto; text-align:center; max-width:80%;">
<img src="assets/images/render.png" alt="Anti-Aliasing Before and After"
style="width:100%; border-radius:8px;">
<figcaption style="color:#aaa; font-size:0.9rem; margin-top:0.5rem;">
Render Submission for Assignment 1
</figcaption>
</figure>
<h3>Assignment 2: Mesh Editing</h3>
<p>
The second assignment introduced interactive mesh editing through the halfedge data structure.
I developed local operations such as edge flips and edge splits, enabling the user to restructure meshes
while preserving valid connectivity.
</p>
<div style="display:flex; justify-content:center; gap:30px; flex-wrap:wrap; margin:20px 0;">
<!-- Before Flip -->
<figure style="flex:0 0 45%; text-align:center;">
<img src="assets/images/BeforeFlip.png" alt="Before Edge Flip"
style="width:100%; height:300px; object-fit:cover; border-radius:8px;">
<figcaption style="color:#aaa; font-size:0.9rem; margin-top:0.5rem;">Before Edge Flip</figcaption>
</figure>
<!-- After Flip -->
<figure style="flex:0 0 45%; text-align:center;">
<img src="assets/images/AfterFlip.png" alt="After Edge Flip"
style="width:100%; height:300px; object-fit:cover; border-radius:8px;">
<figcaption style="color:#aaa; font-size:0.9rem; margin-top:0.5rem;">After Edge Flip</figcaption>
</figure>
</div>
<p>
I then added edge collapse and triangulation tools, which allowed simplification and
reorganization of faces. These operations formed the foundation for more advanced mesh
modifications.
</p>
<div style="display:flex; justify-content:center; gap:30px; flex-wrap:wrap; margin:20px 0;">
<!-- Before Collapse -->
<figure style="flex:0 0 45%; text-align:center;">
<img src="assets/images/BeforeCollapse.png" alt="Before Edge Collapse"
style="width:100%; height:300px; object-fit:cover; border-radius:8px;">
<figcaption style="color:#aaa; font-size:0.9rem; margin-top:0.5rem;">Before Edge Collapse</figcaption>
</figure>
<!-- After Collapse -->
<figure style="flex:0 0 45%; text-align:center;">
<img src="assets/images/AfterCollapse.png" alt="After Edge Collapse"
style="width:100%; height:300px; object-fit:cover; border-radius:8px;">
<figcaption style="color:#aaa; font-size:0.9rem; margin-top:0.5rem;">After Edge Collapse</figcaption>
</figure>
</div>
<p>
Building on the foundational mesh operations from Assignment 2, I implemented Loop subdivision, an approximating subdivision scheme
specifically designed for triangle meshes. Unlike linear and Catmull-Clark subdivision, Loop subdivision required using local mesh operations—edge
splits and flips—to achieve smooth surface refinement.
</p>
<br>
<p>
A critical implementation detail was computing all new vertex positions before modifying any connectivity. I stored these in temporary data
structures for new vertex and edge positions to prevent averaging already-averaged values, which would produce incorrect results. The implementation successfully produces
smooth approximations of the original mesh geometry. Each iteration quadruples the triangle count while progressively smoothing sharp features, converging toward a limit surface
that faithfully represents the coarse input with enhanced detail and smoothness.
</p>
<div style="display:flex; justify-content:center; gap:30px; flex-wrap:wrap; margin:20px 0;">
<figure style="flex:0 0 100%; text-align:center;">
<img src="assets/images/LoopSubdivisionShowcase.png" alt="Loop Subdivision"
style="width:100%; height:100%; object-fit:contain; border-radius:8px;">
<figcaption style="color:#aaa; font-size:0.9rem; margin-top:0.5rem;">Loop Subdivision Showcase </figcaption>
</figure>
</div>
<br>
<h3> Assignment 3: Pathtracing</h3>
<p>
Path tracing follows light as it bounces off multiple surfaces before reaching the camera, enabling global illumination
effects like color bleeding, soft shadows, and realistic reflections. This involved implementing both material models and
acceleration structures to make rendering practical.
</p>
<br>
<h4> Material Models & BSDF Implementation </h4>
<p>
I began by implementing the Lambertian material, which models diffuse surfaces that scatter
light equally in all directions. The implementation required three key functions: scatter to randomly sample
outgoing light directions, evaluate to compute the ratio of outgoing to incoming radiance, and pdf to calculate the probability
density function for those samples.
A critical detail was handling the cosine term in the rendering equation. Traditional BSDFs operate on the ratio of
radiance to irradiance, but Scotty3D's BSDFs work purely with radiance, requiring careful scaling. I used cosine-weighted
hemisphere sampling to importance sample directions, which naturally biases samples toward directions that contribute more to the final result
</p>
<br>
<h4> Direct and Indirect Lighting </h4>
<p>
Path tracing separates lighting into direct and indirect components. Direct lighting comes from light sources without any bounces, while indirect lighting accounts for light that bounced off at least one surface before reaching the shading point.
For indirect lighting, I sample a random direction from the BSDF, trace a ray in that direction recursively, and accumulate the incoming light scaled by the BSDF attenuation. The recursion depth must be limited to prevent infinite bounces. For direct lighting, I used the same sampling approach but with depth set to zero to capture only the first intersection.
While it might seem redundant to separate these components, doing so enables more sophisticated direct light sampling strategies that significantly reduce noise in the final render.
</p>
<br>
<div style="display:flex; justify-content:center; gap:30px; flex-wrap:wrap; margin:20px 0;">
<figure style="flex:0 0 100%; text-align:center;">
<img src="assets/images/pathtracer_showcase.png" alt="Loop Subdivision"
style="width:100%; height:100%; object-fit:contain; border-radius:8px;">
<figcaption style="color:#aaa; font-size:0.9rem; margin-top:0.5rem;">Pathtracer Showcase </figcaption>
</figure>
</div>
<br>
<h4> BVH Acceleration Structure </h4>
<p>
To make path tracing practical for complex scenes, I implemented a Bounding Volume Hierarchy (BVH) that dramatically accelerates ray-scene intersection tests. Without a BVH, every ray must test intersection against every primitive in the scene which becomes expensive for detailed models.
The BVH organizes scene primitives into a tree structure where each node stores a bounding box that encloses all primitives in its subtree. I implemented the structure as an implicit tree stored in a vector, similar to heap data structures. Construction uses the Surface Area Heuristic to determine optimal split positions, balancing the tree for efficient traversal.
Key implementation details included proper bounding box intersection tests and carefully reordering primitives during construction so that each node's start and size fields correctly index into the primitive array. The BVH reduces intersection tests from O(n) to O(log n) on average, making complex scenes renderable in reasonable time
</p>
</section>
<br>
<div style="display:flex; justify-content:center; gap:30px; flex-wrap:wrap; margin:20px 0;">
<figure style="flex:0 0 100%; text-align:center;">
<img src="assets/images/bvh_showcase.png" alt="Loop Subdivision"
style="width:100%; height:100%; object-fit:contain; border-radius:8px;">
<figcaption style="color:#aaa; font-size:0.9rem; margin-top:0.5rem;">BVH showcase </figcaption>
</figure>
</div>
<br>
<h3>Assignment 4: Animation</h3>
<p>
The fourth assignment focused on animating 3D characters through skeletal systems and deformation techniques.
I implemented the complete animation pipeline from spline interpolation to skinning, enabling smooth character movement
and realistic deformation.
</p>
<br>
<h4>Spline Interpolation</h4>
<p>
I began by implementing Catmull-Rom spline interpolation for smooth animation curves. Unlike linear interpolation,
splines create smooth transitions between keyframes by computing cubic polynomial segments that pass through control points.
The implementation required careful handling of tangent computation at each keyframe, using surrounding points to determine
the curve's velocity and ensuring C1 continuity across segments.
</p>
<br>
<div style="display:flex; justify-content:center; gap:30px; flex-wrap:wrap; margin:20px 0;">
<figure style="flex:0 0 100%; text-align:center;">
<img src="assets/images/spline_showcase.png" alt="Loop Subdivision"
style="width:100%; height:100%; object-fit:contain; border-radius:8px;">
<figcaption style="color:#aaa; font-size:0.9rem; margin-top:0.5rem;">Spline showcase </figcaption>
</figure>
</div>
<br>
<h4>Forward and Inverse Kinematics</h4>
<p>
The skeletal animation system required both forward kinematics (FK) and inverse kinematics (IK). For FK, I implemented
hierarchical transformation matrices that propagate from parent bones to children, allowing animators to pose characters
by directly rotating joints. The bind pose represents the rest configuration, while the current pose applies bone rotations
to achieve the desired character position.
</p>
<p>
For IK, I implemented gradient descent optimization that automatically computes joint angles to reach target positions.
This involved calculating the gradient of the squared distance function with respect to each bone's pose parameters,
then iteratively adjusting rotations to minimize the error. IK is essential for animations like foot placement or hand
reaching, where the end effector position is known but joint angles must be computed.
</p>
<br>
<h4>Linear Blend Skinning</h4>
<p>
The final component was linear blend skinning (LBS), which deforms mesh vertices based on skeletal motion. I first
implemented automatic weight assignment by computing each vertex's distance to bone capsules in the bind pose. Vertices
closer to a bone receive higher weights, with all weights normalized to sum to one.
</p>
<p>
The skinning algorithm then transforms each vertex by a weighted combination of bone transformations. For each bone
influencing a vertex, I computed the bind-to-current transformation matrix and blended them according to the vertex's
weights. A critical detail was transforming normals using the inverse transpose of the blended matrix to maintain
correct lighting after deformation.
</p>
<p>
Key implementation challenges included working entirely in skeleton-local space (avoiding scaling issues), efficiently
pre-computing bone positions to avoid redundant hierarchy traversals, and properly handling vertices with no bone weights
(which remain stationary). The result is smooth, realistic character deformation that follows skeletal motion while
preserving mesh volume and avoiding artifacts.
</p>
<br>
<div class="video-container">
<iframe
width="560"
height="315"
src="https://www.youtube.com/embed/v03U2UqRTOE"
title="Final Submission"
frameborder="0"
allowfullscreen>
</iframe>
</div>
</main>
<!-- Sticky Footer -->
<footer>
<div class="footer-icons">
<a href="mailto:joselima@andrew.cmu.edu" aria-label="Email">
<img src="assets/icons/email.svg" alt="Email Icon" class="email"/>
</a>
<a href="https://www.linkedin.com/in/jose-l-b4a2132a8/" target="_blank" rel="noopener noreferrer" aria-label="LinkedIn">
<img src="assets/icons/linkedin.svg" alt="LinkedIn Icon" class="linkedin" />
</a>
<a href="https://github.com/josecmu27" target="_blank" rel="noopener noreferrer" aria-label="Resume">
<img src="assets/icons/github.svg" alt="Github Icon" class = "linkedin"/>
</a>
<a href="joselima_resume.pdf" target="_blank" rel="noopener noreferrer" aria-label="Resume">
<img src="assets/icons/resume.svg" alt="Resume Icon" class = "resume"/>
</a>
</div>
</footer>
</body>
</html>