Skip to content

Commit 5e75248

Browse files
authored
docs: Ripple cube (#2151)
1 parent 226e90a commit 5e75248

11 files changed

Lines changed: 1806 additions & 0 deletions

File tree

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
import { perlin3d, randf } from '@typegpu/noise';
2+
import type { TgpuRoot, TgpuTextureView } from 'typegpu';
3+
import tgpu, { d, std } from 'typegpu';
4+
import { CUBEMAP_SIZE } from './constants.ts';
5+
6+
const spaceNebula = (rd: d.v3f): d.v3f => {
7+
'use gpu';
8+
const n1 = perlin3d.sample(rd.mul(1.2)) * 0.5 + 0.5;
9+
const n2 = perlin3d.sample(rd.mul(2.5).add(50)) * 0.5 + 0.5;
10+
const n3 = perlin3d.sample(rd.mul(5).add(150)) * 0.5 + 0.5;
11+
const n4 = perlin3d.sample(rd.mul(0.8).add(300)) * 0.5 + 0.5;
12+
const colorShift = perlin3d.sample(rd.mul(0.5).add(500)) * 0.5 + 0.5;
13+
14+
const purple = d.vec3f(0.6, 0.1, 0.8).mul(n1 ** 1.8 * 0.5);
15+
const blue = d.vec3f(0.1, 0.3, 0.7).mul(n2 ** 2 * 0.4);
16+
const cyan = d.vec3f(0.1, 0.6, 0.6).mul((n3 * n4) ** 1.5 * 0.3);
17+
const pink = d.vec3f(0.7, 0.2, 0.4).mul((1 - n1) ** 3 * n2 * 0.4);
18+
const gold = d.vec3f(0.8, 0.5, 0.1).mul((n2 * n3) ** 3 * 0.6);
19+
20+
let color = d
21+
.vec3f(0.01, 0.01, 0.03)
22+
.add(std.mix(purple, blue, colorShift))
23+
.add(std.mix(pink, cyan, n4))
24+
.add(gold);
25+
26+
color = color.add(
27+
std
28+
.mix(d.vec3f(0.8, 0.4, 1), d.vec3f(0.4, 0.8, 1), colorShift)
29+
.mul((n1 * n2 * n3) ** 4 * 2),
30+
);
31+
32+
return color;
33+
};
34+
35+
export const spaceBackground = (rd: d.v3f): d.v3f => {
36+
'use gpu';
37+
let color = spaceNebula(rd);
38+
39+
// Small stars
40+
const starPos = rd.mul(50);
41+
randf.seed3(std.floor(starPos));
42+
const starCenter = d
43+
.vec3f(randf.sample(), randf.sample(), randf.sample())
44+
.mul(0.6)
45+
.add(0.2);
46+
const starDist = std.length(std.fract(starPos).sub(starCenter));
47+
const starHash = randf.sample();
48+
color = color.add(
49+
std
50+
.mix(d.vec3f(1, 0.9, 0.8), d.vec3f(0.8, 0.9, 1), starHash)
51+
.mul(std.max(1 - starDist * 4, 0) ** 4 * std.step(0.85, starHash) * 3),
52+
);
53+
54+
// Big stars
55+
const bigStarPos = rd.mul(20);
56+
randf.seed3(std.floor(bigStarPos));
57+
const bigStarCenter = d
58+
.vec3f(randf.sample(), randf.sample(), randf.sample())
59+
.mul(0.5)
60+
.add(0.25);
61+
const bigStarDist = std.length(std.fract(bigStarPos).sub(bigStarCenter));
62+
color = color.add(
63+
d
64+
.vec3f(1, 0.95, 0.9)
65+
.mul(
66+
std.max(1 - bigStarDist * 3, 0) ** 3 * std.step(0.95, randf.sample()) *
67+
8,
68+
),
69+
);
70+
71+
return color;
72+
};
73+
74+
const CUBEMAP_FACES = [
75+
{
76+
forward: d.vec3f(1, 0, 0),
77+
right: d.vec3f(0, 0, -1),
78+
up: d.vec3f(0, -1, 0),
79+
},
80+
{
81+
forward: d.vec3f(-1, 0, 0),
82+
right: d.vec3f(0, 0, 1),
83+
up: d.vec3f(0, -1, 0),
84+
},
85+
{
86+
forward: d.vec3f(0, 1, 0),
87+
right: d.vec3f(1, 0, 0),
88+
up: d.vec3f(0, 0, 1),
89+
},
90+
{
91+
forward: d.vec3f(0, -1, 0),
92+
right: d.vec3f(1, 0, 0),
93+
up: d.vec3f(0, 0, -1),
94+
},
95+
{
96+
forward: d.vec3f(0, 0, 1),
97+
right: d.vec3f(1, 0, 0),
98+
up: d.vec3f(0, -1, 0),
99+
},
100+
{
101+
forward: d.vec3f(0, 0, -1),
102+
right: d.vec3f(-1, 0, 0),
103+
up: d.vec3f(0, -1, 0),
104+
},
105+
] as const;
106+
107+
export interface BackgroundCubemap {
108+
view: TgpuTextureView<d.WgslTextureCube<d.F32>>;
109+
}
110+
111+
export function createBackgroundCubemap(root: TgpuRoot): BackgroundCubemap {
112+
const texture = root['~unstable']
113+
.createTexture({
114+
size: [CUBEMAP_SIZE, CUBEMAP_SIZE, 6],
115+
format: 'rgba16float',
116+
})
117+
.$usage('storage', 'sampled');
118+
119+
const perlinCache = perlin3d.staticCache({
120+
root,
121+
size: d.vec3u(128, 128, 128),
122+
});
123+
124+
const faceOutputLayout = tgpu.bindGroupLayout({
125+
outputTexture: { storageTexture: d.textureStorage2d('rgba16float') },
126+
});
127+
128+
const FaceBasis = d.struct({ forward: d.vec3f, right: d.vec3f, up: d.vec3f });
129+
const faceBasisUniform = root.createUniform(FaceBasis);
130+
131+
const renderFacePipeline = root['~unstable']
132+
.pipe(perlinCache.inject())
133+
.createGuardedComputePipeline((x, y) => {
134+
'use gpu';
135+
const u = ((d.f32(x) + 0.5) / CUBEMAP_SIZE) * 2 - 1;
136+
const v = ((d.f32(y) + 0.5) / CUBEMAP_SIZE) * 2 - 1;
137+
const basis = faceBasisUniform.$;
138+
139+
const direction = std.normalize(
140+
basis.forward.add(basis.right.mul(u)).add(basis.up.mul(v)),
141+
);
142+
143+
const color = spaceBackground(direction);
144+
145+
std.textureStore(
146+
faceOutputLayout.$.outputTexture,
147+
d.vec2u(x, y),
148+
d.vec4f(color, 1),
149+
);
150+
});
151+
152+
for (let face = 0; face < 6; face++) {
153+
faceBasisUniform.write(CUBEMAP_FACES[face]);
154+
155+
const faceView = texture.createView(d.textureStorage2d('rgba16float'), {
156+
baseArrayLayer: face,
157+
arrayLayerCount: 1,
158+
baseMipLevel: 0,
159+
mipLevelCount: 1,
160+
});
161+
162+
const faceBindGroup = root.createBindGroup(faceOutputLayout, {
163+
outputTexture: faceView,
164+
});
165+
166+
renderFacePipeline
167+
.with(faceBindGroup)
168+
.dispatchThreads(CUBEMAP_SIZE, CUBEMAP_SIZE);
169+
}
170+
171+
perlinCache.destroy();
172+
173+
const view = texture.createView(d.textureCube(d.f32));
174+
175+
return { view };
176+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
export const MAX_STEPS = 48;
2+
export const MAX_DIST = 5;
3+
export const SURF_DIST = 0.001;
4+
export const PI = Math.PI;
5+
export const LIGHT_COUNT = 2;
6+
export const BLUR_RADIUS = 8;
7+
export const TAA_BLEND = 0.85;
8+
9+
export const CUBEMAP_SIZE = 1024;
10+
export const GRID_SIZE = 212;
11+
12+
export function halton(index: number, base: number): number {
13+
let result = 0;
14+
let f = 1 / base;
15+
let i = index;
16+
while (i > 0) {
17+
result += f * (i % base);
18+
i = Math.floor(i / base);
19+
f /= base;
20+
}
21+
return result;
22+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<canvas></canvas>

0 commit comments

Comments
 (0)