@@ -21,15 +21,10 @@ const context = root.configureContext({ canvas, alphaMode: 'premultiplied' });
2121
2222// data types
2323
24- const VertexOutput = {
25- position : d . builtin . position ,
26- color : d . vec4f ,
27- } ;
28-
2924const ParticleGeometry = d . struct ( {
25+ color : d . vec4f ,
3026 tilt : d . f32 ,
3127 angle : d . f32 ,
32- color : d . vec4f ,
3328} ) ;
3429
3530const ParticleData = d . struct ( {
@@ -43,120 +38,80 @@ const ParticleData = d.struct({
4338const particleGeometryBuffer = root
4439 . createBuffer (
4540 d . arrayOf ( ParticleGeometry , PARTICLE_AMOUNT ) ,
46- Array ( PARTICLE_AMOUNT )
47- . fill ( 0 )
48- . map ( ( ) => ( {
49- angle : Math . floor ( Math . random ( ) * 50 ) - 10 ,
50- tilt : Math . floor ( Math . random ( ) * 10 ) - 10 - 10 ,
51- color : COLOR_PALETTE [ Math . floor ( Math . random ( ) * COLOR_PALETTE . length ) ] ,
52- } ) ) ,
41+ Array . from ( { length : PARTICLE_AMOUNT } , ( ) => ( {
42+ color : COLOR_PALETTE [ Math . floor ( Math . random ( ) * COLOR_PALETTE . length ) ] ,
43+ tilt : Math . floor ( Math . random ( ) * 10 ) - 10 - 10 ,
44+ angle : Math . floor ( Math . random ( ) * 50 ) - 10 ,
45+ } ) ) ,
5346 )
5447 . $usage ( 'vertex' ) ;
5548
5649const particleDataBuffer = root
5750 . createBuffer ( d . arrayOf ( ParticleData , PARTICLE_AMOUNT ) )
5851 . $usage ( 'storage' , 'uniform' , 'vertex' ) ;
5952
53+ let elapsedTime = 0 ;
6054const aspectRatio = root . createUniform ( d . f32 , canvas . width / canvas . height ) ;
6155const deltaTime = root . createUniform ( d . f32 ) ;
62- const time = root . createMutable ( d . f32 ) ;
56+ const time = root . createUniform ( d . f32 ) ;
6357
6458const particleDataStorage = particleDataBuffer . as ( 'mutable' ) ;
6559
6660// layouts
6761
6862const geometryLayout = tgpu . vertexLayout ( d . arrayOf ( ParticleGeometry ) , 'instance' ) ;
69-
7063const dataLayout = tgpu . vertexLayout ( d . arrayOf ( ParticleData ) , 'instance' ) ;
7164
7265// functions
7366
74- const rotate = tgpu . fn (
75- [ d . vec2f , d . f32 ] ,
76- d . vec2f ,
77- ) ( ( v , angle ) => {
78- const pos = d . vec2f (
67+ const rotate = ( v : d . v2f , angle : number ) => {
68+ 'use gpu' ;
69+ return d . vec2f (
7970 v . x * std . cos ( angle ) - v . y * std . sin ( angle ) ,
8071 v . x * std . sin ( angle ) + v . y * std . cos ( angle ) ,
8172 ) ;
82-
83- return pos ;
84- } ) ;
85-
86- const mainVert = tgpu . vertexFn ( {
87- in : {
88- tilt : d . f32 ,
89- angle : d . f32 ,
90- color : d . vec4f ,
91- center : d . vec2f ,
92- index : d . builtin . vertexIndex ,
93- } ,
94- out : VertexOutput ,
95- } ) /* wgsl */ `{
96- let width = in.tilt;
97- let height = in.tilt / 2;
98-
99- var pos = rotate(array<vec2f, 4>(
100- vec2f(0, 0),
101- vec2f(width, 0),
102- vec2f(0, height),
103- vec2f(width, height),
104- )[in.index] / 350, in.angle) + in.center;
105-
106- if (aspectRatio < 1) {
107- pos.x /= aspectRatio;
108- } else {
109- pos.y *= aspectRatio;
110- }
111-
112- return Out(vec4f(pos, 0.0, 1.0), in.color);
113- }` . $uses ( {
114- rotate,
115- aspectRatio,
116- } ) ;
117-
118- const mainFrag = tgpu . fragmentFn ( {
119- in : VertexOutput ,
120- out : d . vec4f ,
121- } ) /* wgsl */ `{ return in.color; }` ;
122-
123- const mainCompute = tgpu . computeFn ( {
124- in : { gid : d . builtin . globalInvocationId } ,
125- workgroupSize : [ 1 ] ,
126- } ) /* wgsl */ `{
127- let index = in.gid.x;
128- if index == 0 {
129- time += deltaTime;
130- }
131- let phase = (time / 300) + particleData[index].seed;
132- particleData[index].position += particleData[index].velocity * deltaTime / 20 + vec2f(sin(phase) / 600, cos(phase) / 500);
133- }` . $uses ( {
134- particleData : particleDataStorage ,
135- deltaTime,
136- time,
137- } ) ;
73+ } ;
13874
13975// pipelines
14076
14177const renderPipeline = root
14278 . createRenderPipeline ( {
143- vertex : mainVert ,
144- fragment : mainFrag ,
14579 attribs : {
146- tilt : geometryLayout . attrib . tilt ,
147- angle : geometryLayout . attrib . angle ,
148- color : geometryLayout . attrib . color ,
80+ ...geometryLayout . attrib ,
14981 center : dataLayout . attrib . position ,
15082 } ,
83+ vertex : ( { tilt, angle, color, center, $vertexIndex } ) => {
84+ 'use gpu' ;
85+ const width = tilt / 350 ;
86+ const height = width / 2 ;
87+
88+ const local = [ d . vec2f ( 0 , 0 ) , d . vec2f ( width , 0 ) , d . vec2f ( 0 , height ) , d . vec2f ( width , height ) ] ;
89+ const pos = rotate ( local [ $vertexIndex ] , angle ) + center ;
90+
91+ if ( aspectRatio . $ < 1 ) {
92+ pos . x /= aspectRatio . $ ;
93+ } else {
94+ pos . y *= aspectRatio . $ ;
95+ }
15196
152- primitive : {
153- topology : 'triangle-strip' ,
97+ return { $position : d . vec4f ( pos , 0 , 1 ) , color } ;
15498 } ,
99+ fragment : ( { color } ) => {
100+ 'use gpu' ;
101+ return color ;
102+ } ,
103+ primitive : { topology : 'triangle-strip' } ,
155104 } )
156105 . with ( geometryLayout , particleGeometryBuffer )
157106 . with ( dataLayout , particleDataBuffer ) ;
158107
159- const computePipeline = root . createComputePipeline ( { compute : mainCompute } ) ;
108+ const computePipeline = root . createGuardedComputePipeline ( ( index ) => {
109+ 'use gpu' ;
110+ const phase = time . $ / 300 + particleDataStorage . $ [ index ] . seed ;
111+ particleDataStorage . $ [ index ] . position +=
112+ ( particleDataStorage . $ [ index ] . velocity * deltaTime . $ ) / 20 +
113+ d . vec2f ( std . sin ( phase ) / 600 , std . cos ( phase ) / 500 ) ;
114+ } ) ;
160115
161116// compute and draw
162117
@@ -192,11 +147,15 @@ function onFrame(loop: (deltaTime: number) => unknown) {
192147}
193148
194149onFrame ( ( dt ) => {
150+ elapsedTime += dt ;
151+ time . write ( elapsedTime ) ;
195152 deltaTime . write ( dt ) ;
196153 aspectRatio . write ( canvas . width / canvas . height ) ;
197154
198- computePipeline . dispatchWorkgroups ( PARTICLE_AMOUNT ) ;
155+ // Simulating the physics
156+ computePipeline . dispatchThreads ( PARTICLE_AMOUNT ) ;
199157
158+ // Drawing the particles
200159 renderPipeline . withColorAttachment ( { view : context } ) . draw ( 4 , PARTICLE_AMOUNT ) ;
201160} ) ;
202161
0 commit comments