Skip to content

thumun/TerrainGen

Repository files navigation

TerrainGen

Final project for University of Pennsylvania, CIS5650 GPU Programming and Architecture, Fall 2025

Raymond Feng, Neha Thumu, Thomas Shaw

Screenshot 2025-12-07 231302

Link to website!

Overview

TerrainGen is a single-page web application using WebGPU to create a real-time node-based procedural terrain generation and rendering tool. Our motivation for the project was to create an accessible modelling tool on the web to showcase the power of WebGPU.

image Screenshot 2025-12-07 233712

Milestones

  1. Milestone 1 Progress Slides
  2. Milestone 2 Progress Slides
  3. Milestone 3 Progress Slides
  4. Final Presentation

How to Use

For a more in-depth look at how to use each node/feature, check out the project wiki.

Window Layout

image

Nodes can be added to the canvas element on the left-hand side of the screen and will be renderer on the right side window when the output nodes have the appropriate inputs. The terrain has two additional settings that can be adjusted with the terrain size and resolution sliders below the render screen.

Import/Export

Screenshot 2025-12-07 232242

A user can import/export their node graph.

As an example, here is a saved node graph layout file. If this is imported, then the following node graph will be loaded in.

image

The skybox can also be changed by uploading an HDR file.

Project Features

  • 🔌 Node-based description system for procedural terrain
  • 🏭 Just-in-time WebGPU shader code generation
  • 🏔️ Real-time terrain rendering
    • Adjustable tesselation and terrain size
    • Varied terrain type rendering (grass, rock, snow, etc)
    • Shadow mapping
    • Distance fog
  • 🌲 Mesh instancing across terrain
    • glTF/OBJ import for instancing

JIT Shader Code Generation

Once there is a valid node graph connected to one of our output pipelines (Terrain, Instancing, and Water) our pipeline gets computed and the shader code is generated. Our nodes of type input create uniform keys and each subsequent output handle generates a key on the fly. Each node has specific code that is generated and added to our vertex shader along with references to the aforementioned uniform keys.

Terrain Rendering

The terrain is a tesselated plane with an adjustable size and resolution. Whenever the size and resolution sliders are changed, a compute shader populates a vertex buffer and an index buffer. A second compute pass gives each vertex on the terrain a normal value, which is calculated based on the position of neighboring vertices.

Once the terrain is created with the compute shaders, it is rendered every frame with lambertian shading, shadow mapping, and distance fog.

The terrain's color can be changed with a dropdown in the Terrain (Output) node.

Mesh Instancing

TerrainGen also supports OBJ and glTF import, which can be used as part of the instancing pipeline. Users can create multiple instancing pipelines, each of which creates a separate buffer of instancing points on which the desired mesh will be placed. These instancing points are randomly generated on top of the terrain using the Scatter node.

With glTFs, base color textures can be displayed.

Node Types

  • General-purpose
    • Basic math (add, sub, mult, div)
    • Trig math (sin, cos, tan)
  • Terrain source
    • Worley noise
  • Terrain input
    • Vertex XYZ position
  • Terrain output
    • Height
    • Terrain type
    • Water level
  • Scattering source
    • Terrain height
    • Instancing node
  • Scattering geometry
    • Built-in objects: trees, rocks, bushes
    • Primitive geometry: sphere, cube, plane
    • Custom models
      • OBJ import
      • glTF import

Appendix

npm install
npm run dev

Building For Production

To build this application for production:

npm run build

The resulting static content will be in the dist folder. You can preview these with npm run preview.

We have created a GitHub Actions workflow (.github/workflows/deploy.yml) to automatically deploy static content to GitHub Pages.

Testing

This project uses Vitest for testing. You can run the tests with:

npm run test

Linting & Formatting

This project uses eslint and prettier for linting and formatting. Eslint is configured using tanstack/eslint-config. The following scripts are available:

npm run typecheck  # just runs tsc
npm run lint
npm run lint:fix  # automatically fix issues
npm run format
npm run format:check  # don't write to any files, just report issues

Third-party libraries

  • Tailwind CSS for styling.
  • React for DOM manipulation
  • TanStack Router. The initial setup is a code based router. Which means that the routes are defined in code (in the ./src/main.tsx file). If you like you can also use a file based routing setup by following the File Based Routing guide.
  • React Flow for node editor functionality
  • loaders.gl for reading/writing of external files
  • io-rgbe for HDR loading

About

Final project for CIS5650

Resources

Stars

Watchers

Forks

Contributors