This project represents the culmination of my computer graphics journey: "Eat The Metaball", an interactive game developed using WebGL and GLSL.
KEY FEATURES OF THE PROJECT
Metaball Rendering: Implemented metaballs using implicit surfaces and signed distance functions (SDFs). The smooth blending of metaballs was achieved through GLSL shaders, giving the game its organic, fluid visuals.
WebGL Pipeline: Leveraged WebGL to handle vertex and fragment shaders, ensuring efficient real-time rendering in a web browser.
Interactive Gameplay: Designed user interactions where players control a point that "eats" smaller metaballs while avoiding larger ones, blending graphics with an engaging game mechanic.
Performance Optimization: Carefully optimized shader programs to compute metaball visuals dynamically, balancing visual quality and performance.
More than just a project, "Eat The Metaball" kickstarted my passion for shaders. It was here that I discovered how powerful code can be—not just for solving problems, but for creating something artistic, interactive, and fun. This project showed me the creative potential behind graphics programming, blending mathematical precision with visual design.
"Eat The Metaball" is a milestone that reflects both my technical growth and my excitement for combining code, creativity, and playability.
But where did my Computer Graphics journey start...?
This project marks the beginning of my computer graphics journey, where I implemented the fundamentals of rendering 3D shapes. Using C++ and OpenGL, I focused on:
Defining vertices and points: Stored coordinates in arrays to build the geometry of primitives.
Tessellation: Controlled the subdivision of surfaces by adjusting the tessellation factor, increasing the detail level.
Computing normals: Calculated normal vectors for each vertex to ensure accurate surface orientation and lighting.
Rendering wireframes and triangles: Connected points to form triangles and displayed the geometry in wireframe mode.
Visualizing normals: Rendered normals as red lines extending from each vertex for debugging and verification.
The image showcase the primitives I was able to render, with the wireframe highlighted in yellow displaying the tessellation, and the normals displayed in red. This project gave me a clear understanding of how primitives are built and rendered, laying the groundwork for more complex 3D graphics.
KEY CONCEPTS I EXPLORED:
Object vs. World Space: Learned how objects exist in their own local space but must be transformed into world space to position them in a scene.
Transformations: Implemented rotations, translations, and scaling to manipulate objects relative to both the camera and world axes.
Camera Movement: Designed a functional camera to navigate the scene, enabling view transformations and perspective projection to simulate a 3D view.
Scene Graph: Built a hierarchical structure to manage transformations for multiple primitives. This allowed me to construct a scene efficiently and demonstrate relationships between objects.
To bring this knowledge to life, I created a scene graph that renders a primitive-based model of Squirtle, the Pokémon. By breaking Squirtle into individual shapes (e.g., spheres for the head and shell, cylinders for limbs), I could position and animate each part using parent-child transformations within the scene graph.
This project was a turning point—it showed me how a simple combination of mathematical transformations could construct and control entire 3D scenes. The functional camera not only expanded my technical skills but also gave me the tools to visualize and explore complex worlds.
Building on my understanding of transformations and cameras, I ventured into the world of ray tracing by implementing a recursive ray tracing algorithm. This project deepened my grasp of lighting, shadows, and reflections while teaching me how recursion can simulate the real-world behavior of light.
KEY FEATURES AND CONCEPTS:
Ray Casting: Cast rays from an eye point through each pixel on the screen to determine the color of that pixel.
Recursive Secondary Rays: Implemented recursion to handle shadows, reflections, and refractions. A recursion depth slider allows control over how many levels of rays are cast, balancing accuracy and performance.
Lighting Calculations: Integrated Phong lighting to compute realistic shading with:
Ambient lighting for overall illumination,
Diffuse lighting for surface shading based on light direction,
Specular highlights to simulate shiny surfaces.
Multiple Light Sources: Added support for multiple light sources to enhance realism and complexity in lighting calculations.
Texture Mapping: Parsed PPM textures and blended them with surface colors, allowing textured objects to interact dynamically with light and reflections.
With this recursive ray tracer, I took a significant step forward—from building static scenes to simulating how light behaves in a dynamic, mathematically driven environment.
Progressing further into graphics programming, I delved into GLSL to enhance my understanding of shaders and real-time rendering. This project focused on implementing environment mapping to create realistic reflections on objects.
KEY FEATURES:
Loading PLY Files: Implemented loading a PLY (Polygon File Format) model into the scene. This allowed for rendering complex, real-world objects rather than simple primitives.
Spherical Environment Mapping: Implemented environment mapping by surrounding the scene with a textured sphere. Calculated reflection vectors in GLSL to simulate how the environment reflects off the surface of the central object, creating a mirror-like effect.
GLSL Shaders: Utilized vertex and fragment shaders to perform per-pixel calculations for reflections and lighting, leveraging the power of the GPU for real-time performance.
Texture Blending: Handled texture mapping on the object, blending the environment reflection with the object's base texture to achieve a more nuanced and realistic appearance.
Diffuse Lighting: Incorporated diffuse lighting calculations to ensure the object interacts naturally with the scene's light sources, enhancing depth and realism.
This project was a significant step in understanding how shaders can manipulate the appearance of objects dynamically. By calculating how the environment reflects off surfaces, I could create the illusion of a reflective material without the computational cost of real-time ray tracing.
Learning GLSL opened up new possibilities for creative expression through code. It reinforced how programmable shaders are essential for modern graphics, enabling complex visual effects that are both efficient and visually stunning.