1- import tgpu , { common , d } from 'typegpu' ;
21import { perlin3d } from '@typegpu/noise' ;
2+ import tgpu , { common , d } from 'typegpu' ;
33import { abs , mix , mul , pow , sign , tanh } from 'typegpu/std' ;
44import { defineControls } from '../../common/defineControls.ts' ;
55
66/** The depth of the perlin noise (in time), after which the pattern loops around */
77const DEPTH = 10 ;
88
9- const gridSizeAccess = tgpu [ '~unstable' ] . accessor ( d . f32 ) ;
10- const timeAccess = tgpu [ '~unstable' ] . accessor ( d . f32 ) ;
11- const sharpnessAccess = tgpu [ '~unstable' ] . accessor ( d . f32 ) ;
12-
139const exponentialSharpen = ( n : number , sharpness : number ) : number => {
1410 'use gpu' ;
1511 return sign ( n ) * pow ( abs ( n ) , 1 - sharpness ) ;
@@ -20,30 +16,6 @@ const tanhSharpen = (n: number, sharpness: number): number => {
2016 return tanh ( n * ( 1 + sharpness * 10 ) ) ;
2117} ;
2218
23- const sharpenFnSlot = tgpu . slot < ( n : number , sharpness : number ) => number > (
24- exponentialSharpen ,
25- ) ;
26-
27- const mainFragment = tgpu [ '~unstable' ] . fragmentFn ( {
28- in : { uv : d . vec2f } ,
29- out : d . vec4f ,
30- } ) ( ( input ) => {
31- const uv = mul ( gridSizeAccess . $ , input . uv ) ;
32-
33- const n = perlin3d . sample ( d . vec3f ( uv , timeAccess . $ ) ) ;
34-
35- // Apply sharpening function
36- const sharp = sharpenFnSlot . $ ( n , sharpnessAccess . $ ) ;
37-
38- // Map to 0-1 range
39- const n01 = sharp * 0.5 + 0.5 ;
40-
41- // Gradient map
42- const dark = d . vec3f ( 0 , 0.2 , 1 ) ;
43- const light = d . vec3f ( 1 , 0.3 , 0.5 ) ;
44- return d . vec4f ( mix ( dark , light , n01 ) , 1 ) ;
45- } ) ;
46-
4719// Configuring a dynamic (meaning it's size can change) cache
4820// for perlin noise gradients.
4921const perlinCacheConfig = perlin3d . dynamicCacheConfig ( ) ;
@@ -53,38 +25,46 @@ const dynamicLayout = tgpu.bindGroupLayout({ ...perlinCacheConfig.layout });
5325
5426const root = await tgpu . init ( ) ;
5527
28+ const gridSize = root . createUniform ( d . f32 ) ;
29+ const time = root . createUniform ( d . f32 , 0 ) ;
30+ const sharpness = root . createUniform ( d . f32 , 0.1 ) ;
31+
5632// Instantiating the cache with an initial size.
5733const perlinCache = perlinCacheConfig . instance ( root , d . vec3u ( 4 , 4 , DEPTH ) ) ;
5834
5935const canvas = document . querySelector ( 'canvas' ) as HTMLCanvasElement ;
6036const context = root . configureContext ( { canvas, alphaMode : 'premultiplied' } ) ;
6137const presentationFormat = navigator . gpu . getPreferredCanvasFormat ( ) ;
6238
63- const gridSize = root . createUniform ( d . f32 ) ;
64- const time = root . createUniform ( d . f32 , 0 ) ;
65- const sharpness = root . createUniform ( d . f32 , 0.1 ) ;
66-
67- const renderPipelineBase = root [ '~unstable' ]
68- . with ( gridSizeAccess , gridSize )
69- . with ( timeAccess , time )
70- . with ( sharpnessAccess , sharpness )
71- . pipe ( perlinCacheConfig . inject ( dynamicLayout . $ ) ) ;
72-
73- const renderPipelines = {
74- exponential : renderPipelineBase
75- . with ( sharpenFnSlot , exponentialSharpen )
76- . createRenderPipeline ( {
77- vertex : common . fullScreenTriangle ,
78- fragment : mainFragment ,
79- targets : { format : presentationFormat } ,
80- } ) ,
81- tanh : renderPipelineBase
82- . with ( sharpenFnSlot , tanhSharpen )
39+ const createRenderPipeline = (
40+ sharpenFn : ( n : number , sharpness : number ) => number ,
41+ ) =>
42+ root [ '~unstable' ]
43+ . pipe ( perlinCacheConfig . inject ( dynamicLayout . $ ) )
8344 . createRenderPipeline ( {
8445 vertex : common . fullScreenTriangle ,
85- fragment : mainFragment ,
46+ fragment : ( { uv } ) => {
47+ 'use gpu' ;
48+ const suv = mul ( gridSize . $ , uv ) ;
49+ const n = perlin3d . sample ( d . vec3f ( suv , time . $ ) ) ;
50+
51+ // Apply sharpening function
52+ const sharp = sharpenFn ( n , sharpness . $ ) ;
53+
54+ // Map to 0-1 range
55+ const n01 = sharp * 0.5 + 0.5 ;
56+
57+ // Gradient map
58+ const dark = d . vec3f ( 0 , 0.2 , 1 ) ;
59+ const light = d . vec3f ( 1 , 0.3 , 0.5 ) ;
60+ return d . vec4f ( mix ( dark , light , n01 ) , 1 ) ;
61+ } ,
8662 targets : { format : presentationFormat } ,
87- } ) ,
63+ } ) ;
64+
65+ const renderPipelines = {
66+ exponential : createRenderPipeline ( exponentialSharpen ) ,
67+ tanh : createRenderPipeline ( tanhSharpen ) ,
8868} ;
8969
9070let activeSharpenFn : 'exponential' | 'tanh' = 'exponential' ;
@@ -118,7 +98,7 @@ export const controls = defineControls({
11898 initial : '4' ,
11999 options : [ 1 , 2 , 4 , 8 , 16 , 32 , 64 , 128 , 256 ] . map ( ( x ) => x . toString ( ) ) ,
120100 onSelectChange : ( value : string ) => {
121- const iSize = Number . parseInt ( value ) ;
101+ const iSize = Number . parseInt ( value , 10 ) ;
122102 perlinCache . size = d . vec3u ( iSize , iSize , DEPTH ) ;
123103 gridSize . write ( iSize ) ;
124104 bindGroup = root . createBindGroup ( dynamicLayout , perlinCache . bindings ) ;
0 commit comments