1- struct Particle {
2- position : vec3 <f32 >,
3- padding1 : f32 ,
4- velocity : vec3 <f32 >,
5- padding2 : f32 ,
6- color : vec4 <f32 >,
1+ struct ParticleInput {
2+ @ location ( 0 ) position : vec3 <f32 >,
3+ @ location ( 1 ) padding1 : f32 ,
4+ @ location ( 2 ) velocity : vec3 <f32 >,
5+ @ location ( 3 ) padding2 : f32 ,
6+ @ location ( 4 ) color : vec4 <f32 >,
77};
88
9+ // Output structure matching the Particle struct layout for TF capture
10+ struct ParticleOutput {
11+ @location (0 ) out_position : vec3 <f32 >,
12+ @location (1 ) out_padding1 : f32 ,
13+ @location (2 ) out_velocity : vec3 <f32 >,
14+ @location (3 ) out_padding2 : f32 ,
15+ @location (4 ) out_color : vec4 <f32 >,
16+ // We still need a dummy @builtin(position) for the rasterizer, even if TF is active
17+ @builtin (position ) clip_position : vec4 <f32 >,
18+ };
19+
20+ // Uniforms (same as compute shader)
921struct SimParams {
22+ // First 16 bytes
1023 delta_time : f32 ,
1124 gravity : f32 ,
1225 color_mode : u32 ,
1326 mouse_force : f32 ,
27+
28+ // Second 16 bytes
1429 mouse_radius : f32 ,
15- mouse_position : vec3 <f32 >,
1630 is_mouse_dragging : u32 ,
1731 damping : f32 ,
18- };
19-
20- @group (0 ) @binding (0 )
21- var <storage , read > particles_in : array <Particle >;
22-
23- @group (0 ) @binding (1 )
24- var <uniform > params : SimParams ;
25-
26- @group (0 ) @binding (2 )
27- var <storage , read_write > particles_out : array <Particle >;
32+ _padding1 : u32 , // Ensure correct padding for std140/std430 alignment
2833
29- struct VertexOutput {
30- @builtin (position ) position : vec4 <f32 >,
34+ // Last 16 bytes
35+ mouse_position : vec3 <f32 >,
36+ _padding2 : u32 , // Ensure correct padding
3137};
3238
39+ @group (0 ) @binding (0 ) var <uniform > params : SimParams ;
40+
3341@vertex
34- fn vs_main (@builtin (vertex_index ) vertex_index : u32 ) -> VertexOutput {
35- var output : VertexOutput ;
42+ fn vs_main (particle_in : ParticleInput ) -> ParticleOutput {
43+
44+ // --- Simulation Logic (using particle_in) ---
45+ var new_velocity = particle_in . velocity ;
46+ var new_position = particle_in . position ;
47+ var new_color = particle_in . color ;
48+
49+ // Apply gravity
50+ new_velocity . y -= params . gravity * params . delta_time ;
51+
52+ // Apply mouse force
53+ if (params . is_mouse_dragging > 0u ) {
54+ let dir = params . mouse_position - new_position ;
55+ let dist = length (dir );
56+
57+ if (dist < params . mouse_radius * 2 .0 ) {
58+ // Make the force stronger overall and more dramatic for closer particles
59+ let force_factor = pow (1 .0 - dist / (params . mouse_radius * 2 .0 ), 2 .0 ) * 2 .0 ;
60+ let force = normalize (dir ) * params . mouse_force * force_factor ;
61+ new_velocity += force * params . delta_time ;
62+ }
63+ }
3664
37- // Get current particle
38- var particle = particles_in [vertex_index ];
65+ // Update position
66+ new_position += new_velocity * params . delta_time ;
67+
68+ // Handle boundaries
69+ let bounds = 500 .0 ;
70+ if (new_position . x < - bounds ) {
71+ new_position . x = - bounds ;
72+ new_velocity . x = abs (new_velocity . x ) * 0 .5 ;
73+ } else if (new_position . x > bounds ) {
74+ new_position . x = bounds ;
75+ new_velocity . x = - abs (new_velocity . x ) * 0 .5 ;
76+ }
77+ // ... (repeat for y and z boundaries) ...
78+ if (new_position . y < - bounds ) {
79+ new_position . y = - bounds ;
80+ new_velocity . y = abs (new_velocity . y ) * 0 .5 ;
81+ } else if (new_position . y > bounds ) {
82+ new_position . y = bounds ;
83+ new_velocity . y = - abs (new_velocity . y ) * 0 .5 ;
84+ }
85+ if (new_position . z < - bounds ) {
86+ new_position . z = - bounds ;
87+ new_velocity . z = abs (new_velocity . z ) * 0 .5 ;
88+ } else if (new_position . z > bounds ) {
89+ new_position . z = bounds ;
90+ new_velocity . z = - abs (new_velocity . z ) * 0 .5 ;
91+ }
3992
40- // Apply gravity
41- particle . velocity . y -= params . gravity * params . delta_time ;
4293
43- // Apply mouse force (same as compute shader)
44- if (params . is_mouse_dragging > 0u ) {
45- let dir = params . mouse_position - particle . position ;
46- let dist = length (dir );
94+ // Apply damping
95+ new_velocity *= params . damping ;
4796
48- if (dist < params . mouse_radius * 2 .0 ) {
49- let force_factor = pow (1 .0 - dist / (params . mouse_radius * 2 .0 ), 2 .0 ) * 2 .0 ;
50- let force = normalize (dir ) * params . mouse_force * force_factor ;
51- particle . velocity += force * params . delta_time ;
97+ // Update color based on mode
98+ if (params . color_mode == 1u ) {
99+ // Velocity-based coloring
100+ let speed = length (new_velocity );
101+ let norm_speed = min (speed / 5 .0 , 1 .0 );
102+ new_color = vec4 <f32 >(norm_speed , 0 .5 - norm_speed * 0 .5 , 1 .0 - norm_speed , 1 .0 );
103+ } else if (params . color_mode == 2u ) {
104+ // Position-based coloring
105+ let norm_pos = (new_position / bounds + vec3 <f32 >(1 .0 )) * 0 .5 ;
106+ new_color = vec4 <f32 >(norm_pos . x , norm_pos . y , norm_pos . z , 1 .0 );
52107 }
53- }
54-
55- // Update position
56- particle . position += particle . velocity * params . delta_time ;
57-
58- // Handle boundaries
59- let bounds = 500 .0 ;
60-
61- if (particle . position . x < - bounds ) {
62- particle . position . x = - bounds ;
63- particle . velocity . x = abs (particle . velocity . x ) * 0 .5 ;
64- } else if (particle . position . x > bounds ) {
65- particle . position . x = bounds ;
66- particle . velocity . x = - abs (particle . velocity . x ) * 0 .5 ;
67- }
68-
69- if (particle . position . y < - bounds ) {
70- particle . position . y = - bounds ;
71- particle . velocity . y = abs (particle . velocity . y ) * 0 .5 ;
72- } else if (particle . position . y > bounds ) {
73- particle . position . y = bounds ;
74- particle . velocity . y = - abs (particle . velocity . y ) * 0 .5 ;
75- }
76-
77- if (particle . position . z < - bounds ) {
78- particle . position . z = - bounds ;
79- particle . velocity . z = abs (particle . velocity . z ) * 0 .5 ;
80- } else if (particle . position . z > bounds ) {
81- particle . position . z = bounds ;
82- particle . velocity . z = - abs (particle . velocity . z ) * 0 .5 ;
83- }
84-
85- // Apply damping
86- particle . velocity *= params . damping ;
87-
88- // Update color based on mode (same logic as compute shader)
89- if (params . color_mode == 1u ) {
90- // Velocity-based coloring
91- let speed = length (particle . velocity );
92- let norm_speed = min (speed / 5 .0 , 1 .0 );
93- particle . color = vec4 <f32 >(norm_speed , 0 .5 - norm_speed * 0 .5 , 1 .0 - norm_speed , 1 .0 );
94- } else if (params . color_mode == 2u ) {
95- // Position-based coloring
96- let norm_pos = (particle . position / bounds + 1 .0 ) * 0 .5 ;
97- particle . color = vec4 <f32 >(norm_pos . x , norm_pos . y , norm_pos . z , 1 .0 );
98- }
99-
100- // Write updated particle to output buffer
101- particles_out [vertex_index ] = particle ;
102-
103- // We don't actually render anything in this pass
104- output . position = vec4 <f32 >(0 .0 , 0 .0 , 0 .0 , 1 .0 );
105- return output ;
108+ // else: keep original color (already in new_color)
109+
110+ // --- Output the NEW state ---
111+ var output : ParticleOutput ;
112+ output . out_position = new_position ;
113+ output . out_padding1 = 0 .0 ; // Ensure padding is written
114+ output . out_velocity = new_velocity ;
115+ output . out_padding2 = 0 .0 ; // Ensure padding is written
116+ output . out_color = new_color ;
117+ output . clip_position = vec4 (0 .0 , 0 .0 , 0 .0 , 1 .0 ); // Dummy position, not used for rendering here
118+
119+ return output ;
106120}
121+
122+ @fragment
123+ fn fs_dummy_main () {
124+
125+ }
0 commit comments