Tri-Noise 3D

Triangle-wave 3D noise (WGSL + CPU)

Quick Start

import { triNoise3DWGSL, triNoise3D } from './webgpu-market/tri-noise-3d/tri-noise-3d';

// In a shader — prepend the WGSL source
const shader = triNoise3DWGSL + `
  @fragment fn main(@location(0) uv: vec2f) -> @location(0) vec4f {
      let value = triNoise3D(vec3f(uv * 4.0, 0.0), time);
      return vec4f(vec3f(value), 1.0);
  }
`;

// On the CPU — same function, same output
const value = triNoise3D([x, y, z], elapsed);
Source
// Triangle-wave 3D noise
// Ported from https://github.com/cabbibo/glsl-tri-noise-3d
// Returns a value roughly in [0, 1].

fn tri(x: f32) -> f32 {
    return abs(fract(x) - 0.5);
}

fn tri3(p: vec3f) -> vec3f {
    return vec3f(
        tri(p.z + tri(p.y)),
        tri(p.z + tri(p.x)),
        tri(p.y + tri(p.x))
    );
}

// position : 3D sample point
// t        : time offset for animation
fn triNoise3D(position: vec3f, t: f32) -> f32 {
    var p  = position;
    var z  = 1.4;
    var rz = 0.0;
    var bp = position;

    for (var i = 0; i <= 3; i++) {
        let dg = tri3(bp * 2.0);
        p  = p  + dg + vec3f(t * 0.1);
        bp = bp * 1.8;
        z  = z  * 1.5;
        p  = p  * 1.2;

        let s = tri(p.z + tri(p.x + tri(p.y)));
        rz = rz + s / z;
        bp = bp + vec3f(0.14);
    }

    return rz;
}
Documentation

tri-noise-3d

Triangle-wave 3D noise — a WGSL function you embed in your own shader, plus a matching CPU/TypeScript implementation that produces the same values.

API

triNoise3DWGSL: string

Raw WGSL source defining three functions: tri, tri3, and triNoise3D. Paste or concatenate this into your shader module.

triNoise3D(position, time): number

CPU implementation. Returns a noise value roughly in [0, 1].

  • position[x, y, z] sample point
  • time — Time offset for animation
Further Reading

Further Reading

Rationale

Not all noise needs to be Perlin or Simplex. Triangle-wave noise produces a distinct organic, rippling quality — less "cloudy" than classic gradient noise, more like flowing liquid or heat distortion. It's cheap to compute (no gradient lookups or permutation tables) and works well for animated displacement, water caustics, and abstract procedural textures.

Original Source

How It Works

The algorithm composes triangle waves (abs(fract(x) - 0.5)) in 3D across multiple octaves. Each octave:

  1. Samples a triangle wave of the current position, feeding each axis into the next (creating cross-axis dependency).
  2. Adds a time-based offset for animation.
  3. Scales the position up (increasing frequency) and scales the contribution down (decreasing amplitude).

This produces fractal-like detail without any hash tables or gradient vectors — just fract, abs, and arithmetic.

Further Learning

  • The Book of Shaders: Noise — Patricio Gonzalez Vivo's chapter on noise covers the design space beyond Perlin/Simplex, including wave-based approaches. https://thebookofshaders.com/11/
  • Inigo Quilez: Useful Little Functions — A collection of small mathematical building blocks for procedural graphics, including triangle wave patterns. https://iquilezles.org/articles/functions/