diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 0000000..e7ca359
Binary files /dev/null and b/.DS_Store differ
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..910f44f
--- /dev/null
+++ b/README.md
@@ -0,0 +1,11 @@
+# CS184/284A Homework Webpage Repo
+
+The goal of this repo is to provide a template from which students can host CS184/284A homework writeups.
+
+## Enabling Github Pages
+
+To enable Github pages, go to the 'Settings' tab then click on 'Pages'. Under 'Build and Deployment' -> 'Branch', make sure that the branch is set to 'master' and the folder is set to 'root'. If these settings are correct, you should see a message saying "Your site is live at [website url]" at the top of the 'Pages' page, and navigating to the github page link should render index.html.
+
+## Adding Homework Webpages
+
+There are 4 folders, one for each homework. Each contains an index.html file. When the links from the mainpage are clicked, these files will be loaded, so edit these to add your homework webpages.
diff --git a/_config.yml b/_config.yml
new file mode 100644
index 0000000..c419263
--- /dev/null
+++ b/_config.yml
@@ -0,0 +1 @@
+theme: jekyll-theme-cayman
\ No newline at end of file
diff --git a/final project/Milestone_Deliverables.png b/final project/Milestone_Deliverables.png
new file mode 100644
index 0000000..7928f7c
Binary files /dev/null and b/final project/Milestone_Deliverables.png differ
diff --git a/final project/Milestone_Slide_1.jpg b/final project/Milestone_Slide_1.jpg
new file mode 100644
index 0000000..17c4af2
Binary files /dev/null and b/final project/Milestone_Slide_1.jpg differ
diff --git a/final project/Milestone_Slide_2.jpg b/final project/Milestone_Slide_2.jpg
new file mode 100644
index 0000000..5aacb4e
Binary files /dev/null and b/final project/Milestone_Slide_2.jpg differ
diff --git a/final project/Milestone_Slide_3.jpg b/final project/Milestone_Slide_3.jpg
new file mode 100644
index 0000000..ad9bc84
Binary files /dev/null and b/final project/Milestone_Slide_3.jpg differ
diff --git a/final project/Milestone_Video.mkv b/final project/Milestone_Video.mkv
new file mode 100644
index 0000000..3080ae5
Binary files /dev/null and b/final project/Milestone_Video.mkv differ
diff --git a/final project/Milestone_Video.mp4 b/final project/Milestone_Video.mp4
new file mode 100644
index 0000000..b648204
Binary files /dev/null and b/final project/Milestone_Video.mp4 differ
diff --git a/final project/index.html b/final project/index.html
new file mode 100644
index 0000000..a6fe717
--- /dev/null
+++ b/final project/index.html
@@ -0,0 +1,236 @@
+
+
+ For this project, we will develop an add-on for Blender that allows
+ users to procedurally generate furniture of four different kinds:
+ dressers, tables, chairs, and beds. Both the geometry and texture data
+ of each furniture will be different each time the addon is used,
+ allowing for a wide variety of unique furniture to be created.
+
+
+
+
+
Problem Description
+
+ Building multiple different shapes of furniture with realistic, detailed
+ texture takes a long time as it requires complex modeling skills for
+ each individual object. As a result, it takes too much time when
+ modeling a scene that involves a ton of different objects, which can
+ cause potential problems in the workflow when it comes to building a
+ massive project within a tight deadline. To avoid such problems caused
+ by this time-consuming modeling process, speeding up the development
+ process is necessary, which can be achieved by implementing an add-on
+ for Blender that procedurally generated furniture and texture.
+
+
+
+
+
Goals and Deliverables
+
Goals:
+
+
Learn how to use and code in blender.
+
Build and render furniture needed for a bedroom.
+
+ Adjust the settings so that it changes the textures and geometries for
+ furniture.
+
+
+ Deliver the code in Python for the “add-on” function in Blender that
+ is able to build and render all the furniture (Dresser, Table, Chair
+ and Bed), and then change the geometry and textures.
+
+
+
+
Deliverables:
+
+ An available add-on that is able to randomly generate the whole
+ settings of a simulated bedroom including furniture and their
+ geometries and textures.
+
+
+
+
+
+
Schedule
+
Week 1: April 2 - 9
+
+
Everyone downloads Blender.
+
Everyone familiarizes themselves with Blender.
+
+ Everyone researches the Blender API to understand how to write code
+ for Blender.
+
+
We set up a GitHub for the project.
+
+
Week 2: April 9 - 16
+
+
Meet to discuss the structure of our code.
+
Write texture generation code.
+
Wood (Miller)
+
Plastic (Eugene)
+
Metal (Darren)
+
Cloth (Jiayi)
+
+
Week 3: April 16 - 23
+
+
Finalize texture generation code.
+
Start furniture generation code (if you have time).
+
Dresser (Miller)
+
Table (Eugene)
+
Chair (Darren)
+
Bed (Jiayi)
+
+
+
Week 4: April 23 - 30
+
+
Write + finish up our furniture generation code.
+
+
Week 5: April 30 - May 1
+
+
Prepare the final presentation!
+
+ Any last-minute work to put the addon together + make it available
+ online.
+
+ For this project, we will develop an add-on for Blender that allows
+ users to procedurally generate furniture of four different kinds:
+ dressers, tables, chairs, and beds. Both the geometry and texture data
+ of each furniture will be different each time the addon is used,
+ allowing for a wide variety of unique furniture to be created.
+
+
+
+
+
Problem Description
+
+ Building multiple different shapes of furniture with realistic, detailed
+ texture takes a long time as it requires complex modeling skills for
+ each individual object. As a result, it takes too much time when
+ modeling a scene that involves a ton of different objects, which can
+ cause potential problems in the workflow when it comes to building a
+ massive project within a tight deadline. To avoid such problems caused
+ by this time-consuming modeling process, speeding up the development
+ process is necessary, which can be achieved by implementing an add-on
+ for Blender that procedurally generated furniture and texture.
+
+
+
+
+
Updates
+
+
+ All team members have downloaded blender and learned how to use and
+ code in blender.
+
+
+ As schedule, we have finished setting up a repo and writing texture
+ generation codes for our assigned textures.
+
+ The assignment encompassed fundamental tasks such as drawing
+ single-color triangles using Barycentric Coordinates, optimizing
+ algorithms for efficiency, implementing supersampling for antialiasing,
+ and applying hierarchical transforms to create dynamic cubeman postures.
+ Additionally, we delved into advanced features like texture mapping with
+ both Nearest Neighbor Sampling and Bilinear Interpolation, and level
+ sampling with mipmaps for efficient rendering. The comparison of
+ performance metrics highlighted the trade-offs between pixel sampling
+ and level sampling, considering factors such as speed, memory usage, and
+ antialiasing quality.
+
+
+
+
+
Task 1: Drawing Single-Color Triangles (20 pts)
+
+
+
basic/test4.svg
+
+
Solution Walk Though
+
+ In this task, we implemented a naive algorithm for pixel sampling within
+ triangle shapes. Initially, we utilized the provided helper function
+ rasterize_line
+ to draw the edges of the triangles. Subsequently, we determined the
+ position of the smallest bounding rectangle around the triangle. We then
+ iterated through every pixel within that rectangle, applying the
+ Barycentric Coordinate method to ascertain whether each pixel resides
+ inside the triangle and should be colored.
+
+
Optimization
+
+
+
+
+
+
A
+
B
+
+
+
+ One way that we did to optimize the algorithm is to detect when we are
+ out of the triangle for the second time.
+
+
+ To be specific, we used the fact that when we iterating through the
+ circumscribed rectangle of the triangle, we will be out of the triangle
+ for at most twice. See point A and B in the graph above.
+ Point A
+ represents the first time we are out of the triangle, and
+ Point B
+ represents the second time we are out of the triangle. As we can see, we
+ are not going to be in the triangle for another time.
+
+
+ Therefore, we can stop the iteration when we are out of the triangle for
+ the second time. This will make sure that we don't need to iterate
+ through the whole circumscribed rectangle of the triangle.
+
+
Usage
+
+ Barycentric Coordinates are commonly used in computer graphics,
+ particularly in rendering techniques such as triangle interpolation and
+ texture mapping.
+
+
+
+
+
Task 2: Antialiasing by Supersampling (20 pts)
+
+
+
+
Solution Walk Though
+
+ This is one of the key parts of the whole homework coding part. In this
+ section, we are supersampling every one pixel of our buffer. As we can
+ see in the description diagram provided on the website (shown as above),
+ supersampling provides us a more precise result by checking on which
+ smaller pixel is in the area and which ones are not. Therefore, we can
+ combine them back to one pixel with color averaged from the smaller
+ pixels. This will make sure that we have a more precise result and the
+ edges of the triangle will be smoother.
+
+
Algorithm
+
+ The way we implemented it is to divide the pixel into
+ sample_rate
+ subpixels and then sample the color of the subpixels in
+ void RasterizerImp::rasterize_triangle
+ . We also need to update our algorithm for calculating Barycentric
+ Coordinates at the same time since our coordinates for
+ x0, y0, x1, ...., y3
+ have changed according to our sample_rate. The rest are quite the same
+ as in the previous task. We just iterate the whole rectangle and send
+ the colors to the
+ sample_buffer
+ .
+
+
+ We then average the color of the subpixels and assign it to the pixel in
+ RasterizerImp::resolve_to_framebuffer. To average the color, we just
+ simply add up the colors for every single subpixel for one original
+ pixel (
+ sample_rate
+ subpixels in total) and then divide it by the
+
+ sample_rate.
+ We then assign the result to the pixel in the framebuffer.
+
+
+ However, we also need to alter our
+ void RasterizerImp::fill_pixel
+ function for this one since our lines and points does not need to be
+ supersampled. We can simply alter this function by assigning the same
+ color to all
+ sample_rate
+ subpixels.
+
+
Result
+
+
+
+
Sample Rate = 1
+
+
+
+
Sample Rate = 4
+
+
+
+
+
+
Sample Rate = 9
+
+
+
+
Sample Rate = 16
+
+
+
+
+
+
Task 3: Transforms (10 pts)
+
+
+
+
+ created a cubeman in running posture by doing the following operations.
+
+
+
+ rotate the head and torso by a certain angle to make it more natural.
+
+
+ adjusted the angle and position of the arms and legs to add dynamic to
+ the body.
+
+
+
+
+
+
Task 4: Barycentric Coordinate (10 pts)
+
Description about Barycentric Coordinates
+
+ Barycentric coordinates are a set of three values (usually denoted as
+ alpha, beta, and gamma) that represent the weights of the vertices of a
+ triangle in a coordinate system. These coordinates are used to express
+ any point within the triangle as a combination of its vertices.
+
+
Solution Walk Though
+
+ The function
+ void rasterize_interpolated_color_triangle
+ is responsible for rasterizing a triangle and interpolating colors
+ across it using barycentric coordinates. The barycentric coordinates are
+ calculated for each pixel within the bounding box of the triangle, and
+ the corresponding color is interpolated based on these coordinates. The
+ code iterates through each pixel in the bounding box, and for each
+ pixel, it performs subpixel sampling. For each subpixel, it calculates
+ the barycentric coordinates using the function
+ baryCalc and
+ checks whether the point is inside the triangle by verifying if the
+ barycentric coordinates are within certain bounds. If the point is
+ inside the triangle, the color is interpolated using the barycentric
+ coordinates, and the result is stored in the
+ sample_buffer.
+ This process is repeated for all subpixels within each pixel of the
+ bounding box, effectively filling the entire triangle with interpolated
+ colors.
+
+
Result
+
+
+
basic/test7.svg
+
+
+
+
+
Task 5: "Pixel sampling" for texture mapping (15 pts)
+
+ Pixel sampling involves determining the color of a pixel in an image. In
+ texture mapping, I implemented it by mapping texture coordinates to
+ corresponding pixels and then sample on the mipmap of level 0. Following
+ are two ways to do pixel sampling:
+
+
+
+ Nearest Neighbor Sampling: When an image is resized or transformed,
+ each pixel in the new image is assigned the color value of the nearest
+ pixel in the original image. This method is quick and computationally
+ less intensive but can result in jagged edges and blocky artifacts,
+ especially when scaling up. The way we implemented it was to take the
+ float cordinates and round it to the nearest int cordinates.
+
+
+ Bilinear Interpolation: It considers the weighted average of the four
+ nearest pixels in the original image to determine the color of a pixel
+ in the new image. This results in smoother transitions and better
+ image quality during resizing or transformations. The way we
+ implemented this was to do interpolations between two reference points
+ and the current point. At first, we have four reference points
+ (vertices of the pixel the current point in in). We do interpolation
+ according to the graph below from the lecture.
+
From the above imagines, we can see the order of smoothness is:
+
Nearest-1 < Nearest-16 < Bilinear-1 < Bilinear-16
+
+ The differences between Nearest Neighbor Sampling and Bilinear
+ Interpolation becomes noticeable when there are significant variations
+ in texture magnification or reduction. This is because that Nearest
+ Neighbor Sampling assigns the nearest pixel color, causing blockiness
+ during size changes. While Bilinear Interpolation blends neighboring
+ pixels, offering smoother transitions.
+
+
+
+
+
+
+
+ Task 6: "Level sampling" with mipmaps for texture mapping (25 pts)
+
+
Description about Level Sampling
+
+ Level sampling is a technique used in computer graphics for efficient
+ rendering. It involves sampling pixels at different levels of detail,
+ starting with a coarse level and gradually refining to finer levels.
+ Level sampling relies on the principle that people don't perceive
+ resolution changes over distances. It optimizes performance by adjusting
+ image details based on viewing distance, saving computational resources.
+
+
Solution Walk Though
+
+ The way that we implemented level sampling invloves functions:
+ float Texture::get_level,
+ Color Texture::sample
+ and
+ rasterize_textured_triangle.
+
+
+
+ float Texture::get_level: We determine the level of mipmap of a certain point by using the
+ derivative vectors passed into the function.
+
+
+
+
+
+ Color Texture::sample: Use the helper function
+ float Texture::get_level
+ that we implemented before to get a certain level of mipmap. And then
+ decide which combination of sampling methods that we want to use
+ according to field
+ sp->lsm and
+ sp->psm.
+ Collect the sampled color and return it to the
+ void RasterizerImp::rasterize_textured_triangle
+ function.
+
+
+ void RasterizerImp::rasterize_textured_triangle: We reused a lot of the codes from Task 2. The difference is that we
+ did three Barycentric interpolations separately on point (x, y), (x+1,
+ y), (x, y+1) and then calculate the Vector parameters in sp by doing
+ dot product of
+ [alpha, beta, gamma]
+ with
+ [u0, u1, u2]
+ and
+ [v0, v1, v2]. Finally, we fill the framebuffer with the color returned from the
+ sample function that we implemented above.
+
+ In this assignment, you will explore topics on geometric modeling
+ covered in lecture. You will build Bezier curves and surfaces using de
+ Casteljau algorithm, manipulate triangle meshes represented by half-edge
+ data structure, and implement loop subdivision.
+
+
+
+
+
Section I: Bezier Curves and Surfaces
+
Part 1: Bezier Curves with 1D de Casteljau Subdivision (10 pts)
+
explanation of De Casteljau's algorithm
+
+ De Casteljau's algorithm is a method used to evaluate points on a Bézier
+ curve. Bézier curves are defined by a set of control points, and De
+ Casteljau's algorithm recursively divides the control points to
+ calculate intermediate points on the curve. The process involves
+ creating a set of linear interpolations between control points and
+ repeating this process until a single point is obtained—the evaluated
+ point on the Bézier curve.
+
+
Implementation
+
+ We followed the instruction on the spec: took in a
+ std::vector<Vector2D> controlPoints
+
+ of length n, applied the function \[ p_i' = \text{lerp}(p_i, p_{i+1}, t)
+ = (1 - t) * p_i + t * p_{i+1} \] to every point
+ <Vector2D> p_i and p_i_1, returning a new
+ <Vector2D> controlPoint curr. We will then push back "curr" to a new
+ std::vector <Vector2D> nextlevel
+
+ of length p - 1. Finally, we will return "nextlevel".
+
+
+
Screenshots
+
+ The curve with 6 control points are written in
+ bzc/curve3.bzc.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Part 2: Bezier Surfaces with Separable 1D de Casteljau (15 pts)
+
+
de Casteljau algorithm to Bezier surfaces
+
+ De Casteljau's algorithm, which is initially designed for Bézier curves,
+ can be extended to evaluate points on Bézier surfaces in a similar
+ recursive manner as in part1. Bézier surfaces are defined by a grid n*n
+ of control points, and the algorithm iteratively subdivides this grid to
+ calculate points on the surface.
+
+
Algorithm
+
+ std::vector<Vector3D>
+ BezierPatch::evaluateStep(std::vector<Vector3D> const &points,
+ double t): This function simulates one step of de Casteljau algorithm (same
+ functionality as part1), except that we are now taking in
+ std::vector<Vector3D> instead of
+ <Vector2D>.
+
+
+ Vector3D BezierPatch::evaluate1D(std::vector<Vector3D> const
+ &points, double t): calls
+ evaluateStep
+ one row of control points using a given parameter
+ t until we get
+ one final point for each row.(This must happen because each time we call
+ evaluateStep
+ on a vector of n points, the function will return a vector of n-1
+ points.)
+
+
+ Vector3D BezierPatch::evaluate(double u, double v)
+ In this function, we first loop through each rool of the N * N grid
+ controlPoints and call
+ evaluate1D
+ with the input
+ u on each
+ roll. We will get n returning points from the n loops and form a new
+ vector Final.
+ Finally, we call
+ evaluate1D
+ on
+ Final using
+ the input v.
+ (applying De Casteljau's algorithm across columns.)
+
+
+
Result
+
+
+
+
+
+
+
+
+
Section II: Triangle Meshes and Half-Edge Data Structure
+
Part 3: Area-Weighted Vertex Normals (10 pts)
+
Implementation
+
+ We first get the face the caller vertex belongs by calling
+ HalfedgeCIter he = halfedge();. We then iterate through all the other 5 triangles argound the caller
+ vertex by using the line
+ he = he->twin()->next();
+ (The halfedges he pointed to are shown in the following graph.) For each
+ triangle, we calculate the normal vector of it and add it to the
+ variable n. At
+ last, we return the normalized
+ n.
+
+
+
+
+
Result
+
+
+
+
+
+
+
+
Part 4: Edge Flip (15 pts)
+
Implementation
+
+ The function takes an iterator pointing to a halfedge as input. This
+ halfedge represents the edge that will be flipped.
+
+
Steps
+
+
+ Check for Boundary Edge: first checks if the input edge is a boundary
+ edge. If it is, flipping is not possible, so the function simply
+ returns the original edge iterator.
+
+
+ Get Halfedge: obtains iterators for several halfedges surrounding the
+ edge to be flipped, namely 3 halfedges for Left and 3 halfedges for
+ Right. These iterators are used to update connections between
+ halfedges after the flip.
+
+
+ Get Vertex: obtains iterators for the four vertices in the diagram
+ connected to the halfedges. These iterators are used to update the
+ vertices' halfedge pointers after the flip.
+
+
+ Get Face: obtains iterators for the two faces, namely Left and Right,
+ that the two halfedges being flipped belong to. These iterators are
+ used to update the faces' halfedge pointers after the flip.
+
+
+ Update Halfedge Neighbors (via
+ setNeighbors()): updates the neighbor pointers of the four halfedges involved in
+ the flip. This step reconfigures the connections between halfedges to
+ reflect the flipped edge.
+
+
+ Update Halfedge Next Pointers: updates the "next" pointers of two
+ halfedges to reverse their order in the counter-clockwise direction
+ around their respective faces.
+
+
+ Update Vertex Halfedge Pointers: updates the "halfedge" pointers of
+ the four vertices involved in the flip to point to their new
+ corresponding halfedges after the flip.
+
+
+ Update Face Halfedge Pointers: updates the "halfedge" pointers of the
+ two faces involved in the flip to point to their new starting
+ halfedges after the flip.
+
+
+ Return Flipped Edge: The function returns the iterator pointing to the
+ original edge, which now represents the flipped edge.
+
+
+
Debugging
+
+ We used the diagram to help us understand the connections between the 4
+ halfedges and 4 vertices involved in the flip. We also used the diagram
+ to help us understand the connections between the 2 faces involved in
+ the flip.
+
+
+
+
+
Result
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Task 5: Edge Split (15 pts)
+
Steps
+
+ Please refer to the diagram below for the notations of the vertices,
+ halfedges and faces as we have created new ones.
+
+
+ For your reference, vertices starting with "M" means "from the
+ Midpoint", "U" means "from the Upper face", "D" means "from the Down
+ face", "L" means "from the Left face", "R" means "from the Right face".
+
+
+
+
+
+
+ Create New Mesh Elements: The function first creates several new
+ elements to be inserted into the mesh during the split:
+
+
+ A new vertex ("MID") to represent the midpoint of the split edge.
+
+
+ Three new edges ("MD", "MB", "MA") to form the new edges after the
+ split.
+
+
+ Six new halfedges ("UR3", "DR3", "DR0", "DL0", "DL3", "UL3") to
+ connect the new vertex and edges.
+
+
+ Two new faces ("UP", "DOWN") to fill the gaps created by the
+ split.
+
+
+
+
+ Get Iterators for Existing Elements: The function obtains iterators
+ for existing halfedges, faces, and vertices surrounding the edge to be
+ split. These iterators are used to update connections after the split.
+
+
+ Position the New Vertex The position of the new vertex ("MID") is set
+ to the average of the positions of the two original vertices connected
+ by the edge.
+
+
+ Set Initial Halfedge Pointers: The "halfedge" pointer of the new
+ vertex ("MID") is set to point to one of the original halfedges
+ ("L0_OLD"). The "halfedge" pointer of the original vertex's vertex is
+ updated to point to a new halfedge on the opposite face ("R1_OLD").
+
+
+ Set Face Halfedge Pointers: The "halfedge" pointers of the new and
+ existing faces are updated to point to appropriate halfedges, ensuring
+ correct face-vertex relationships.
+
+
+ Set Edge Halfedge Pointers: The "halfedge" pointers of the new edges
+ are set to point to their corresponding halfedges.
+
+
+ Update Existing Halfedge Neighbors: The neighbor pointers of the
+ existing halfedges are modified to accommodate the new vertex and
+ edges, maintaining mesh connectivity.
+
+
+ Set New Halfedge Neighbors: The neighbor pointers of the new halfedges
+ are set to correctly connect them to the existing mesh elements,
+ forming the new edges and faces.
+
+
+ Return the New Vertex: The function returns an iterator pointing to
+ the newly inserted vertex ("MID").
+
+
+
Result
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Task 6: Loop Subdivision for Mesh Upsampling (25 pts)
+
Steps
+
+
+
Generating newPosition for all old vertices
+ Loop through every vertex in the mesh and use the position update
+ function for old vertex
+ (1 - n * u) * original_position + u *
+ original_neighbor_position_sum
+ where
+ original_position
+ is the current vertex's position and
+ original_neighbor_position_sum
+ is the sum of the positions of all neighbor vertices of the current
+ vertex. We resued our code from Part3 to get all the neighbor
+ vertices. After we get the position, we put it into
+ v->newPosition.
+
+
+
Generating newPosition for all new vertices
+ Loop through every edge in the mesh and use the position update
+ function for new vertex
+ 3/8 * (A + B) + 1/8 * (C + D)
+ where
+ A, B and
+ C, D and not
+ neighbours of each other. We will be storing new positions of new
+ vertex in
+ e->newPosition. This works because after we split, each edge will have a new vertex
+ on it, so that we can get the new position of the new vertex by first
+ getting the edge that the new vertex is on and then get the previously
+ stored newPosition value.
+
+
+
Spliting each edge
+ Loop through each edge of the mesh and call the
+ splitEdge
+ function on one edge if
+ !(e->isNew)
+ and the two vertices at the end of e are not new. Then we set the
+ isNew
+ indicator of the two subEdge created by spliting
+ e as false
+ and the
+ isNew
+ indicator of the other two newly created edges by split as true. Set
+ the
+ isNew
+ indicator of the returned vertex by
+ splitEdge
+ function as true. Finally, we set the
+ newPosition
+ field of the returned vertex as
+ e->newPosition.
+
+
+
Fliping edges
+ Loop through each edge of the mesh and check if
+ e->isNew is
+ true and if the
+ isNew field
+ of the two vertices at the end of e are not equal (one new and one
+ old). If yes, flip the edge.
+
+
+
Setting new positions
+ Loop through each vertex of the mesh and update
+ v->position = v->newPosition
+ only if it is an old vertex. Then change
+ v->isNew = false.
+
+
+
Interesting Implementation and Debugging
+
+ For debugging, we did not really use any helper functions. We just used
+ printing messages and drawing down how the mesh acts as we walk through
+ our code. For Implementation, we were struggling with making sure we are
+ only fliping "newly created edges with one new vertex and one old
+ vertex". Before the current way, we tried to add a bool field to
+ EdgeIter called
+ splited. With
+ this field, we can set
+ isNew of all
+ edges around the new vertex as true so that in the split interation, we
+ only check if
+ e->isNew == false. While in the flip interation, we check if
+ e->splited == true
+ and if the edge has one new vertex and one old vertex.
+
+
Observations
+
+ After Subdividing, we noticed that the sharp edges and corners got
+ rounded in render view. We tried pre-spiliting but it creates some caves
+ on the smooth surface.
+
+ In this project, we developed a pathtracer with advanced features. In
+ Part 1, we focused on ray generation and scene intersection using
+ techniques like perspective projection and the Moller Trumbore algorithm
+ for triangle intersection. Part 2 introduced a Bounding Volume Hierarchy
+ (BVH) to accelerate ray tracing, reducing rendering times for complex
+ scenes. We covered steps such as computing bounding boxes, choosing
+ splitting axes, and recursively constructing the BVH. In Part 3, we
+ enhanced the pathtracer with direct illumination, comparing uniform
+ hemisphere sampling with importance sampling. The latter provided
+ smoother results in light-surface interactions. Part 4 explored global
+ illumination, addressing indirect lighting, maximum ray depth, Russian
+ Roulette rendering, and sample-per-pixel rates. Screenshots illustrated
+ the impact of settings on visual richness. Part 5 delved into adaptive
+ sampling, dynamically adjusting samples based on pixel color variance.
+ Confidence intervals and early termination for low-variance pixels
+ ensured computational efficiency without compromising quality. Our
+ project showcased a comprehensive pathtracer with optimizations,
+ demonstrating our grasp of computer graphics principles and effective
+ application in a complex rendering environment.
+
+
+
+
+
Part 1: Ray Generation and Scene Intersection
+
Generating Rays and Primitive Intersection
+
+ We determine the original point's position and project it onto the
+ screen. To find
+ new_x and
+ new_y, we
+ center the original rectangle screen defined by (0, 0) and (1, 1) at (0,
+ 0), resulting in (x - 0.5, y - 0.5). The relative positions of
+ x and
+ y in the
+ original screen remain the same as
+ new_x and
+ new_y. This
+ leads to the equations:
+
+ \[\frac{(x - 0.5)}{1} = \frac{\text{new_x}}{(2 \cdot
+ \tan(\text{radians(hFov) * .5}))}\] \[\frac{(y - 0.5)}{1} =
+ \frac{\text{new_y}}{(2 \cdot \tan(\text{radians(vFov) * .5}))}\]
+
+ We obtain
+ Vector3D ray_vector = Vector3D(new_x, new_y, -1.0). After obtaining the position of the projected point, we calculate the
+ direction vector of
+ result_ray
+ using matrix multiplication
+ c2w * ray_vector. Finally, we set the visible boundary for this ray between nClip and
+ fClip, which we will update later.
+
+
Process walkthrough
+
+ Ray generation begins with casting rays from the virtual camera into the
+ scene. Each ray is defined by its origin (the camera's position) and a
+ direction (pointing through a pixel on the camera plane). These rays
+ traverse the scene, interacting with objects along their directions. The
+ primitive intersection stage involves determining if a ray intersects
+ with any geometric primitives(sphere, triangle, etc.) in the scene. This
+ process employs the function
+ Triangle::intersect
+ or
+ Sphere::intersect. When an intersection is detected, information about the point of
+ intersection, such as its position, surface properties, and material
+ characteristics, will be upadted in the struct
+ Intersection* isect.
+
+
+
triangle intersection algorithm
+
+ We used the Moller Trumbore Algorithm that we have discussed in lecture.
+ After following the steps and get the vector containing [t, alpha,
+ beta], we first see if t is between
+ r.min_t and
+ r.max_t and if
+ alpha and beta are within [0, 1]. If any of the condition fails, the
+ intersection is not suppose to happen and we return false. If both
+ conditions are met, we update the intersection information to
+ Intersection* isect, including the filed t, primitive, bsdf and n(calculated by doing
+ barycentric interpolation with the current three norms and the alpha,
+ beta, gamma values that we calculated above.) We also updated ray.max_t
+ to t.
+
+
Screenshots
+
+
+
+
+
+
+
+
+
+
+
+
Part 2: Bounding Volume Hierarchy
+
BVH construction algorithm
+
Following are our steps for constructing BVH
+
+
+ Compute the Bounding Box (bbox): We start by computing the
+ bounding box that encloses all the primitives between
+ start and
+ end. The
+ bounding box is computed by iteratively expanding it to include the
+ bounding boxes of individual primitives using function
+ bbox.expand.
+
+
+ Choose Splitting Axis: We then choose the splitting axis based
+ on the maximum extent of the bounding box. The axis is selected to be
+ the one along which the bounding box has the maximum size. This
+ heuristic helps achieve a more balanced partitioning.
+
+
+ Check Leaf Node Condition: If the number of primitives in the
+ current range is less than or equal to
+ max_leaf_size, the current node becomes a leaf node. We just create a leaf node
+ and set its start and end field with the input
+ start and
+ end.
+
+
+ Partition Primitives: If the number of primitives exceeds
+ max_leaf_size, we partition the primitives along the chosen axis. We used the
+ function
+ nth_element
+ to partially sort the primitives based on their centroids along the
+ selected axis. This effectively places the median primitive at the
+ position that separates the primitives into two groups.
+
+
+ Construction: Then, we recursively constructs the left and
+ right child nodes of the current node, each covering a subset of the
+ primitives. The left child covers the range [start, start + size/2),
+ and the right child covers the range [start + size/2, end]. Finally,
+ we return the current node.
+
+
+
screenshots of large images with normal shading
+
+
+
+
+
+
+
+
+
+
Render Time Comparison Analysis
+
+ Before implementing BVH acceleration, the rendering time for cow and the
+ other .dae file shown in the screenshots below were close to a minute.
+ After implementing BVH, the rendering time for cow is around 1 second.
+ And all the other large .dae files(the ones above) all takes less than
+ 1.5 seconds to complete. The speed-up is much faster, we think this is
+ because once a ray does not intersect with a node's bbox, we do not test
+ for intersection between the ray and the primitives contained by the
+ node, which saves us a lot of computation.
+
+
+
+
+
Part 3: Direct Illumination
+
+ Walkthough for
+ Vector3D PathTracer::estimate_direct_lighting_hemisphere
+
+
+
+ Sampling Loop for Direct Lighting: We start a num_samples times
+ loop to sample the hemisphere around the hit point, considering the
+ lights in the scene.
+
+
+ Sample Light: Within the loop, we get the sampled light by
+ calling
+ isect.bsdf->sample_f. This function returns the sampled reflected direction wj and the
+ corresponding probability density function (pdf). Then, we multiply
+ the direction vector by
+ o2w to get
+ the transformed vector and normalize it. Then, we construct the
+ sampleray using hit_p as origin and the normalized vector as direction
+ with its min_t set to EPS_F and max_t set to INF_D.
+
+
+ Check for Intersection: If sampleray intersects with the scene,
+ we calculate the contribution for L_out by this sampleray using the
+ function
+ lightIsect.bsdf->get_emission() * f * abs_cos_theta(wj) / pdf
+ and add it to L_out.
+
+
+ Normalizing Output: Finally, we return the light estimator
+ equals to L_out / num_samples.
+
+
+
+
+ Walkthough for
+ Vector3D PathTracer::estimate_direct_lighting_importance
+
+
+
+ Calculate the hit point hit_p by extending the ray to the
+ intersection distance isect.t. Determine the direction of
+ the ray coming from the hit point (w_out) by transforming
+ the negative ray direction from world to object space.
+
+
+
+ Initialize variables for the loop over lights, determining the number
+ of samples based on whether the light is a delta light. For delta
+ lights, take only one sample; otherwise, use the variable
+ ns_area_light.
+
+
+
+ Inside the loop over light sources, sample the light using the
+ sample_L function to obtain the direction
+ wj towards the light, the distance to the light
+ distToLight, and the probability density function
+ pdf. Transform wj to object space and
+ normalize it.
+
+
+
+ Create a shadow ray from the hit point to the sampled light direction,
+ setting its minimum and maximum t-values to avoid self-intersection.
+ Perform a shadow ray intersection test with the BVH, checking for
+ obstructions between the hit point and the light source. Skip the
+ sample if an intersection occurs within the valid range.
+
+
+
+ Calculate the contribution of this light sample to the overall
+ lighting at the hit point. This involves evaluating the emission from
+ the light, the bidirectional scattering distribution function (BSDF)
+ using the f function, the cosine term, and dividing by
+ the probability density function. Accumulate these contributions for
+ all samples and lights.
+
+
+
+ The result L_out represents the estimated direct lighting
+ at the intersection point, considering importance sampling from light
+ sources. Return this result, taking into account the number of samples
+ used for each light source.
+
+
+
+
+ Comparison and Analysis of uniform hemisphere sampling and lighting
+ sampling
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Uniform hemisphere sampling provides an unbiased, yet more visually
+ noisy representation, especially in regions where there are intricate
+ interactions between light and surfaces. In contrast, light sampling, by
+ strategically sampling directions based on the light source, tends to
+ produce smoother results with reduced noise levels in areas affected by
+ soft shadows.
+
+
+
+ Comparison Between Noise Levels in Soft Shadows Using Lighting Sampling
+
+
+
+
+
+
+
+
+
+
+
+
+ As the number of light rays (l) increases in the rendering process with
+ light sampling, the transitions of shadows become smoother and the
+ presence of noisy pixels diminishes. This improvement is attributed to
+ the increased number of samples per pixel, leading to more accurate and
+ refined estimations of soft shadows, resulting in a visually smoother
+ and less noisy appearance in the illuminated regions of the scene.
+
+
+
+
+
Part 4: Global Illumination
+
Implementation
+
+
+ Get Vertex: obtains iterators for the four vertices in the diagram
+ connected to the halfedges. These iterators are used to update the
+ vertices' halfedge pointers after the flip.
+
+
+ Get Face: obtains iterators for the two faces, namely Left and Right,
+ that the two halfedges being flipped belong to. These iterators are
+ used to update the faces' halfedge pointers after the flip.
+
+
+ Update Halfedge Neighbors (via
+ setNeighbors()): updates the neighbor pointers of the four halfedges involved in
+ the flip. This step reconfigures the connections between halfedges to
+ reflect the flipped edge.
+
+
+ Update Halfedge Next Pointers: updates the "next" pointers of two
+ halfedges to reverse their order in the counter-clockwise direction
+ around their respective faces.
+
+
+ Update Vertex Halfedge Pointers: updates the "halfedge" pointers of
+ the four vertices involved in the flip to point to their new
+ corresponding halfedges after the flip.
+
+
+
+
Screenshots for global (direct and indirect) illumination
+
+
+
+
+
+
+
+
+
+ Comparison between rendered views using only direct illumination or
+ indirect illumination
+
+
+
+
+
+
+
+
+
+ ScreenShots and Analysis for mth bounce of light for CBbunny.dae with
+ isAccumBounces=false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ The 2nd bounce represents light that bounces once off surfaces before
+ reaching the camera, and the 3rd bounce extends this process further. We
+ can see that as m gets highter, the rendered lights gets dimmer and and
+ smoother. This is because there are loss in light reflection using the
+ process according to the contiunous probability we we add in every
+ recursive call in
+ at_least_one_bounce_radiance
+
+
+
+ ScreenShots and Analysis for mth bounce of light for CBbunny.dae with
+ isAccumBounces = true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Higher max_ray_depth values result in more complex indirect lighting
+ effects, such as color bleeding, reflections, and global illumination.
+ These effects enhance the realism and visual richness of the rendered
+ image compared to rasterization, where indirect lighting is challenging
+ to achieve accurately.
+
+
+
ScreenShots for Russian Roulette rendering for CBbunny.dae
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Comparison of rendered views with various sample-per-pixel rates
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Task 5: Adaptive Sampling
+
Explanation of the Adaptive Sampling
+
+
+ Adaptive sampling dynamically adjusts the number of samples taken during
+ rendering based on the variance in pixel color. In the provided code,
+ after processing a batch of samples, the algorithm computes the mean and
+ variance of radiance values and calculates a confidence interval width.
+ If the interval width is below a specified tolerance relative to the
+ mean, the sampling loop breaks early, optimizing computational resources
+ by allocating more samples to pixels with higher uncertainty and fewer
+ samples to those with lower uncertainty.
+
+
Implementation of the Adaptive Sampling
+
+ Additional to our implementation from part1, we added the variables
+ s1 (sum of
+ xk)and
+ variance (sum
+ of xk{2}) Reuse the for loop that we had before, in each loop, we set xk
+ as the return value from
+ est_radiance_global_illumination.illum(), update s1 and s2. We also added a if statement checking if the number
+ of samples that we have sampled is a multiple of
+ samplesPerBatch, we check if 1.96 · √n
+ / σ < maxTolerance · mean. If false, the sample has not
+ converged and we will keep looping; if yes, the sample has converged and
+ we will break the loop. Finally, we update
+ sampleCountBuffer
+ at the corresponding index to be num_samples.
+
+
+
Result
+
+
+
+
+
+
blob.dae -s 2048 -l 1 -m 5
+
+
+
+
+
CBdragon.dae -s 2048 -l 1 -m 5
+
+
+
+
diff --git a/hw3/task1_CBspheres.png b/hw3/task1_CBspheres.png
new file mode 100644
index 0000000..9203deb
Binary files /dev/null and b/hw3/task1_CBspheres.png differ
diff --git a/hw3/task1_banana.png b/hw3/task1_banana.png
new file mode 100644
index 0000000..d22c222
Binary files /dev/null and b/hw3/task1_banana.png differ
diff --git a/hw3/task1_bunny.png b/hw3/task1_bunny.png
new file mode 100644
index 0000000..5004ad1
Binary files /dev/null and b/hw3/task1_bunny.png differ
diff --git a/hw3/task2_CBlucy.png b/hw3/task2_CBlucy.png
new file mode 100644
index 0000000..fd4622d
Binary files /dev/null and b/hw3/task2_CBlucy.png differ
diff --git a/hw3/task2_beast.png b/hw3/task2_beast.png
new file mode 100644
index 0000000..fff4a34
Binary files /dev/null and b/hw3/task2_beast.png differ
diff --git a/hw3/task2_cow.png b/hw3/task2_cow.png
new file mode 100644
index 0000000..cf60e09
Binary files /dev/null and b/hw3/task2_cow.png differ
diff --git a/hw3/task2_peter.png b/hw3/task2_peter.png
new file mode 100644
index 0000000..8527abc
Binary files /dev/null and b/hw3/task2_peter.png differ
diff --git a/hw3/task3_ bunny_1_1.png b/hw3/task3_ bunny_1_1.png
new file mode 100644
index 0000000..7cce399
Binary files /dev/null and b/hw3/task3_ bunny_1_1.png differ
diff --git a/hw3/task3_ bunny_1_16.png b/hw3/task3_ bunny_1_16.png
new file mode 100644
index 0000000..783b4c2
Binary files /dev/null and b/hw3/task3_ bunny_1_16.png differ
diff --git a/hw3/task3_ bunny_1_4.png b/hw3/task3_ bunny_1_4.png
new file mode 100644
index 0000000..ca86cbb
Binary files /dev/null and b/hw3/task3_ bunny_1_4.png differ
diff --git a/hw3/task3_ bunny_1_64.png b/hw3/task3_ bunny_1_64.png
new file mode 100644
index 0000000..65de964
Binary files /dev/null and b/hw3/task3_ bunny_1_64.png differ
diff --git a/hw3/task3_Cbgems_H.png b/hw3/task3_Cbgems_H.png
new file mode 100644
index 0000000..cdcee81
Binary files /dev/null and b/hw3/task3_Cbgems_H.png differ
diff --git a/hw3/task3_Cbgems_I.png b/hw3/task3_Cbgems_I.png
new file mode 100644
index 0000000..6ba49e6
Binary files /dev/null and b/hw3/task3_Cbgems_I.png differ
diff --git a/hw3/task3_bunny_H.png b/hw3/task3_bunny_H.png
new file mode 100644
index 0000000..8590e6e
Binary files /dev/null and b/hw3/task3_bunny_H.png differ
diff --git a/hw3/task3_bunny_I.png b/hw3/task3_bunny_I.png
new file mode 100644
index 0000000..7bcdca1
Binary files /dev/null and b/hw3/task3_bunny_I.png differ
diff --git a/hw3/task3_coil_H.png b/hw3/task3_coil_H.png
new file mode 100644
index 0000000..64ad432
Binary files /dev/null and b/hw3/task3_coil_H.png differ
diff --git a/hw3/task3_coil_I.png b/hw3/task3_coil_I.png
new file mode 100644
index 0000000..dbf9db6
Binary files /dev/null and b/hw3/task3_coil_I.png differ
diff --git a/hw3/task3_spheres_H.png b/hw3/task3_spheres_H.png
new file mode 100644
index 0000000..d3b60b3
Binary files /dev/null and b/hw3/task3_spheres_H.png differ
diff --git a/hw3/task3_spheres_I.png b/hw3/task3_spheres_I.png
new file mode 100644
index 0000000..23b8946
Binary files /dev/null and b/hw3/task3_spheres_I.png differ
diff --git a/hw3/task4_bounce_0.png b/hw3/task4_bounce_0.png
new file mode 100644
index 0000000..343ff0c
Binary files /dev/null and b/hw3/task4_bounce_0.png differ
diff --git a/hw3/task4_bounce_1.png b/hw3/task4_bounce_1.png
new file mode 100644
index 0000000..63eb76f
Binary files /dev/null and b/hw3/task4_bounce_1.png differ
diff --git a/hw3/task4_bounce_2.png b/hw3/task4_bounce_2.png
new file mode 100644
index 0000000..2eeec67
Binary files /dev/null and b/hw3/task4_bounce_2.png differ
diff --git a/hw3/task4_bounce_3.png b/hw3/task4_bounce_3.png
new file mode 100644
index 0000000..ed8224a
Binary files /dev/null and b/hw3/task4_bounce_3.png differ
diff --git a/hw3/task4_bounce_4.png b/hw3/task4_bounce_4.png
new file mode 100644
index 0000000..bfaaacb
Binary files /dev/null and b/hw3/task4_bounce_4.png differ
diff --git a/hw3/task4_bounce_5.png b/hw3/task4_bounce_5.png
new file mode 100644
index 0000000..6ee2878
Binary files /dev/null and b/hw3/task4_bounce_5.png differ
diff --git a/hw3/task4_direct_illumination.png b/hw3/task4_direct_illumination.png
new file mode 100644
index 0000000..96b50d7
Binary files /dev/null and b/hw3/task4_direct_illumination.png differ
diff --git a/hw3/task4_global_illumination.png b/hw3/task4_global_illumination.png
new file mode 100644
index 0000000..cbe74b6
Binary files /dev/null and b/hw3/task4_global_illumination.png differ
diff --git a/hw3/task4_global_illumination_1.png b/hw3/task4_global_illumination_1.png
new file mode 100644
index 0000000..27c827c
Binary files /dev/null and b/hw3/task4_global_illumination_1.png differ
diff --git a/hw3/task4_global_illumination_1_rate.png b/hw3/task4_global_illumination_1_rate.png
new file mode 100644
index 0000000..6216f66
Binary files /dev/null and b/hw3/task4_global_illumination_1_rate.png differ
diff --git a/hw3/task4_global_illumination_2.png b/hw3/task4_global_illumination_2.png
new file mode 100644
index 0000000..f8d229d
Binary files /dev/null and b/hw3/task4_global_illumination_2.png differ
diff --git a/hw3/task4_global_illumination_2_rate.png b/hw3/task4_global_illumination_2_rate.png
new file mode 100644
index 0000000..0b6dc98
Binary files /dev/null and b/hw3/task4_global_illumination_2_rate.png differ
diff --git a/hw3/task4_indirect_illumination.png b/hw3/task4_indirect_illumination.png
new file mode 100644
index 0000000..1153131
Binary files /dev/null and b/hw3/task4_indirect_illumination.png differ
diff --git a/hw3/task4_max_depth_0.png b/hw3/task4_max_depth_0.png
new file mode 100644
index 0000000..343ff0c
Binary files /dev/null and b/hw3/task4_max_depth_0.png differ
diff --git a/hw3/task4_max_depth_1.png b/hw3/task4_max_depth_1.png
new file mode 100644
index 0000000..4309a53
Binary files /dev/null and b/hw3/task4_max_depth_1.png differ
diff --git a/hw3/task4_max_depth_2.png b/hw3/task4_max_depth_2.png
new file mode 100644
index 0000000..92a453b
Binary files /dev/null and b/hw3/task4_max_depth_2.png differ
diff --git a/hw3/task4_max_depth_3.png b/hw3/task4_max_depth_3.png
new file mode 100644
index 0000000..904d83e
Binary files /dev/null and b/hw3/task4_max_depth_3.png differ
diff --git a/hw3/task4_max_depth_4.png b/hw3/task4_max_depth_4.png
new file mode 100644
index 0000000..ac5126f
Binary files /dev/null and b/hw3/task4_max_depth_4.png differ
diff --git a/hw3/task4_max_depth_5.png b/hw3/task4_max_depth_5.png
new file mode 100644
index 0000000..5efe2e5
Binary files /dev/null and b/hw3/task4_max_depth_5.png differ
diff --git a/hw3/task4_russian_roulette_0.png b/hw3/task4_russian_roulette_0.png
new file mode 100644
index 0000000..2a404de
Binary files /dev/null and b/hw3/task4_russian_roulette_0.png differ
diff --git a/hw3/task4_russian_roulette_1.png b/hw3/task4_russian_roulette_1.png
new file mode 100644
index 0000000..43cd129
Binary files /dev/null and b/hw3/task4_russian_roulette_1.png differ
diff --git a/hw3/task4_russian_roulette_100.png b/hw3/task4_russian_roulette_100.png
new file mode 100644
index 0000000..33022c5
Binary files /dev/null and b/hw3/task4_russian_roulette_100.png differ
diff --git a/hw3/task4_russian_roulette_2.png b/hw3/task4_russian_roulette_2.png
new file mode 100644
index 0000000..e763f92
Binary files /dev/null and b/hw3/task4_russian_roulette_2.png differ
diff --git a/hw3/task4_russian_roulette_3.png b/hw3/task4_russian_roulette_3.png
new file mode 100644
index 0000000..44f134d
Binary files /dev/null and b/hw3/task4_russian_roulette_3.png differ
diff --git a/hw3/task4_russian_roulette_4.png b/hw3/task4_russian_roulette_4.png
new file mode 100644
index 0000000..0dce1e3
Binary files /dev/null and b/hw3/task4_russian_roulette_4.png differ
diff --git a/hw3/task4_spp_1.png b/hw3/task4_spp_1.png
new file mode 100644
index 0000000..4d4967e
Binary files /dev/null and b/hw3/task4_spp_1.png differ
diff --git a/hw3/task4_spp_1024.png b/hw3/task4_spp_1024.png
new file mode 100644
index 0000000..d28a9c9
Binary files /dev/null and b/hw3/task4_spp_1024.png differ
diff --git a/hw3/task4_spp_16.png b/hw3/task4_spp_16.png
new file mode 100644
index 0000000..5977d0c
Binary files /dev/null and b/hw3/task4_spp_16.png differ
diff --git a/hw3/task4_spp_2.png b/hw3/task4_spp_2.png
new file mode 100644
index 0000000..67a67d7
Binary files /dev/null and b/hw3/task4_spp_2.png differ
diff --git a/hw3/task4_spp_4.png b/hw3/task4_spp_4.png
new file mode 100644
index 0000000..1c1f393
Binary files /dev/null and b/hw3/task4_spp_4.png differ
diff --git a/hw3/task4_spp_64.png b/hw3/task4_spp_64.png
new file mode 100644
index 0000000..fafd543
Binary files /dev/null and b/hw3/task4_spp_64.png differ
diff --git a/hw3/task4_spp_8.png b/hw3/task4_spp_8.png
new file mode 100644
index 0000000..9a04c51
Binary files /dev/null and b/hw3/task4_spp_8.png differ
diff --git a/hw3/task5_blob.png b/hw3/task5_blob.png
new file mode 100644
index 0000000..7458fb4
Binary files /dev/null and b/hw3/task5_blob.png differ
diff --git a/hw3/task5_blob_rate.png b/hw3/task5_blob_rate.png
new file mode 100644
index 0000000..dc599b2
Binary files /dev/null and b/hw3/task5_blob_rate.png differ
diff --git a/hw3/task5_dragon.png b/hw3/task5_dragon.png
new file mode 100644
index 0000000..023b816
Binary files /dev/null and b/hw3/task5_dragon.png differ
diff --git a/hw3/task5_dragon_rate.png b/hw3/task5_dragon_rate.png
new file mode 100644
index 0000000..89e0931
Binary files /dev/null and b/hw3/task5_dragon_rate.png differ
diff --git a/hw4/Part I-all.png b/hw4/Part I-all.png
new file mode 100644
index 0000000..0f60cf3
Binary files /dev/null and b/hw4/Part I-all.png differ
diff --git a/hw4/Part I-angle-1.png b/hw4/Part I-angle-1.png
new file mode 100644
index 0000000..0d1bb11
Binary files /dev/null and b/hw4/Part I-angle-1.png differ
diff --git a/hw4/Part I-angle-2.png b/hw4/Part I-angle-2.png
new file mode 100644
index 0000000..3c9a1d2
Binary files /dev/null and b/hw4/Part I-angle-2.png differ
diff --git a/hw4/Part I-angle-3.png b/hw4/Part I-angle-3.png
new file mode 100644
index 0000000..9d2e086
Binary files /dev/null and b/hw4/Part I-angle-3.png differ
diff --git a/hw4/Part I-angle-4.png b/hw4/Part I-angle-4.png
new file mode 100644
index 0000000..35173a7
Binary files /dev/null and b/hw4/Part I-angle-4.png differ
diff --git a/hw4/Part I-no-shearing.png b/hw4/Part I-no-shearing.png
new file mode 100644
index 0000000..90d4d01
Binary files /dev/null and b/hw4/Part I-no-shearing.png differ
diff --git a/hw4/Part I-only-shearing.png b/hw4/Part I-only-shearing.png
new file mode 100644
index 0000000..8139005
Binary files /dev/null and b/hw4/Part I-only-shearing.png differ
diff --git a/hw4/Part III-ks500.png b/hw4/Part III-ks500.png
new file mode 100644
index 0000000..5a17e46
Binary files /dev/null and b/hw4/Part III-ks500.png differ
diff --git a/hw4/Part III-ks5000.png b/hw4/Part III-ks5000.png
new file mode 100644
index 0000000..9f887fc
Binary files /dev/null and b/hw4/Part III-ks5000.png differ
diff --git a/hw4/Part III-ks50000.png b/hw4/Part III-ks50000.png
new file mode 100644
index 0000000..3aa1b7a
Binary files /dev/null and b/hw4/Part III-ks50000.png differ
diff --git a/hw4/Part III-plane.png b/hw4/Part III-plane.png
new file mode 100644
index 0000000..6933058
Binary files /dev/null and b/hw4/Part III-plane.png differ
diff --git a/hw4/Part IV-falling-1.png b/hw4/Part IV-falling-1.png
new file mode 100644
index 0000000..06218f0
Binary files /dev/null and b/hw4/Part IV-falling-1.png differ
diff --git a/hw4/Part IV-falling-2.png b/hw4/Part IV-falling-2.png
new file mode 100644
index 0000000..425adbc
Binary files /dev/null and b/hw4/Part IV-falling-2.png differ
diff --git a/hw4/Part IV-falling-3.png b/hw4/Part IV-falling-3.png
new file mode 100644
index 0000000..8b483a4
Binary files /dev/null and b/hw4/Part IV-falling-3.png differ
diff --git a/hw4/Part IV-falling-4.png b/hw4/Part IV-falling-4.png
new file mode 100644
index 0000000..39f794c
Binary files /dev/null and b/hw4/Part IV-falling-4.png differ
diff --git a/hw4/Part IV-falling-density40-1.png b/hw4/Part IV-falling-density40-1.png
new file mode 100644
index 0000000..de22047
Binary files /dev/null and b/hw4/Part IV-falling-density40-1.png differ
diff --git a/hw4/Part IV-falling-density40-2.png b/hw4/Part IV-falling-density40-2.png
new file mode 100644
index 0000000..ca534ac
Binary files /dev/null and b/hw4/Part IV-falling-density40-2.png differ
diff --git a/hw4/Part IV-falling-density40-3.png b/hw4/Part IV-falling-density40-3.png
new file mode 100644
index 0000000..395fb6f
Binary files /dev/null and b/hw4/Part IV-falling-density40-3.png differ
diff --git a/hw4/Part IV-falling-density40-4.png b/hw4/Part IV-falling-density40-4.png
new file mode 100644
index 0000000..e6b13cd
Binary files /dev/null and b/hw4/Part IV-falling-density40-4.png differ
diff --git a/hw4/Part IV-falling-density5-1.png b/hw4/Part IV-falling-density5-1.png
new file mode 100644
index 0000000..c2a792b
Binary files /dev/null and b/hw4/Part IV-falling-density5-1.png differ
diff --git a/hw4/Part IV-falling-density5-2.png b/hw4/Part IV-falling-density5-2.png
new file mode 100644
index 0000000..f10f169
Binary files /dev/null and b/hw4/Part IV-falling-density5-2.png differ
diff --git a/hw4/Part IV-falling-density5-3.png b/hw4/Part IV-falling-density5-3.png
new file mode 100644
index 0000000..477e84e
Binary files /dev/null and b/hw4/Part IV-falling-density5-3.png differ
diff --git a/hw4/Part IV-falling-density5-4.png b/hw4/Part IV-falling-density5-4.png
new file mode 100644
index 0000000..bfa37aa
Binary files /dev/null and b/hw4/Part IV-falling-density5-4.png differ
diff --git a/hw4/Part IV-falling-ks500-1.png b/hw4/Part IV-falling-ks500-1.png
new file mode 100644
index 0000000..d5f52d9
Binary files /dev/null and b/hw4/Part IV-falling-ks500-1.png differ
diff --git a/hw4/Part IV-falling-ks500-2.png b/hw4/Part IV-falling-ks500-2.png
new file mode 100644
index 0000000..253d649
Binary files /dev/null and b/hw4/Part IV-falling-ks500-2.png differ
diff --git a/hw4/Part IV-falling-ks500-3.png b/hw4/Part IV-falling-ks500-3.png
new file mode 100644
index 0000000..a011642
Binary files /dev/null and b/hw4/Part IV-falling-ks500-3.png differ
diff --git a/hw4/Part IV-falling-ks500-4.png b/hw4/Part IV-falling-ks500-4.png
new file mode 100644
index 0000000..d93665a
Binary files /dev/null and b/hw4/Part IV-falling-ks500-4.png differ
diff --git a/hw4/Part IV-falling-ks500-5.png b/hw4/Part IV-falling-ks500-5.png
new file mode 100644
index 0000000..30f0338
Binary files /dev/null and b/hw4/Part IV-falling-ks500-5.png differ
diff --git a/hw4/Part IV-falling-ks50000-1.png b/hw4/Part IV-falling-ks50000-1.png
new file mode 100644
index 0000000..139cf4c
Binary files /dev/null and b/hw4/Part IV-falling-ks50000-1.png differ
diff --git a/hw4/Part IV-falling-ks50000-2.png b/hw4/Part IV-falling-ks50000-2.png
new file mode 100644
index 0000000..f35e49d
Binary files /dev/null and b/hw4/Part IV-falling-ks50000-2.png differ
diff --git a/hw4/Part IV-falling-ks50000-3.png b/hw4/Part IV-falling-ks50000-3.png
new file mode 100644
index 0000000..62c3033
Binary files /dev/null and b/hw4/Part IV-falling-ks50000-3.png differ
diff --git a/hw4/Part IV-falling-ks50000-4.png b/hw4/Part IV-falling-ks50000-4.png
new file mode 100644
index 0000000..7bb9c32
Binary files /dev/null and b/hw4/Part IV-falling-ks50000-4.png differ
diff --git a/hw4/Part V-bump_ball.png b/hw4/Part V-bump_ball.png
new file mode 100644
index 0000000..a03be42
Binary files /dev/null and b/hw4/Part V-bump_ball.png differ
diff --git a/hw4/Part V-bump_cloth.png b/hw4/Part V-bump_cloth.png
new file mode 100644
index 0000000..9547b38
Binary files /dev/null and b/hw4/Part V-bump_cloth.png differ
diff --git a/hw4/Part V-bump_sphere_128.png b/hw4/Part V-bump_sphere_128.png
new file mode 100644
index 0000000..de415e1
Binary files /dev/null and b/hw4/Part V-bump_sphere_128.png differ
diff --git a/hw4/Part V-bump_sphere_16.png b/hw4/Part V-bump_sphere_16.png
new file mode 100644
index 0000000..445057e
Binary files /dev/null and b/hw4/Part V-bump_sphere_16.png differ
diff --git a/hw4/Part V-displacement_ball.png b/hw4/Part V-displacement_ball.png
new file mode 100644
index 0000000..ccfa0b7
Binary files /dev/null and b/hw4/Part V-displacement_ball.png differ
diff --git a/hw4/Part V-displacement_cloth.png b/hw4/Part V-displacement_cloth.png
new file mode 100644
index 0000000..10a868f
Binary files /dev/null and b/hw4/Part V-displacement_cloth.png differ
diff --git a/hw4/Part V-displacement_sphere_128.png b/hw4/Part V-displacement_sphere_128.png
new file mode 100644
index 0000000..1e8d3c9
Binary files /dev/null and b/hw4/Part V-displacement_sphere_128.png differ
diff --git a/hw4/Part V-displacement_sphere_16.png b/hw4/Part V-displacement_sphere_16.png
new file mode 100644
index 0000000..4b2041b
Binary files /dev/null and b/hw4/Part V-displacement_sphere_16.png differ
diff --git a/hw4/Part V-mirror_cloth.png b/hw4/Part V-mirror_cloth.png
new file mode 100644
index 0000000..6c292f5
Binary files /dev/null and b/hw4/Part V-mirror_cloth.png differ
diff --git a/hw4/Part V-mirror_sphere.png b/hw4/Part V-mirror_sphere.png
new file mode 100644
index 0000000..fb7b0a4
Binary files /dev/null and b/hw4/Part V-mirror_sphere.png differ
diff --git a/hw4/Part V-phong-all.png b/hw4/Part V-phong-all.png
new file mode 100644
index 0000000..e782014
Binary files /dev/null and b/hw4/Part V-phong-all.png differ
diff --git a/hw4/Part V-phong-ambient.png b/hw4/Part V-phong-ambient.png
new file mode 100644
index 0000000..14edea0
Binary files /dev/null and b/hw4/Part V-phong-ambient.png differ
diff --git a/hw4/Part V-phong-diffuse.png b/hw4/Part V-phong-diffuse.png
new file mode 100644
index 0000000..1a5644d
Binary files /dev/null and b/hw4/Part V-phong-diffuse.png differ
diff --git a/hw4/Part V-phong-specular.png b/hw4/Part V-phong-specular.png
new file mode 100644
index 0000000..0582ead
Binary files /dev/null and b/hw4/Part V-phong-specular.png differ
diff --git a/hw4/Part V-texture_mapping.png b/hw4/Part V-texture_mapping.png
new file mode 100644
index 0000000..c228238
Binary files /dev/null and b/hw4/Part V-texture_mapping.png differ
diff --git a/hw4/Part-II-high-damp-done.png b/hw4/Part-II-high-damp-done.png
new file mode 100644
index 0000000..a6cfc3b
Binary files /dev/null and b/hw4/Part-II-high-damp-done.png differ
diff --git a/hw4/Part-II-high-damp-mid.png b/hw4/Part-II-high-damp-mid.png
new file mode 100644
index 0000000..4eb464e
Binary files /dev/null and b/hw4/Part-II-high-damp-mid.png differ
diff --git a/hw4/Part-II-high-dense-done.png b/hw4/Part-II-high-dense-done.png
new file mode 100644
index 0000000..a8ceb71
Binary files /dev/null and b/hw4/Part-II-high-dense-done.png differ
diff --git a/hw4/Part-II-high-dense-mid.png b/hw4/Part-II-high-dense-mid.png
new file mode 100644
index 0000000..0f65e61
Binary files /dev/null and b/hw4/Part-II-high-dense-mid.png differ
diff --git a/hw4/Part-II-high-ks-done.png b/hw4/Part-II-high-ks-done.png
new file mode 100644
index 0000000..54b3c6f
Binary files /dev/null and b/hw4/Part-II-high-ks-done.png differ
diff --git a/hw4/Part-II-high-ks-mid.png b/hw4/Part-II-high-ks-mid.png
new file mode 100644
index 0000000..6e0359c
Binary files /dev/null and b/hw4/Part-II-high-ks-mid.png differ
diff --git a/hw4/Part-II-low-damp-done.png b/hw4/Part-II-low-damp-done.png
new file mode 100644
index 0000000..988027d
Binary files /dev/null and b/hw4/Part-II-low-damp-done.png differ
diff --git a/hw4/Part-II-low-damp-mid-1.png b/hw4/Part-II-low-damp-mid-1.png
new file mode 100644
index 0000000..46d5a04
Binary files /dev/null and b/hw4/Part-II-low-damp-mid-1.png differ
diff --git a/hw4/Part-II-low-damp-mid-2.png b/hw4/Part-II-low-damp-mid-2.png
new file mode 100644
index 0000000..58715a5
Binary files /dev/null and b/hw4/Part-II-low-damp-mid-2.png differ
diff --git a/hw4/Part-II-low-dense-done.png b/hw4/Part-II-low-dense-done.png
new file mode 100644
index 0000000..49ebd9d
Binary files /dev/null and b/hw4/Part-II-low-dense-done.png differ
diff --git a/hw4/Part-II-low-dense-mid.png b/hw4/Part-II-low-dense-mid.png
new file mode 100644
index 0000000..18fe76d
Binary files /dev/null and b/hw4/Part-II-low-dense-mid.png differ
diff --git a/hw4/Part-II-low-ks-done.png b/hw4/Part-II-low-ks-done.png
new file mode 100644
index 0000000..1cc36cc
Binary files /dev/null and b/hw4/Part-II-low-ks-done.png differ
diff --git a/hw4/Part-II-low-ks-mid.png b/hw4/Part-II-low-ks-mid.png
new file mode 100644
index 0000000..9f5dfb7
Binary files /dev/null and b/hw4/Part-II-low-ks-mid.png differ
diff --git a/hw4/Part-II-pinned-4.png b/hw4/Part-II-pinned-4.png
new file mode 100644
index 0000000..17f3fb8
Binary files /dev/null and b/hw4/Part-II-pinned-4.png differ
diff --git a/hw4/index.html b/hw4/index.html
new file mode 100644
index 0000000..9841b9d
--- /dev/null
+++ b/hw4/index.html
@@ -0,0 +1,543 @@
+
+
+
+
+
+ Homework 4 Report
+
+
+
+
+
+
+
+ Clothsim explores various aspects of cloth simulation, divided into
+ several parts. Part 1 introduces masses and springs, showcasing
+ wireframe images with different constraints. Part 2 delves into
+ numerical integration simulations, demonstrating the impact of
+ parameters like spring constant, damping, and density on cloth behavior.
+ Part 3 focuses on collision handling with other objects, illustrating
+ the effect of varying spring constants. Part 4 addresses
+ self-collisions, displaying cloth falling scenarios with different
+ densities and spring constants. Part 5 explores shader programs,
+ including the Blinn-Phong shading model, texture mapping, bump mapping,
+ and mirror shader effects, showcasing their visual outcomes and
+ computational complexities. Overall, the implementation proecss went
+ quite smooth for our team.
+
+
+
+
+
Part 1: Masses and springs
+
screenshots of scene/pinned2.json
+
+
+
+
+
+
+
+
+
+
screenshots of wireframe
+
+
+
+
+
+
+
+
+
+
+
Part 2: Simulation via numerical integration
+
+
screenshots of large images with normal shading
+
+
+
+
+
+
+
+
+
+
+
+
+
+ With a very low spring constant(ks), the cloth behaves sluggishly. It
+ stretches easily and doesn't snap back quickly. This results in a very
+ loose and wobbly cloth that doesn't hold its shape well. Conversely,
+ with a high spring constant, the cloth becomes stiff. It resists
+ deformation strongly, leading to less movement and more rigidity in the
+ cloth structure.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ With low damping, the cloth oscillates more freely and takes longer to
+ come to rest after being disturbed. It may exhibit exaggerated movements
+ and fluttering. High damping damps out oscillations more quickly,
+ resulting in a smoother and more controlled movement of the cloth. It
+ settles down faster after being disturbed.
+
+
+
+
+
+
+
+
+
+
+
+
+ A low density cloth feels lighter and thus looks smoother and has less
+ wrinkles at the point of gravity. On the other hand, a high-density
+ cloth feels heavier and is less affected by external forces. It has
+ larger gravity which creates more folds in the middle.
+
+
screenshot of shaded cloth from scene/pinned4.json
+
+
+
+
+
+
+
+
+
Part 3: Handling collisions with other objects
+
Comparison between different ks
+
+
+
+
+
+
+
+
+ We can see that varying the spring constant in the cloth simulation will
+ directly impact its stiffness and how tightly it conforms to the
+ underlying surface. Lower values will yield a softer, more fluid-like
+ behavior, while higher values will produce a stiffer, more rigid
+ appearance.
+
+
Cloth resting on plane
+
+
+
+
+
+
+
+
+
Part 4: Handling self-collisions
+
+
Screenshots cloth falling
+
+
+
+
+
+
+
+
+
+
+
dense = 15, ks = 5000
+
+
Comparison between different ks and density
+
+
+
+
+
+
+
+
+
+
+
dense = 40, ks = 5000
+
+
+
+
+
+
+
+
+
+
+
dense = 5, ks = 5000
+
+ As the density grows, the gravity of the cloth gets larger and thus if
+ falls and go to a rest state faster. When reaching a final state, the
+ cloth with higher density will be piled together into several layers,
+ while the cloth with lower density will have less layers on the ground
+ and eventually become flat.
+
+
+
+
+
+
+
+
+
+
+
+
+
dense = 15, ks = 500
+
+
+
+
+
+
+
+
+
+
+
dense = 15, ks = 500
+
+ With a high ks, the cloth behaves stiffly and resists deformation. As
+ the cloth falls onto the plane, it maintains its shape relatively well.
+ The impact with the plane is absorbed quickly, causing the cloth to
+ bounce off with little deformation. While with lower ks, the cloth
+ behaves more flexibly and deforms easily. As it falls onto the plane,
+ the cloth stretches and wrinkles significantly due to the impact force.
+ It may even fold or bunch up upon contact with the surface. The low
+ stiffness allows the cloth to absorb more energy from the impact,
+ resulting in a slower settling process. When reaches a final state, the
+ cloth has more wrinkles and folds.
+
+
+
+
+
Part 5: Cloth Sim
+
Shader Program Definition and Usage Explaation
+
+
+ A shader program is a set of instructions written in a shading language
+ that runs on the GPU to compute rendering effects. Shaders are used to
+ manipulate the appearance of 3D objects in computer graphics
+ applications. They are typically categorized into two main types: vertex
+ shaders and fragment shaders.
+
+
+ Vertex shaders primarily handle vertex-level operations, transforming 3D
+ vertex positions from object space to screen space, and computing
+ lighting and material properties at each vertex. They also pass data to
+ fragment shaders which determine the color of each pixel on the screen
+ by interpolating values computed by vertex shaders across triangles, and
+ applying lighting equations, texture mapping, and material properties to
+ produce the final rendered image.
+
+
+
Blinn-Phong shading model
+
+ The Blinn-Phong shading model calculates the color of each pixel based
+ on its interaction with light sources. It considers ambient, diffuse,
+ and specular lighting components. The ambient component represents the
+ overall light in the scene. Diffuse lighting depends on the angle
+ between the surface normal and light direction. Specular lighting is
+ based on the reflection of light towards the viewer, with the intensity
+ influenced by the surface roughness. The model simulates realistic
+ material effects.
+
+
+
Screenshots for Blinn-Phong
+
+
+
+
+
+
+
+
+
Texture Mapping Shader Custom Sample
+
+
+
+
Bump Mapping Shader with texture_3
+
+
+
+
+
+
+
+
+
+ Bump mapping would produce a cloth and sphere with the illusion of bumps
+ and wrinkles, while displacement mapping would physically deform the
+ geometry of the sphere to represent the bumps and wrinkles. Displacement
+ mapping yields more realistic results at the cost of increased
+ computational complexity.
+
+
+
+
+
+
+
+
+
+
+ Bump mapping outperforms displacement mapping at this low sampling rate.
+ The blockiness of the sphere in the 16x16 displacement mapping image
+ illustrates this issue. This blockiness occurs because the fragment
+ shader interpolates height perturbations over the sphere from too few
+ samples, leading to inadequate representation of high frequency details
+ present in the texture. Conversely, with 128x128 samples, displacement
+ mapping matches the texture's high frequency content better, accurately
+ portraying both texture shading and physical deformations on the sphere.
+
+
Mirror Shader
+
+
+
+
+
+
+
+
+
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..746e482
--- /dev/null
+++ b/index.html
@@ -0,0 +1,103 @@
+
+
+
+
+ Darren Wang | CS184 Homework Webpages
+
+
+
+