1#import bevy_gaussian_splatting::bindings::{ 6#import bevy_gaussian_splatting::classification::class_to_rgb 7#import bevy_gaussian_splatting::depth::depth_to_rgb 8#import bevy_gaussian_splatting::optical_flow::{ 9 calculate_motion_vector, 12#import bevy_gaussian_splatting::helpers::{ 16#import bevy_gaussian_splatting::transform::{ 22 #import bevy_gaussian_splatting::gaussian_2d::{ 24 get_bounding_box_cov2d, 25 surfel_fragment_power, 27#else ifdef GAUSSIAN_3D 28 #import bevy_gaussian_splatting::gaussian_3d::{ 31 #import bevy_gaussian_splatting::helpers::{ 32 get_bounding_box_clip, 34#else ifdef GAUSSIAN_4D 35 #import bevy_gaussian_splatting::gaussian_4d::{ 38 #import bevy_gaussian_splatting::helpers::{ 40 get_bounding_box_clip, 45 #ifdef PRECOMPUTE_COVARIANCE_3D 46 #import bevy_gaussian_splatting::packed::{ 54 #import bevy_gaussian_splatting::packed::{ 63#else ifdef BUFFER_STORAGE 64 #ifdef PRECOMPUTE_COVARIANCE_3D 65 #import bevy_gaussian_splatting::planar::{ 73 #import bevy_gaussian_splatting::planar::{ 82#else ifdef BUFFER_TEXTURE 83 #ifdef PRECOMPUTE_COVARIANCE_3D 84 #import bevy_gaussian_splatting::texture::{ 93 #import bevy_gaussian_splatting::texture::{ 107 @group(3) @binding(0) var<storage, read> sorted_entries: array<Entry>; 108 fn get_entry(index: u32) -> Entry { 109 return sorted_entries[index]; 111#else ifdef BUFFER_TEXTURE 112 @group(3) @binding(0) var sorted_entries: texture_2d<u32>; 113 fn get_entry(index: u32) -> Entry { 114 let sample = textureLoad( 128 struct GaussianVertexOutput { 129 @builtin(position) position: vec4<f32>, 130 @location(0) color: vec4<f32>, 131 @location(1) uv: vec2<f32>, 133 @location(2) local_to_pixel_u: vec3<f32>, 134 @location(3) local_to_pixel_v: vec3<f32>, 135 @location(4) local_to_pixel_w: vec3<f32>, 136 @location(5) mean_2d: vec2<f32>, 137 @location(6) radius: vec2<f32>, 138 #else #ifdef GAUSSIAN_3D 139 @location(2) conic: vec3<f32>, 140 @location(3) major_minor: vec2<f32>, 141 #else #ifdef GAUSSIAN_4D 142 @location(2) conic: vec3<f32>, 143 @location(3) major_minor: vec2<f32>, 147 struct GaussianVertexOutput { 148 @builtin(position) position: vec4<f32>, 149 @location(0) @interpolate(flat) color: vec4<f32>, 150 @location(1) @interpolate(linear) uv: vec2<f32>, 152 @location(2) @interpolate(flat) local_to_pixel_u: vec3<f32>, 153 @location(3) @interpolate(flat) local_to_pixel_v: vec3<f32>, 154 @location(4) @interpolate(flat) local_to_pixel_w: vec3<f32>, 155 @location(5) @interpolate(flat) mean_2d: vec2<f32>, 156 @location(6) @interpolate(flat) radius: vec2<f32>, 157 #else ifdef GAUSSIAN_3D 158 @location(2) @interpolate(flat) conic: vec3<f32>, 159 @location(3) @interpolate(linear) major_minor: vec2<f32>, 160 #else ifdef GAUSSIAN_4D 161 @location(2) @interpolate(flat) conic: vec3<f32>, 162 @location(3) @interpolate(linear) major_minor: vec2<f32>, 170 @builtin(instance_index) instance_index: u32, 171 @builtin(vertex_index) vertex_index: u32, 172) -> GaussianVertexOutput { 173 var output: GaussianVertexOutput; 175 let entry = get_entry(instance_index); 176 let splat_index = entry.value; 178 var discard_quad = false; 180 discard_quad |= entry.key == 0xFFFFFFFFu; 182 let position = vec4<f32>(get_position(splat_index), 1.0); 184 var transformed_position = (gaussian_uniforms.transform * position).xyz; 185 var previous_transformed_position = transformed_position; 188 discard_quad |= get_visibility(splat_index) < 0.5; 193 let projected_position = world_to_clip(transformed_position); 194 discard_quad |= !in_frustum(projected_position.xyz); 198 output.color = vec4<f32>(0.0, 0.0, 0.0, 0.0); 199 output.position = vec4<f32>(0.0, 0.0, 0.0, 0.0); 203 var quad_vertices = array<vec2<f32>, 4>( 204 vec2<f32>(-1.0, -1.0), 205 vec2<f32>(-1.0, 1.0), 206 vec2<f32>( 1.0, -1.0), 207 vec2<f32>( 1.0, 1.0), 210 let quad_index = vertex_index % 4u; 211 let quad_offset = quad_vertices[quad_index]; 214 var opacity = get_opacity(splat_index); 216#ifdef OPACITY_ADAPTIVE_RADIUS 217 let cutoff = sqrt(max(9.0 + 2.0 * log(opacity), 0.000001)); 224 let surfel = compute_cov2d_surfel( 225 transformed_position, 230 output.local_to_pixel_u = surfel.local_to_pixel[0]; 231 output.local_to_pixel_v = surfel.local_to_pixel[1]; 232 output.local_to_pixel_w = surfel.local_to_pixel[2]; 233 output.mean_2d = surfel.mean_2d; 235 let bb = get_bounding_box_cov2d( 240 output.radius = bb.zw; 243 let gaussian_cov2d = compute_cov2d_3dgs( 244 transformed_position, 247 #else ifdef GAUSSIAN_4D 248 let gaussian_4d = conditional_cov3d( 249 transformed_position, 251 gaussian_uniforms.time, 254 if !gaussian_4d.mask { 255 output.color = vec4<f32>(0.0, 0.0, 0.0, 0.0); 256 output.position = vec4<f32>(0.0, 0.0, 0.0, 0.0); 260 let position_t = vec4<f32>(position.xyz + gaussian_4d.delta_mean, 1.0); 261 transformed_position = (gaussian_uniforms.transform * position_t).xyz; 263 let projected_position = world_to_clip(transformed_position); 265 if !in_frustum(projected_position.xyz) { 266 output.color = vec4<f32>(0.0, 0.0, 0.0, 0.0); 267 output.position = vec4<f32>(0.0, 0.0, 0.0, 0.0); 271 opacity = opacity * gaussian_4d.opacity_modifier; 273 let gaussian_cov2d = cov2d( 274 transformed_position, 279 let bb = get_bounding_box_clip( 286 let det = gaussian_cov2d.x * gaussian_cov2d.z - gaussian_cov2d.y * gaussian_cov2d.y; 287 let det_inv = 1.0 / det; 288 let conic = vec3<f32>( 289 gaussian_cov2d.z * det_inv, 290 -gaussian_cov2d.y * det_inv, 291 gaussian_cov2d.x * det_inv 293 output.conic = conic; 294 output.major_minor = bb.zw; 299 var rgb = vec3<f32>(0.0); 302#ifdef RASTERIZE_CLASSIFICATION 303 let ray_direction = normalize(transformed_position - view.world_position); 305 #ifdef GAUSSIAN_3D_STRUCTURE 306 rgb = get_color(splat_index, ray_direction); 307 #else ifdef GAUSSIAN_4D 308 rgb = get_color(splat_index, gaussian_4d.dir_t, ray_direction); 312 get_visibility(splat_index), 315#else ifdef RASTERIZE_DEPTH 317 let first_position = vec4<f32>(get_position(get_entry(1u).value), 1.0); 318 let last_position = vec4<f32>(get_position(get_entry(gaussian_uniforms.count - 1u).value), 1.0); 320 let min_position = (gaussian_uniforms.transform * first_position).xyz; 321 let max_position = (gaussian_uniforms.transform * last_position).xyz; 323 let camera_position = view.world_position; 325 let min_distance = length(min_position - camera_position); 326 let max_distance = length(max_position - camera_position); 328 let depth = length(transformed_position - camera_position); 334#else ifdef RASTERIZE_NORMAL 336 let R = get_rotation_matrix(get_rotation(splat_index)); 337 let S = get_scale_matrix(get_scale(splat_index)); 339 gaussian_uniforms.transform[0].xyz, 340 gaussian_uniforms.transform[1].xyz, 341 gaussian_uniforms.transform[2].xyz, 345 let local_normal = vec4<f32>(L[2], 0.0); 346 let world_normal = view.view_from_world * local_normal; 348 let t = normalize(world_normal); 355#else ifdef RASTERIZE_OPTICAL_FLOW 356 let motion_vector = calculate_motion_vector( 357 transformed_position, 358 previous_transformed_position, 361 rgb = optical_flow_to_rgb(motion_vector); 362#else ifdef RASTERIZE_POSITION 363 rgb = (transformed_position - gaussian_uniforms.min.xyz) / (gaussian_uniforms.max.xyz - gaussian_uniforms.min.xyz); 364#else ifdef RASTERIZE_VELOCITY 365 let time_delta = 1e-3; 366 let future_gaussian_4d = conditional_cov3d( 367 transformed_position, 369 gaussian_uniforms.time + time_delta, 371 let position_delta = future_gaussian_4d.delta_mean - gaussian_4d.delta_mean; 372 let velocity = position_delta / time_delta; 373 let velocity_magnitude = length(velocity); 374 let velocity_normalized = normalize(velocity); 377 let min_magnitude = 1.0; 378 let max_magnitude = 2.0; 380 let scaled_mag = clamp( 381 (velocity_magnitude - min_magnitude) / (max_magnitude - min_magnitude), 386 if scaled_mag < 1e-2 { 390 let base_color = 0.5 * (velocity_normalized + vec3<f32>(1.0, 1.0, 1.0)); 391 rgb = base_color * scaled_mag; 392#else ifdef RASTERIZE_COLOR 395 let ray_direction = normalize(transformed_position - view.world_position); 397 #ifdef GAUSSIAN_3D_STRUCTURE 398 rgb = get_color(splat_index, ray_direction); 399 #else ifdef GAUSSIAN_4D 400 rgb = get_color(splat_index, gaussian_4d.dir_t, ray_direction); 405 output.color = vec4<f32>( 407 opacity * gaussian_uniforms.global_opacity, 410#ifdef HIGHLIGHT_SELECTED 411 if (get_visibility(splat_index) > 0.5) { 412 output.color = vec4<f32>(0.3, 1.0, 0.1, 1.0); 417 output.uv = quad_offset; 418 output.position = vec4<f32>( 419 projected_position.xy + bb.xy, 420 projected_position.zw, 427fn fs_main(input: GaussianVertexOutput) -> @location(0) vec4<f32> { 430 let radius = input.radius; 431 let mean_2d = input.mean_2d; 432 let aspect = vec2<f32>( 434 view.viewport.z / view.viewport.w, 436 let pixel_coord = input.uv * radius * aspect + mean_2d; 438 let power = surfel_fragment_power( 440 input.local_to_pixel_u, 441 input.local_to_pixel_v, 442 input.local_to_pixel_w, 447#else ifdef GAUSSIAN_3D 448 let d = -input.major_minor; 449 let conic = input.conic; 450 let power = -0.5 * (conic.x * d.x * d.x + conic.z * d.y * d.y) + conic.y * d.x * d.y; 451#else ifdef GAUSSIAN_4D 452 let d = -input.major_minor; 453 let conic = input.conic; 454 let power = -0.5 * (conic.x * d.x * d.x + conic.z * d.y * d.y) + conic.y * d.x * d.y; 463 let sigma = 1.0 / 3.0; 464 let sigma_squared = 2.0 * sigma * sigma; 465 let distance_squared = dot(input.uv, input.uv); 467 let power = -distance_squared / sigma_squared; 469 if (distance_squared > 3.0 * 3.0) { 474#ifdef VISUALIZE_BOUNDING_BOX 475 let uv = input.uv * 0.5 + 0.5; 476 let edge_width = 0.08; 478 (uv.x < edge_width || uv.x > 1.0 - edge_width) || 479 (uv.y < edge_width || uv.y > 1.0 - edge_width) 481 return vec4<f32>(0.3, 1.0, 0.1, 1.0); 485 let alpha = min(exp(power) * input.color.a, 0.999); 490 input.color.rgb * alpha,