Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 41 additions & 82 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
# TerrainGen

_Final project for CIS5650_
_Final project for University of Pennsylvania, CIS5650 GPU Programming and Architecture, Fall 2025_

![Milestone 1 Demo](./docs/images/milestone_01_demo.webp)
Raymond Feng, Neha Thumu, Thomas Shaw

<img width="1195" height="569" alt="Screenshot 2025-12-07 231302" src="https://github.com/user-attachments/assets/b1dab04f-0c98-46ac-9cde-09d7cb394e71" />

[Link to website! ](https://thumun.github.io/TerrainGen/)

## Motivation
## 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.

This is a single-page web application using WebGPU to create a real-time node-based procedural terrain generation tool.
<img width="500" height="400" alt="image" src="https://github.com/user-attachments/assets/830e006d-f6ba-4b15-9daf-a802301df2bf" />
<img width="500" height="400" alt="Screenshot 2025-12-07 233712" src="https://github.com/user-attachments/assets/9a188925-c8d5-4b1d-ad1a-db0ab446be80" />

### Milestones

Expand All @@ -17,9 +22,9 @@ This is a single-page web application using WebGPU to create a real-time node-ba
3. [Milestone 3 Progress Slides](https://docs.google.com/presentation/d/1SY8XgbtOQOwFCNqlIhqCft3_o6H0uVIyBBi3s_v93jw/edit?usp=sharing)
4. [Final Presentation](https://docs.google.com/presentation/d/1d1kF9o0qythf8vgfsJAXlKPUyjCBU8piUQctd_OLzT8/edit?usp=sharing)

## Project Details
## How to Use

TerrainGen is a easy-to-use procedural, node-based tool that users can utilize to create terrain! Our project is entirely on WebGPU so the user does not have to worry about any setup/download issues.
For a more in-depth look at how to use each node/feature, check out the **[project wiki](https://github.com/thumun/TerrainGen/wiki)**.

### Window Layout

Expand All @@ -29,7 +34,7 @@ Nodes can be added to the canvas element on the left-hand side of the screen and

### Import/Export

<img width="200" height="292" alt="image" src="https://github.com/user-attachments/assets/5946e1e9-4189-46ef-a593-d0007ddfe020" />
<img width="385" height="213" alt="Screenshot 2025-12-07 232242" src="https://github.com/user-attachments/assets/1a66c0e5-335a-4202-ab53-0feba296e9d6" />

A user can import/export their node graph.

Expand All @@ -38,109 +43,62 @@ If this is imported, then the following node graph will be loaded in.

<img width="500" height="968" alt="image" src="https://github.com/user-attachments/assets/91ac03f7-4fad-4dd1-a62b-5bd242054c49" />

### Input Nodes

#### Vertex Data

This node outputs the position of the verticies. Nodes connected to this one can be used to offset these positions.
<img width="378" height="174" alt="image" src="https://github.com/user-attachments/assets/38adfa94-68c6-42cb-8bd6-b7689630da02" />

#### Geometry

These nodes all work the same functionally. In that, they load a chosen model based on user input after connected to the **instancing (output)** node.
|<img width="379" height="241" alt="image" src="https://github.com/user-attachments/assets/aa79ad21-5101-40a2-9b4e-874bb0944ef5" /> | <img width="373" height="241" alt="image" src="https://github.com/user-attachments/assets/91e9f8f0-09c5-4d9a-9ab1-5a317ee425d2" /> | <img width="481" height="261" alt="Screenshot 2025-12-01 135707" src="https://github.com/user-attachments/assets/0a9cf638-f27d-43b0-94fb-de3d3d76534d" /> |
-------------------------- | -------------------------- | -------------------------- |
A user can add primitive geometry with this node (cube, sphere, plane) | A user can load their personal models with this node (only OBJ is supported for the time being) | A user can choose between our custom built-in geometry (ex. trees, rocks) to add to the terrain rather than upload their own |

#### Float

This node allows for an input float variable.

<img width="320" height="197" alt="image" src="https://github.com/user-attachments/assets/27a5aca0-a385-470a-ba32-99a32d944072" />

#### Vector

This node allows for an input vec3f variable.

<img width="318" height="325" alt="image" src="https://github.com/user-attachments/assets/417311ad-3078-410a-93ca-5e866f0d6d0f" />

#### Unsigned Int

This node allows for an input unsigned int variable.
The skybox can also be changed by uploading an HDR file.

<img width="321" height="208" alt="image" src="https://github.com/user-attachments/assets/1109f959-3dec-4e72-911f-de0c8c3880cc" />
## Project Features

### Utility Nodes

| Separate XYZ | Combine XYZ |
| ---------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| <img width="340" height="306" alt="image" src="https://github.com/user-attachments/assets/d1d2e9f2-9d14-4c8e-8d8f-07c4b0350d6b" /> | <img width="330" height="300" alt="image" src="https://github.com/user-attachments/assets/cd8947c4-a7f5-4eb5-80b0-b31d0ce896c1" /> |
| This node separates an input of type vec3f to three floats (x, y, z) | This node combines three float inputs into one vec3f |

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

-- Will be added --
### Node-based Description System

### Operator Nodes
### JIT Shader Code Generation

### Math
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.

| Math | Trig Math | Mix |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| <img width="352" height="325" alt="image" src="https://github.com/user-attachments/assets/56f5bf4e-05ad-45fc-996b-010a88bfa42c" /> | <img width="396" height="317" alt="image" src="https://github.com/user-attachments/assets/4da26921-8eb5-4b22-ab87-7a5bfe9fdff3" /> | <img width="370" height="334" alt="image" src="https://github.com/user-attachments/assets/c23e180c-956c-4230-b1f8-0e3f4d65aba2" /> |
| This node can be used to apply one of the following operations (add, subtract, multiply, divide) to two inputs (float or vec3f) and returns a value of the same type | This node applies a trig function to an input value and returns a float output | This node linearly interporaltes between the two input values based on the mix value |
### Terrain Rendering

### Noise
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.

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

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

| Terrain | Instancing |
| ---------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| <img width="340" height="306" alt="image" src="https://github.com/user-attachments/assets/d1d2e9f2-9d14-4c8e-8d8f-07c4b0350d6b" /> | <img width="330" height="300" alt="image" src="https://github.com/user-attachments/assets/cd8947c4-a7f5-4eb5-80b0-b31d0ce896c1" /> |
| This node triggers the terrain pipeline if the height float input is connected to a valid node. | This node triggers the instancing pipeline. The pipeline is only run/rerun if both the scatter and geometry inputs are connected to valid nodes. |
### Mesh Instancing

### Feature checklist
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.

- [x] 🔌 Node-based description system for procedural terrain
- [x] 🏭 Just-in-time WebGPU shader code generation
- [x] 🏔️ Real-time terrain rendering
- [x] Adjustable tesselation and terrain size
- [ ] Varied terrain type rendering (grass, rock, snow, etc)
- [ ] 🔎 Real-time in-editor node previews
- [x] 🌲 Mesh instancing across terrain
- [x] Mesh import for instancing
- [ ] 💾 Export to glTF or similar format
With glTFs, base color textures can be displayed.

#### Node types:
## Node Types

- General-purpose
- [x] Basic math (add, sub, mult, div)
- [x] Trig math (sin, cos, tan)
- [ ] Masking/graphics util (mix, lt, gt, min, max)
- Terrain source
- [ ] Perlin noise
- [ ] Custom image texture
- [x] Worley noise
- Terrain input
- [x] Vertex XYZ position
- Terrain output
- [x] Height
- [ ] Terrain type
- [x] Terrain type
- [x] Water level
- Scattering source
- [x] Terrain height
- [ ] Voronoi scattering
- [x] Instancing node
- Scattering geometry
- [x] Built-in objects: trees, rocks, bushes
- [x] Primitive geometry: sphere, cube, plane, line
- [x] Primitive geometry: sphere, cube, plane
- Custom models
- [x] OBJ import
- [ ] glTF import
- [ ] Vegetation → like Unreal’s PCG

## Development

To run this application:
- [x] glTF import

```bash
npm install
Expand Down Expand Up @@ -186,3 +144,4 @@ npm run format:check # don't write to any files, just report issues
- [TanStack Router](https://tanstack.com/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](https://tanstack.com/router/latest/docs/framework/react/guide/file-based-routing) guide.
- [React Flow](https://reactflow.dev/) for node editor functionality
- [loaders.gl](https://loaders.gl/) for reading/writing of external files
- [io-rgbe](https://github.com/DerSchmale/io-rgbe) for HDR loading