1#import bevy_render::view::View 2#import bevy_hanabi::vfx_common::{ 3 IndirectBuffer, SimParams, Spawner, 4 seed, tau, pcg_hash, to_float01, frand, frand2, frand3, frand4, 5 rand_uniform_f, rand_uniform_vec2, rand_uniform_vec3, rand_uniform_vec4, 6 rand_normal_f, rand_normal_vec2, rand_normal_vec3, rand_normal_vec4, proj 13struct ParticleBuffer { 14 particles: array<Particle>, 18 @builtin(position) position: vec4<f32>, 19 @location(0) color: vec4<f32>, 21 @location(1) uv: vec2<f32>, 24 @location(2) normal: vec3<f32>, 26#ifdef NEEDS_PARTICLE_FRAGMENT 27 @location(3) slab_particle_index: u32, 31@group(0) @binding(0) var<uniform> view: View; 32@group(0) @binding(1) var<uniform> sim_params : SimParams; 34@group(1) @binding(0) var<storage, read> particle_buffer : ParticleBuffer; 35@group(1) @binding(1) var<storage, read> indirect_buffer : IndirectBuffer; 36@group(1) @binding(2) var<storage, read> spawner : Spawner; 40fn get_camera_position_effect_space() -> vec3<f32> { 41 let view_pos = view.world_from_view[3].xyz; 42#ifdef LOCAL_SPACE_SIMULATION 43 let inverse_transform = transpose( 45 spawner.inverse_transform[0].xyz, 46 spawner.inverse_transform[1].xyz, 47 spawner.inverse_transform[2].xyz, 50 return inverse_transform * view_pos; 56fn get_camera_rotation_effect_space() -> mat3x3<f32> { 57 let view_rot = mat3x3(view.world_from_view[0].xyz, view.world_from_view[1].xyz, view.world_from_view[2].xyz); 58#ifdef LOCAL_SPACE_SIMULATION 59 let inverse_transform = transpose( 61 spawner.inverse_transform[0].xyz, 62 spawner.inverse_transform[1].xyz, 63 spawner.inverse_transform[2].xyz, 66 return inverse_transform * view_rot; 73fn unpack_compressed_transform(compressed_transform: mat3x4<f32>) -> mat4x4<f32> { 76 compressed_transform[0], 77 compressed_transform[1], 78 compressed_transform[2], 79 vec4<f32>(0.0, 0.0, 0.0, 1.0) 85fn unpack_compressed_transform_3x3_transpose(compressed_transform: mat3x4<f32>) -> mat3x3<f32> { 87 compressed_transform[0].xyz, 88 compressed_transform[1].xyz, 89 compressed_transform[2].xyz, 97fn transform_position_simulation_to_world(sim_position: vec3<f32>) -> vec4<f32> { 98#ifdef LOCAL_SPACE_SIMULATION 99 let transform = unpack_compressed_transform(spawner.transform); 100 return transform * vec4<f32>(sim_position, 1.0); 102 return vec4<f32>(sim_position, 1.0); 106fn transform_normal_simulation_to_world(sim_normal: vec3<f32>) -> vec3<f32> { 107#ifdef LOCAL_SPACE_SIMULATION 111 let transform = unpack_compressed_transform_3x3_transpose(spawner.inverse_transform); 112 return transform * sim_normal; 124fn transform_position_simulation_to_clip(sim_position: vec3<f32>) -> vec4<f32> { 125 return view.clip_from_world * transform_position_simulation_to_world(sim_position); 128fn inverse_transpose_mat3(m: mat3x3<f32>) -> mat3x3<f32> { 129 let tmp0 = cross(m[1], m[2]); 130 let tmp1 = cross(m[2], m[0]); 131 let tmp2 = cross(m[0], m[1]); 132 let inv_det = 1.0 / dot(m[2], tmp2); 133 return mat3x3<f32>(tmp0 * inv_det, tmp1 * inv_det, tmp2 * inv_det); 140 @builtin(instance_index) instance_index: u32, 141 @location(0) vertex_position: vec3<f32>, 143 @location(1) vertex_uv: vec2<f32>, 146 @location(2) vertex_normal: vec3<f32>, 151 let base_particle = spawner.slab_offset; 154 let indirect_read_index = spawner.render_indirect_read_index; 155 let particle_index = indirect_buffer.rows[base_particle + instance_index].particle_index[indirect_read_index]; 156 var particle = particle_buffer.particles[base_particle + particle_index]; 158 var out: VertexOutput; 160#ifdef NEEDS_PARTICLE_FRAGMENT 161 out.slab_particle_index = base_particle + particle_index; 162#endif // NEEDS_PARTICLE_FRAGMENT 166 if (instance_index == 0) { 167 out.position = vec4(0.0); 172 let prev_index = indirect_buffer.rows[base_particle + instance_index - 1u].particle_index[indirect_read_index]; 173 let prev_particle = particle_buffer.particles[base_particle + prev_index]; 177 if (prev_particle.ribbon_id != particle.ribbon_id) { 178 out.position = vec4(0.0); 187 let row_count = {{FLIPBOOK_ROW_COUNT}}; 188 let ij = vec2<f32>(f32(particle.sprite_index % row_count), f32(particle.sprite_index / row_count)); 189 uv = (ij + uv) * {{FLIPBOOK_SCALE}}; 199 var delta = particle.position - prev_particle.position; 201 axis_x = normalize(delta); 202 axis_y = normalize(cross(axis_x, axis_z)); 203 axis_z = cross(axis_x, axis_y); 205 position = mix(particle.position, prev_particle.position, 0.5); 206 size = vec3(length(delta), size.y, 1.0); 211 let vpos = vertex_position * size; 212 let sim_position = position + axis_x * vpos.x + axis_y * vpos.y + axis_z * vpos.z; 213 out.position = transform_position_simulation_to_clip(sim_position); 218 let normal = inverse_transpose_mat3(mat3x3(axis_x, axis_y, axis_z)) * vertex_normal; 219 out.normal = transform_normal_simulation_to_world(normal); 220#endif // NEEDS_NORMAL 226fn fragment(in: VertexOutput) -> @location(0) vec4<f32> { 229 var alpha_cutoff: f32 = {{ALPHA_CUTOFF}}; 231 var color = in.color; 236 var normal = in.normal; 238#ifdef NEEDS_PARTICLE_FRAGMENT 239 var particle = particle_buffer.particles[in.slab_particle_index]; 240#endif // NEEDS_PARTICLE_FRAGMENT 242{{FRAGMENT_MODIFIERS}} 245 if color.a >= alpha_cutoff {