| name | dev-noise-texture |
| description | Add procedural noise texture generation to the asset pipeline — C tool, Python plugin, web UI with live preview |
| user_invokable | true |
Noise Texture Generation
Add procedural noise texture generation to the forge-gpu asset pipeline.
A C tool samples noise functions from forge_math.h across a pixel grid
and writes grayscale BMP heightmaps. A Python pipeline plugin invokes the
tool as a subprocess, and the web UI provides interactive parameter tuning
with live preview.
When to use
- Generating procedural heightmaps for terrain
- Creating tileable noise textures (fBm, Worley, ridged multi-fractal)
- Deriving normal maps from heightmaps
- Adding procedural texture generation to the pipeline
Key API calls
C noise functions (forge_math.h)
| Function | Output | Use case |
|---|
forge_noise_perlin2d | [-1, 1] | Basic gradient noise |
forge_noise_simplex2d | [-1, 1] | Less axis-aligned than Perlin |
forge_noise_fbm2d | [-1, 1] | Multi-scale terrain, clouds |
forge_noise_ridged_fbm2d | [0, 1] | Mountain ridges, rivers |
forge_noise_worley2d | F1, F2 distances | Voronoi cells, edges |
forge_noise_domain_warp2d | [-1, 1] | Organic distortion |
Pipeline plugin (pipeline/plugins/noise.py)
| Function | Purpose |
|---|
find_noise_tool() | Locate forge_noise_tool binary |
run_noise_tool() | Invoke tool as subprocess with CLI args |
generate_noise_textures() | Batch generation from pipeline.toml config |
NoisePlugin.process() | Plugin entry point for pipeline integration |
Server endpoints (pipeline/server.py)
| Endpoint | Method | Purpose |
|---|
/api/generate/noise | POST | Generate full-resolution texture |
/api/generate/noise/preview | GET | Stream a 256×256 BMP preview |
Correct order
Adding a new noise type
- Implement the noise function in
common/math/forge_math.h with full
documentation (parameters, output range, usage example)
- Add tests in
tests/math/test_math.c (determinism, range, edge cases)
- Add a
NOISE_* enum value and parse_type case in tools/noise/main.c
- Add the type to
VALID_TYPES in pipeline/plugins/noise.py
- Add it to the
NOISE_TYPES array in pipeline/web/src/routes/generate/noise.tsx
- Add it to the
NoiseGenerateRequest type dropdown and server endpoint
Setting up noise generation in a project
-
Build the tool: cmake --build build --target forge_noise_tool
-
Add [noise] config to pipeline.toml:
[noise]
noise_enabled = true
output_dir = "generated"
[[noise.textures]]
name = "terrain_height"
type = "fbm"
width = 1024
height = 1024
seed = 42
tiling = true
-
Generate: uv run python -m pipeline generate-noise
-
Or use the web UI: uv run python -m pipeline serve --reload
Seamless tiling
Map 2D coordinates onto a 4D torus — each axis traces a circle in a
separate 2D plane:
float angle_u = u * 2.0f * FORGE_PI;
float angle_v = v * 2.0f * FORGE_PI;
float r = frequency / (2.0f * FORGE_PI);
Normal map derivation
Central differences on the heightmap with wrapping:
float dx = (heightmap[y*w + xp] - heightmap[y*w + xm]) * strength;
float dy = (heightmap[yp*w + x] - heightmap[ym*w + x]) * strength;
Common mistakes
-
Forgetting to normalize output. Perlin/Simplex/fBm return [-1, 1],
ridged returns [0, 1], Worley returns [0, ~1.5]. The tool normalizes via
min/max scan before writing BMP pixels.
-
Tool not found on MSVC. Multi-config generators put binaries in
build/tools/noise/Debug/. The tool_finder.py searches config
subdirectories automatically.
-
Normal map source ordering. In pipeline.toml, the heightmap entry
must appear before the normal map entry that references it (the plugin
processes entries in order).
-
Tiling with Worley noise. The 4D torus approximation works well for
gradient-based noise but can produce visible seams with Worley at low
frequencies. Increase frequency or use fBm/ridged for seamless tiles.
Ready-to-use template
C tool invocation
forge_noise_tool heightmap.bmp fbm \
--width 1024 --height 1024 --seed 42 \
--octaves 6 --frequency 4.0 --persistence 0.5 --tiling
forge_noise_tool normals.bmp fbm \
--width 1024 --height 1024 --seed 42 \
--octaves 6 --frequency 4.0 --normal-map --normal-strength 2.0
Python one-off generation
from pathlib import Path
from pipeline.plugins.noise import find_noise_tool, run_noise_tool
tool = find_noise_tool()
if tool is None:
raise RuntimeError("forge_noise_tool not found — build it first")
run_noise_tool(
Path("output.bmp"), "ridged",
width=512, height=512, seed=42,
frequency=4.0, octaves=6, tiling=True,
tool=tool,
)
Web UI preview URL
import { noisePreviewUrl } from "@/lib/api"
const url = noisePreviewUrl({
noise_type: "worley-edge",
width: 256, height: 256,
seed: 42, frequency: 8.0,
})
Reference