Skip to content

Latest commit

Β 

History

10 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

A raymarched rainforest under warm light

Rainforest

An endless rainforest, grown from a single fragment shader. No textures. No models. Only mathematics, marching through light.

Rainforest is a real-time GPU renderer that conjures an infinite canopy from pure procedural math. A fragment shader raymarches through hash-placed trees, hills carved by fractal noise, volumetric clouds and atmospheric light β€” and paints the whole scene to the screen at interactive frame rates.

It is a faithful, modern re-implementation of IΓ±igo Quilez's celebrated demo, rebuilt on WebGL2, wrapped in a lean React shell, and extended with temporal reprojection so the image quietly sharpens as the camera drifts through the trees.


Table of Contents


About the Project

Some scenes are built; this one is grown. Every leaf, branch and ridge in Rainforest is described by distance functions and layered fractal noise β€” an infinite landscape that costs nothing to store and nothing to stream, because it is computed on demand, one ray at a time.

The result is a place that feels alive: clouds cast drifting shadows across the valley, the canopy shifts with each step of the camera, and the light has that warm, hazy quality of a late afternoon deep in the tropics.

At its core, this project is a study in the art of the possible on the GPU:

  • Everything is procedural. Terrain, trees, clouds and sky are generated in GLSL β€” zero textures, zero meshes.
  • Rendering is real time. Rays march through the scene on every frame, in your browser.
  • The image refines itself. A temporal accumulation pass blends each frame with its predecessor, converging toward a clean, anti-aliased result.

Features

  • Pure procedural world β€” an infinite rainforest defined entirely by hash functions and fractal Brownian motion. Nothing is ever loaded from disk.
  • Signed-distance raymarching β€” trees are ellipsoid SDFs scattered on a hash grid; the terrain is a fractal heightfield. Both are marched in a single pass.
  • Volumetric clouds β€” a density field raymarched over 128 steps, lit with self-shadowing, drifting slowly with time.
  • Temporal accumulation β€” the previous frame is reprojected using a stored camera matrix and blended at 10%, so the render progressively denoises and anti-aliases itself.
  • Two camera modes β€” free Orbit with smooth damping, or a cinematic Auto fly-through that glides over the canopy on its own.
  • Resolution scaling β€” render the heavy pass at Full, Half or Quarter resolution and let temporal accumulation rebuild the detail.
  • Film-style grading β€” gamma, contrast and a subtle color grade give the scene its moody, cinematic palette.
  • Graceful loading β€” the scene fades in with a soft blur-to-sharp reveal, so the very first moments feel considered.

Tech Stack

Layer Technology
UI runtime React 19
3D engine Three.js r185
Shading GLSL ES 3.0 (#version 300 es, WebGL2)
Build tool Vite 8
Camera OrbitControls from three/examples/jsm

The scene itself lives almost entirely inside src/shaders.js β€” a single, self-contained chunk of GLSL. The React side exists to orchestrate it: create the renderer, manage the two-pass pipeline, and expose the on-screen controls.


How It Works

The renderer runs as a two-pass pipeline, bouncing between a pair of framebuffers:

                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  hash + noise ───▢ β”‚      buffer pass         β”‚
  SDF + raymarch    β”‚  terrain Β· trees Β· clouds β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                β”‚  ping-pong render targets
                                β–Ό
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚       image pass         β”‚
                    β”‚  sample + soft vignette  β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                β–Ό
                              canvas
  1. Buffer pass β€” the heavy lifting. A full-screen quad is rendered into an offscreen target at a scaled resolution (Full / Half / Quarter). Each fragment computes the camera rays, marches the scene, shades it, and fogs it by distance.

  2. Temporal accumulation β€” the pass reads the previous frame from the ping-pong target, reprojects it with the camera matrix stored in the buffer's first row, and mixes it in at 10%. Every frame refines the last, giving smooth, near-converged images even while orbiting.

  3. Image pass β€” samples the buffer at native resolution, applies a gentle vignette, and presents the final frame to the canvas.

The whole loop runs inside a single requestAnimationFrame tick, with the shader receiving just four inputs: time, frame number, resolution, and the camera position/target.


Quick Start

All you need is a recent Node.js and your favorite browser.

# install dependencies
npm install

# start the dev server with hot reload
npm run dev

Then open the printed URL β€” the rainforest will fade in and begin to breathe.

Scripts

Command Description
npm run dev Start the Vite dev server with HMR
npm run build Build a production bundle into dist/
npm run preview Serve the production build locally

Note. The on-screen controls are currently in Spanish β€” Γ“rbita means Orbit, and Cargando… means Loading…. The interface is intentionally minimal; the scene is the star.


Interacting

Control Action
Drag anywhere Orbit the camera around the scene
Scroll Zoom in and out
Auto / Γ“rbita toggle Switch between cinematic fly-through and manual orbit
Full / Half / Quarter selector Scale the render resolution

Prefer sitting back? Leave it in Auto mode and let the camera take its own tour of the canopy.


Project Structure

rainforest/
β”œβ”€β”€ public/
β”‚   └── preview.jpg          # README banner
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ App.jsx              # renderer orchestration Β· controls Β· quality scaling
β”‚   β”œβ”€β”€ main.jsx             # React entry point
β”‚   └── shaders.js           # GLSL β€” the entire raymarcher + post pass
β”œβ”€β”€ index.html               # app shell, global styles, font
β”œβ”€β”€ package.json
└── vite.config.js

There is a deliberate division of labor here: App.jsx owns the lifecycle of the WebGL context, the ping-pong framebuffers, resizing, and the loading reveal β€” while shaders.js holds every line of shading code, kept isolated and portable.


Performance Notes

Raymarching an endless forest is expensive by nature, so a few deliberate choices keep it fluid:

  • Scaled buffer pass. The expensive raymarcher renders at a fraction of the screen resolution; only the cheap image pass runs at full resolution.
  • Pixel-ratio discipline. renderer.setPixelRatio(1) keeps high-DPI overdraw in check.
  • Framebuffer lightweights. Depth and stencil buffers are disabled on the render targets β€” no wasted bandwidth.
  • Half-float precision. When the GPU supports it (EXT_color_buffer_float / EXT_color_buffer_half_float), the accumulation pass runs in half float for extra stability.

Tip. If your frame rate dips, drop to Quarter and let temporal accumulation quietly rebuild the detail over a few frames.


Credits

This project stands on the shoulders of a giant of computer graphics.

  • IΓ±igo Quilez β€” the original A Rainforest demo, whose distance functions, analytical noise derivatives, and shading techniques form the heart of src/shaders.js. See it on Shadertoy and read his write-ups on raymarching distance fields.
  • Three.js and Vite β€” the patient scaffolding underneath.

Roadmap

Ideas on the horizon, in no particular order:

  • Time-of-day cycle with shifting sun position and palette
  • Seasonal variants β€” autumn fog, dawn mist, monsoon light
  • Stills export at full resolution
  • Mobile performance pass
  • English / Spanish interface toggle

License

This project is private and unlicensed β€” all rights reserved. It is not currently distributed under an open-source license.

The GLSL in src/shaders.js is derived from IΓ±igo Quilez's A Rainforest, originally published on Shadertoy under Creative Commons licensing. Please respect the terms of the original work when reusing any of the shading code.


Made with ❀️ by SebastiÑn V

About

πŸŒ΄πŸƒA rainforest that isn't planted: it's computed. In a single ray-marching pass, this application makes mountains, fog, clouds, and thousands of trees bloom straight on the GPU β€” with no 3D models and no texture files on disk.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages