@@ -36,8 +36,9 @@ fn vs_main_3d(in: VertexInput, @builtin(instance_index) inst_idx: u32) -> Vertex
3636
3737 let p = particles [inst_idx ];
3838
39- // Discard/hide particle if life is finished or energy is extremely low
40- if (p . pos . w <= 0 .0 || p . vel . w < 0 .001 ) {
39+ // Discard/hide particle if life is finished, energy is extremely low,
40+ // or if this is not the front face of the cube (to render as a single billboarded quad)
41+ if (p . pos . w <= 0 .0 || p . vel . w < 0 .001 || in . normal . z < 0 .9 ) {
4142 out . clip_position = vec4 <f32 >(0 .0 , 0 .0 , - 10 .0 , 1 .0 ); // behind the camera
4243 out . uv = vec2 <f32 >(0 .0 );
4344 out . energy = 0 .0 ;
@@ -48,10 +49,12 @@ fn vs_main_3d(in: VertexInput, @builtin(instance_index) inst_idx: u32) -> Vertex
4849
4950 // Scale particle based on energy (pulsing effect) and clamp to prevent excessive blowouts
5051 let size = 0 .035 + clamp (p . vel . w , 0 .0 , 1 .5 ) * 0 .09 ;
51- let local_pos = in . position * size ;
52- let world_pos = local_pos + p . pos . xyz ;
5352
54- let view_pos = camera . view_matrix * vec4 <f32 >(world_pos , 1 .0 );
53+ // Billboard the vertex: offset particle center in view space
54+ var view_pos = camera . view_matrix * vec4 <f32 >(p . pos . xyz , 1 .0 );
55+ view_pos . x += in . position . x * size ;
56+ view_pos . y += in . position . y * size ;
57+
5558 let depth = - view_pos . z ;
5659
5760 // Discard/hide particle if it is behind or too close to the camera to prevent huge screen-filling discs
0 commit comments