Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
1de9166
Histograms
cieplypolar Aug 7, 2025
7462dfa
Normal, Exp
cieplypolar Aug 11, 2025
2a69945
Work on cauchy
cieplypolar Aug 11, 2025
98dfac7
All continuous
cieplypolar Aug 11, 2025
73a6eef
3d scatter
cieplypolar Aug 12, 2025
e7ae4ea
on unit sphere
cieplypolar Aug 12, 2025
86e10cc
onUnitCube
cieplypolar Aug 13, 2025
d228417
Something
cieplypolar Aug 13, 2025
71c4a0b
Updated docs
cieplypolar Aug 13, 2025
7ec72e8
Restored old pnpm lock file
cieplypolar Aug 13, 2025
f086faa
Restored old pnpm lock file
cieplypolar Aug 13, 2025
f27fdb1
typos
cieplypolar Aug 13, 2025
1912024
Corrected docs
cieplypolar Aug 13, 2025
a6a657a
Skeleton of an example
cieplypolar Aug 14, 2025
60871d5
Nice html layout + camera reset
cieplypolar Aug 14, 2025
450b303
Added tag
cieplypolar Aug 14, 2025
c745a53
Small refactor
cieplypolar Aug 17, 2025
5cbd897
Dont care about 0
cieplypolar Aug 17, 2025
4216899
More refactor
cieplypolar Aug 18, 2025
0b38fff
Histogram plot
cieplypolar Aug 18, 2025
19d8aa6
All plots
cieplypolar Aug 18, 2025
f00de44
thumbnail
cieplypolar Aug 18, 2025
18954d5
Optimized replotting
cieplypolar Aug 19, 2025
04c2d14
Left console.logs
cieplypolar Aug 19, 2025
da6696e
Not working animations
cieplypolar Aug 19, 2025
1659a3a
Merge branch 'main' into feat/uniform01-derivatives
cieplypolar Aug 19, 2025
028ba89
Fixed force reexe
cieplypolar Aug 20, 2025
515d56e
Working transitions!
cieplypolar Aug 20, 2025
70f85c5
Not this bool
cieplypolar Aug 20, 2025
8c5d66b
Fixed seed
cieplypolar Aug 20, 2025
03afea4
Docs update
cieplypolar Aug 20, 2025
2839bfe
Math in docs
cieplypolar Aug 20, 2025
b85304e
Refactor in plotter
cieplypolar Aug 20, 2025
88e6b66
Refactor in plotter
cieplypolar Aug 20, 2025
516ba05
Added controls popup
cieplypolar Aug 21, 2025
e604da9
deno fmt
cieplypolar Aug 21, 2025
37ab92f
Merge branch 'main' into feat/uniform01-derivatives
cieplypolar Aug 21, 2025
6e0cce0
Broken lockfile
cieplypolar Aug 21, 2025
2a29e5b
Merge branch 'main' into feat/uniform01-derivatives
cieplypolar Aug 25, 2025
3fc3050
Example tests alignment
cieplypolar Aug 25, 2025
8763ef6
Some review fixes
cieplypolar Aug 28, 2025
8d2c97c
Merge branch 'main' into feat/uniform01-derivatives
cieplypolar Aug 28, 2025
abc9b2a
rescaling instead of clamping
cieplypolar Aug 29, 2025
1c05a69
Brutal replotFlag
cieplypolar Aug 29, 2025
e5a8dff
Review changes
cieplypolar Aug 29, 2025
3eae7b5
Reseed button and minor changes
cieplypolar Aug 30, 2025
b4f0831
Fix randf.sampleExclusive
cieplypolar Sep 3, 2025
641e621
Bind Group Layouts
cieplypolar Sep 3, 2025
e7d370c
Buffer cache
cieplypolar Sep 3, 2025
5521cb3
Merge branch 'main' into feat/uniform01-derivatives
cieplypolar Sep 3, 2025
4c5bf8e
Pipeline cache
cieplypolar Sep 3, 2025
b2bb9d2
Generator slot docs
cieplypolar Aug 29, 2025
31b9131
more docs
cieplypolar Aug 29, 2025
bcd57b1
Visual uniformity test
cieplypolar Aug 29, 2025
cabf42a
Typos
cieplypolar Sep 3, 2025
553b6ea
Nice uniformity test
cieplypolar Sep 3, 2025
2c70cee
Merge branch 'main' into feat/uniform01-derivatives
cieplypolar Sep 4, 2025
21442d1
Example resolution test
cieplypolar Sep 4, 2025
c739ecd
Merge branch 'feat/uniform01-derivatives' into docs/generator-slot
cieplypolar Sep 4, 2025
a751ae7
More controls and thumbnail
cieplypolar Sep 4, 2025
63ebd3e
Resolution test
cieplypolar Sep 4, 2025
df71137
final polish
cieplypolar Sep 5, 2025
19acd22
Merge branch 'main' into docs/generator-slot
cieplypolar Sep 25, 2025
6b0aff3
Broken pnpm-lock
cieplypolar Sep 25, 2025
a433a0a
Merge branch 'main' into docs/generator-slot
cieplypolar Sep 29, 2025
9e34138
nits
cieplypolar Sep 29, 2025
c89dc3b
typo
cieplypolar Sep 29, 2025
8c9a9a9
shellless
cieplypolar Sep 29, 2025
6c3ca10
Merge branch 'main' into docs/generator-slot
cieplypolar Sep 29, 2025
339309a
optional seeds
cieplypolar Sep 30, 2025
d2b47b3
Merge branch 'main' into docs/generator-slot
cieplypolar Sep 30, 2025
e693bd8
Merge branch 'main' into docs/generator-slot
cieplypolar Sep 30, 2025
a6bf42a
Merge branch 'main' into docs/generator-slot
cieplypolar Oct 1, 2025
3f112be
more descriptive function name
cieplypolar Oct 1, 2025
eb33788
Fix example test
cieplypolar Oct 2, 2025
23e8f7d
Merge branch 'main' into docs/generator-slot
cieplypolar Oct 2, 2025
a08f37d
Merge branch 'main' into docs/generator-slot
cieplypolar Oct 8, 2025
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
57 changes: 56 additions & 1 deletion apps/typegpu-docs/src/content/docs/ecosystem/typegpu-noise.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ It also features a [Perlin noise](#perlin-noise) implementation, which is useful
effects, terrains, and other procedural elements.

:::note
Threads do not share the generator's `State`. As a result, unless you change the seed or provide thread-dependent variables, each thread will produce the same sequence of sampled values.
Threads do not share the generator's `State`. As a result, unless you change the seed in each thread, each thread will produce the same sequence of sampled values.
:::

## Use with either TypeGPU or WebGPU
Expand Down Expand Up @@ -267,3 +267,58 @@ pipeline
// a different domain size
bindGroup = initBindGroup(d.vec3u(5, 5, 1));
```

## Generator slot
The package provides convenient way to change PRNG as needed.
You can easily implement your own PRNG and plug it into the pipeline.

```ts twoslash
import tgpu from 'typegpu';
import * as d from 'typegpu/data';
import { randf } from '@typegpu/noise';
import * as std from 'typegpu/std';

const root = await tgpu.init();

const b = root.createMutable(d.f32);
const f = tgpu['~unstable'].computeFn({ workgroupSize: [1] })(() => {
b.$ = randf.sample();
});
// ---cut---
import {
randomGeneratorSlot,
type StatefulGenerator,
} from '@typegpu/noise';

export const LCG: StatefulGenerator = (() => {
const seed = tgpu.privateVar(d.u32);

const u32To01Float = tgpu.fn([d.u32], d.f32)`(val){
let exponent: u32 = 0x3f800000;
let mantissa: u32 = 0x007fffff & val;
var ufloat: u32 = (exponent | mantissa);
return bitcast<f32>(ufloat) - 1f;
}`;

return {
seed: (value: number) => {
'kernel';
seed.$ = d.u32(value * std.pow(32, 3));
},
seed2: (value: d.v2f) => {
'kernel';
seed.$ = d.u32(value.x * std.pow(32, 3) + value.y * std.pow(32, 2));
},
sample: () => {
'kernel';
seed.$ = seed.$ * 1664525 + 1013904223; // % 2 ^ 32
return u32To01Float(seed.$);
},
};
})();

const pipeline = root['~unstable']
.with(randomGeneratorSlot, LCG)
.withCompute(f)
.createPipeline();
```
6 changes: 6 additions & 0 deletions apps/typegpu-docs/src/examples/tests/uniformity/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { PRNG } from './prngs.ts';

export const gridSizes = [10, 25, 50, 100, 200, 500, 700, 1000];
export const initialGridSize = gridSizes[3];
export const initialPRNG = PRNG.BPETER;
export const prngs: PRNG[] = Object.values(PRNG);
21 changes: 21 additions & 0 deletions apps/typegpu-docs/src/examples/tests/uniformity/fragment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import tgpu from 'typegpu';
import type { TgpuUniform } from 'typegpu';
import * as d from 'typegpu/data';
import * as std from 'typegpu/std';
import { randf } from '@typegpu/noise';

export const bindFullScreenGridFSWithUniforms = (
gridSizeUniform: TgpuUniform<d.F32>,
canvasRatioUniform: TgpuUniform<d.F32>,
) =>
tgpu['~unstable'].fragmentFn({
in: { uv: d.vec2f },
out: d.vec4f,
})((input) => {
const uv = input.uv.add(1).div(2).mul(d.vec2f(canvasRatioUniform.$, 1));
const gridedUV = std.floor(uv.mul(gridSizeUniform.$));

randf.seed2(gridedUV);

return d.vec4f(d.vec3f(randf.sample()), 1.0);
});
37 changes: 37 additions & 0 deletions apps/typegpu-docs/src/examples/tests/uniformity/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import type { TgpuRenderPipeline, TgpuRoot, TgpuUniform } from 'typegpu';
import { randomGeneratorSlot } from '@typegpu/noise';
import type * as d from 'typegpu/data';

import { fullScreenTriangleVertexShader } from './vertex.ts';
import { bindFullScreenGridFSWithUniforms } from './fragment.ts';
import { getPRNG, type PRNG } from './prngs.ts';

export const preparePipeline = (
root: TgpuRoot,
presentationFormat: GPUTextureFormat,
prng: PRNG,
gridSizeUniform: TgpuUniform<d.F32>,
canvasRatioUniform: TgpuUniform<d.F32>,
): TgpuRenderPipeline =>
root['~unstable']
.with(randomGeneratorSlot, getPRNG(prng))
.withVertex(fullScreenTriangleVertexShader, {})
.withFragment(
bindFullScreenGridFSWithUniforms(gridSizeUniform, canvasRatioUniform),
{
format: presentationFormat,
},
)
.createPipeline();

export const executePipeline = (
pipeline: TgpuRenderPipeline,
context: GPUCanvasContext,
) =>
pipeline
.withColorAttachment({
view: context.getCurrentTexture().createView(),
loadOp: 'clear',
storeOp: 'store',
})
.draw(3);
1 change: 1 addition & 0 deletions apps/typegpu-docs/src/examples/tests/uniformity/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<canvas data-fit-to-container></canvas>
94 changes: 94 additions & 0 deletions apps/typegpu-docs/src/examples/tests/uniformity/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import tgpu, { type TgpuRenderPipeline } from 'typegpu';
import * as d from 'typegpu/data';

import * as c from './constants.ts';
import type { PRNG } from './prngs.ts';
import { executePipeline, preparePipeline } from './helpers.ts';

const root = await tgpu.init();

const canvas = document.querySelector('canvas') as HTMLCanvasElement;
const context = canvas.getContext('webgpu') as GPUCanvasContext;
const presentationFormat = navigator.gpu.getPreferredCanvasFormat();
context.configure({
device: root.device,
format: presentationFormat,
alphaMode: 'premultiplied',
});

const gridSizeUniform = root.createUniform(d.f32, c.initialGridSize);
const canvasRatioUniform = root.createUniform(
d.f32,
canvas.width / canvas.height,
);
const pipelineCache = new Map<PRNG, TgpuRenderPipeline>();
let prng: PRNG = c.initialPRNG;

const redraw = (value: PRNG) => {
let pipeline = undefined;
if (!pipelineCache.has(value)) {
pipeline = preparePipeline(
root,
presentationFormat,
value,
gridSizeUniform,
canvasRatioUniform,
);
pipelineCache.set(value, pipeline);
} else {
pipeline = pipelineCache.get(value);
}
executePipeline(pipeline as TgpuRenderPipeline, context);
};

// #region Example controls & Cleanup
export const controls = {
'PRNG': {
initial: c.initialPRNG,
options: c.prngs,
onSelectChange: (value: PRNG) => {
prng = value;
redraw(value);
},
},
'Grid Size': {
initial: c.initialGridSize,
options: c.gridSizes,
onSelectChange: (value: number) => {
gridSizeUniform.write(value);
redraw(prng);
},
},
'Test Resolution': import.meta.env.DEV && {
onButtonClick: () => {
c.prngs
.map((prng) =>
tgpu.resolve({
externals: {
f: preparePipeline(
root,
presentationFormat,
prng,
gridSizeUniform,
canvasRatioUniform,
),
},
})
)
.map((r) => root.device.createShaderModule({ code: r }));
},
},
};

const resizeObserver = new ResizeObserver(() => {
canvasRatioUniform.write(canvas.width / canvas.height);
redraw(prng);
});
resizeObserver.observe(canvas);

export function onCleanup() {
resizeObserver.disconnect();
root.destroy();
}

// #endregion
31 changes: 31 additions & 0 deletions apps/typegpu-docs/src/examples/tests/uniformity/lcg.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import tgpu from 'typegpu';
import * as d from 'typegpu/data';
import * as std from 'typegpu/std';
import type { StatefulGenerator } from '@typegpu/noise';

export const LCG: StatefulGenerator = (() => {
const seed = tgpu.privateVar(d.u32);

const u32To01Float = tgpu.fn([d.u32], d.f32)`(val){
let exponent: u32 = 0x3f800000;
let mantissa: u32 = 0x007fffff & val;
var ufloat: u32 = (exponent | mantissa);
return bitcast<f32>(ufloat) - 1f;
}`;

return {
seed: (value: number) => {
'kernel';
seed.$ = d.u32(value * std.pow(32, 3));
},
seed2: (value: d.v2f) => {
'kernel';
seed.$ = d.u32(value.x * std.pow(32, 3) + value.y * std.pow(32, 2));
},
sample: () => {
'kernel';
seed.$ = seed.$ * 1664525 + 1013904223; // % 2 ^ 32
return u32To01Float(seed.$);
},
};
})();
6 changes: 6 additions & 0 deletions apps/typegpu-docs/src/examples/tests/uniformity/meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"title": "Uniformity",
"category": "tests",
"tags": ["experimental"],
"dev": true
}
17 changes: 17 additions & 0 deletions apps/typegpu-docs/src/examples/tests/uniformity/prngs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { BPETER, type StatefulGenerator } from '@typegpu/noise';

import { LCG } from './lcg.ts';

export const PRNG = {
BPETER: 'bpeter (default)',
LCG: 'lcg',
} as const;

export type PRNG = typeof PRNG[keyof typeof PRNG];

const PRNG_MAP = {
[PRNG.BPETER]: BPETER,
[PRNG.LCG]: LCG,
};

export const getPRNG = (prng: PRNG): StatefulGenerator => PRNG_MAP[prng];
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions apps/typegpu-docs/src/examples/tests/uniformity/vertex.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import tgpu from 'typegpu';
import * as d from 'typegpu/data';

export const fullScreenTriangleVertexShader = tgpu['~unstable'].vertexFn({
in: { vertexIndex: d.builtin.vertexIndex },
out: { pos: d.builtin.position, uv: d.vec2f },
})((input) => {
const pos = [d.vec2f(-1, -1), d.vec2f(3, -1), d.vec2f(-1, 3)];

return {
pos: d.vec4f(pos[input.vertexIndex], 0.0, 1.0),
uv: pos[input.vertexIndex],
};
});
10 changes: 5 additions & 5 deletions packages/typegpu-noise/src/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import * as d from 'typegpu/data';
import { add, cos, dot, fract } from 'typegpu/std';

export interface StatefulGenerator {
seed: TgpuFn<(seed: d.F32) => d.Void>;
seed2: TgpuFn<(seed: d.Vec2f) => d.Void>;
seed3: TgpuFn<(seed: d.Vec3f) => d.Void>;
seed4: TgpuFn<(seed: d.Vec4f) => d.Void>;
sample: TgpuFn<() => d.F32>;
seed: TgpuFn<(seed: d.F32) => d.Void> | ((seed: number) => void);
seed2?: TgpuFn<(seed: d.Vec2f) => d.Void> | ((seed: d.v2f) => void);
seed3?: TgpuFn<(seed: d.Vec3f) => d.Void> | ((seed: d.v3f) => void);
seed4?: TgpuFn<(seed: d.Vec4f) => d.Void> | ((seed: d.v4f) => void);
sample: TgpuFn<() => d.F32> | (() => number);
}

export const randomGeneratorShell: TgpuFnShell<[], d.F32> = tgpu.fn([], d.f32);
Expand Down
Loading