Simulated Stage Chime
By Yaqi Zhen→Simulated Stage Chime transforms the original A8 vertical mass–spring chain into a 3D hanging wind chime made of glass beads, rendered under a rotating stage spotlight. The project combines the physical mass–spring simulation with custom mesh-based bead geometry and dynamic lighting, so the chime both moves realistically and shimmers visually with specular and Fresnel highlights.
Implemented Features
- Beads rendered as instanced triangle-mesh V_sphere_template
- Instead of rendering each mass point as a GL point, every bead is rendered as a small triangle-mesh sphere. So each bead has: a real surface, normals, and smooth shading under the light.
- I load sphere.obj as a template sphere, scale it to a bead radius, and then instantiate it once per mass point (plus one extra bead at the top hook).
- Code: in main.cpp , the sphere mesh is loaded and scaled ( V_sphere_template , F_sphere ). During the simulation, a global bead mesh ( V_beads , F_beads , C_beads ) is dynamically rebuilt by copying and translating this template sphere to the current position of each mass point (plus the fixed hook bead). This instancing step is handled by the function update_bead_mesh(U) . The final bead geometry is then rendered through viewer.data_list[bead_mesh_id].set_mesh(V_beads, F_beads);. This approach keeps the viewer fast and efficient while allowing all beads to benefit from smooth shading, dynamic lighting, and consistent material appearance.
- Multi-color bead palette
- To give the wind chime a stage-prop aesthetic, each bead is assigned one of three alternating colors (cyan → teal → purple), creating a repeating palette. (Line95)
- All fixed/pinned points are assigned a metallic silver color to visually separate structural nodes from free beads. (Line109)
- Code: After loading the mesh, the color matrix CM is created and filled with three bead colors. Pinned vertices are overwritten with the fixed silver color. These colors are then injected into the bead vertex colors inside update_bead_mesh(U) , ensuring the color is embedded into each instanced sphere, and also the graph visualization viewer.data_list[graph_id].set_points(U, CM).
- Rotating spotlight for dynamic stage lighting
- To make the shimmer dynamic, I animate the position of the point light over time. This creates moving specular highlights and shifting Fresnel glows across the beads.
- The light follows a circular XZ-orbit with slight vertical Y-oscillation, allowing to create a spotlight effect.
- Code: In callback_pre_draw (Line237), I compute a time-dependent angle, circular/elliptical path around the chime using cos and sin of elapsed time, and assign it to viewer.core().light_position . (Line248)
- Because the bead mesh uses per-vertex normals in the shader, this moving light causes the highlights to slide along each string of beads as the chime swings in the simulated wind.
- Small shader refinements + dark stage-style background
- In addition to using the assignment’s Phong + Fresnel shader, I made a small modifications to emphasize the stage lighting style of the piece.
- The default fragment-shader lighting block originally computed the final surface color inside a single vec4 color = … expression.
I refactored this part to explicitly separate the lighting components into (Line 435):
- lit — the total contribution from Fresnel ( If ), specular ( Is ), and diffuse ( Id ),
- base — the bead’s intrinsic material/albedo color ( Kdi ),
- final_rgb — a clean mix between the lighting result and the base color, controlled by lighting_factor .
- This separation makes the lighting more tunable.
- I changed the environment to dark so the lighting and bead colors stand out more(Line 170).
- Hook and string structure
- The fixed points of the mass–spring system are averaged to compute a central “hook” position.
- I add an extra node above the chime and connect it with line segments to all fixed points, forming a small pyramid-like structure at the top (similar to a real wind chime hanger).
- Code: V_hook and E_hook are built near the end of main.cpp. The hook structure is rendered as its own drawable entity using: set_edges and set_points.
Acknowledgements
- Starter code and data from CSC317 A8: Mass-Spring Systems
- Wind chime configuration (wind-chime.obj and wind-chime.json ) is adapted from the original horizontal-chain example provided in the CSC317 A8 assignment materials.
- Sphere template mesh (sphere.obj) was downloaded from “OBJ Sphere” on Free3D (https://free3d.com/3d-models/obj-sphere) and adapted for use as the instanced bead geometry in this project.