Back to projects
2022

Interactive 3D Winter Scene

A browser-based, explorative 3D world built with Three.js and custom GLSL shaders. Features a performant GPU-based particle system and handcrafted Blender assets.

JavaScriptThree.jsBlenderWebGLGLSL

The Problem

As a developer accustomed to the rigid box-model of the DOM, I wanted to break out of 2D constraints and understand how immersive graphics work on the web.

I didn't want to simply drag-and-drop assets into an engine. I wanted to understand the full pipeline, from modeling geometry, texture mapping and lighting to manipulating pixels on the screen via the GPU.

The Challenge: Rendering 3D in a browser is computationally expensive. My goal was to create a visually rich scene with dynamic weather effects (snow) that could still run at high framerates on standard hardware.

The Goal

My goal was to build a navigable 3D vignette that demonstrated:

  1. Full Asset Pipeline: Modeling, texturing, and optimizing assets in Blender for web export.
  2. Custom Shaders: Writing native WebGL code (GLSL) to create efficiently handled weather effects including tens of thousands of particles.
  3. Performance Optimization: Managing draw calls and geometry complexity to ensure a seamless user experience.

The Solution

Technical Decisions

I chose Three.js as the engine to handle the scene graph and camera mathematics.

The "Asset" Challenge: To keep the application lightweight, I couldn't use high-poly models. I adopted a "Low Poly" aesthetic, which required careful asset modeling/selection to convey detail through shape and lighting rather than geometry count.

Algorithms & Challenges

The core engineering challenge was the weather system.

  1. The Snow System (CPU vs GPU): Initially, I tried animating thousands of snow particles using JavaScript loops. This immediately tanked the frame rate because the CPU was bottlenecked trying to update thousands of positions per frame.
  2. Vertex Shaders: To fix this, I wrote a custom GLSL Vertex Shader. Instead of updating positions in JavaScript, I passed a "time" uniform to the GPU. The shader calculates the snow's falling movement using mathematical sine waves (to simulate wind flutter) directly on the graphics card. This allowed me to render tens of thousands of particles with zero impact on the main JavaScript thread.
  3. Fog & Atmosphere: I implemented a custom exponential fog effect that blends the geometry into the background color based on camera distance, creating a sense of depth and hiding the edges of the world map.

The Result

The final project is an interactive winter cabin scene. Users can play the role of a character walking around the forest at night, carrying a torch which can be toggled on or off, increasing immersion. The scene feels alive due to the procedural snowfall and warm lighting. By offloading the heavy lifting to the GPU, the scene loads quickly and maintains a high frame rate - the live demo link above runs at 260 FPS on my personal laptop (M2 Macbook Pro).

Lessons Learned

This project gave me a massive appreciation for Linear Algebra and the graphics pipeline. I learned that in 3D development, "brute force" coding rarely works; you have to think in terms of vectors, matrices, and shader programs.

I learnt lots about optimisation, achieving a visual style that looks artistic and immersive while being cheap to render.