diff --git a/src/nodes/drawable/line.wgsl b/src/nodes/drawable/line.wgsl index 4094e5c..e8e7e86 100644 --- a/src/nodes/drawable/line.wgsl +++ b/src/nodes/drawable/line.wgsl @@ -18,13 +18,6 @@ #import bevy_core_pipeline::oit::oit_draw #endif -struct LineMaterial { - unused: u32, -} - -@group(2) @binding(100) -var line_mat: LineMaterial; - @fragment fn fragment( in: VertexOutput, diff --git a/src/nodes/drawable/lines.rs b/src/nodes/drawable/lines.rs index 19d1410..1b4b700 100644 --- a/src/nodes/drawable/lines.rs +++ b/src/nodes/drawable/lines.rs @@ -7,17 +7,19 @@ use crate::{ }, nodes::{ Node, + drawable::LinePoint, spatial::{Spatial, SpatialNode}, }, }; use bevy::{ - asset::{RenderAssetUsages, weak_handle}, + asset::{AssetEvents, RenderAssetUsages, weak_handle}, pbr::{ExtendedMaterial, MaterialExtension}, prelude::*, render::{ mesh::{Indices, MeshAabb, PrimitiveTopology}, primitives::Aabb, render_resource::{AsBindGroup, ShaderRef}, + view::VisibilitySystems, }, }; use glam::Vec3; @@ -31,9 +33,13 @@ type LineMaterial = ExtendedMaterial; const LINE_SHADER_HANDLE: Handle = weak_handle!("7d28aa5a-3abd-43bb-b0e9-0de8b81b650d"); // No extra data needed for a simple holdout #[derive(Default, Asset, AsBindGroup, TypePath, Debug, Clone)] -pub struct LineExtension { - #[uniform(100)] - unused: u32, +#[data(50, u32, binding_array(101))] +#[bindless(index_table(range(50..51), binding(100)))] +pub struct LineExtension {} +impl From<&LineExtension> for u32 { + fn from(_: &LineExtension) -> Self { + 0 + } } impl MaterialExtension for LineExtension { fn fragment_shader() -> ShaderRef { @@ -56,7 +62,14 @@ impl MaterialExtension for LineExtension { pub struct LinesNodePlugin; impl Plugin for LinesNodePlugin { fn build(&self, app: &mut App) { - app.add_systems(Update, build_line_mesh); + app.add_systems( + PostUpdate, + build_line_mesh + .after(TransformSystem::TransformPropagate) + .before(AssetEvents) + .after(VisibilitySystems::VisibilityPropagate) + .before(VisibilitySystems::CheckVisibility), + ); app.world_mut().resource_mut::>().insert( LINE_SHADER_HANDLE.id(), Shader::from_wgsl( @@ -76,6 +89,7 @@ fn build_line_mesh( mut cmds: Commands, mut meshes: ResMut>, mut materials: ResMut>, + query: Query<(&GlobalTransform, &InheritedVisibility)>, ) { for lines in LINES_REGISTRY .get_valid_contents() @@ -88,6 +102,10 @@ fn build_line_mesh( let mut vertex_colors = Vec::<[f32; 4]>::new(); let mut vertex_indices = Vec::::new(); let lines_data = lines.data.lock(); + let Some((transform, visibil)) = lines.spatial.get_entity().and_then(|e| query.get(e).ok()) + else { + continue; + }; if lines_data.is_empty() { *lines.bounds.lock() = Aabb::default(); match lines.entity.get() { @@ -104,14 +122,26 @@ fn build_line_mesh( let mut indices_set = 0; for line in lines_data.iter() { + // yes this alloc is suboptimal, but good enough for now + let line_points = line + .points + .iter() + .map(|p: &LinePoint| LinePoint { + // point: transform.transform_point(p.point.into()).into(), + point: transform.transform_point(p.point.into()).into(), + thickness: p.thickness, + color: p.color, + }) + .collect::>(); + let start_set = indices_set; // Create a sliding window of points to process each segment of the line // For cyclic lines: wraps around by connecting last point back to first // For non-cyclic lines: handles endpoints with None values let point_windows = { let mut out = Vec::new(); - let mut last = line.cyclic.then(|| line.points.last()).flatten(); - let mut peekable = line.points.iter().peekable(); + let mut last = line.cyclic.then(|| line_points.last()).flatten(); + let mut peekable = line_points.iter().peekable(); while let Some(curr) = peekable.next() { // Skip this point if it has the same position as the previous point if let Some(prev) = last @@ -128,7 +158,7 @@ fn build_line_mesh( Some(v) => Some(*v), None => { end = true; - line.cyclic.then(|| line.points.first()).flatten() + line.cyclic.then(|| line_points.first()).flatten() } }; @@ -224,10 +254,9 @@ fn build_line_mesh( emissive: Color::linear_rgba(0.25, 0.25, 0.25, 1.0).into(), ..default() }, - extension: LineExtension { unused: 0 }, + extension: LineExtension {}, })), )); - lines.spatial.set_entity(e.id()); _ = lines.entity.set(e.id().into()); e } @@ -236,7 +265,13 @@ fn build_line_mesh( *lines.bounds.lock() = aabb; entity.insert(aabb); } - entity.insert(Mesh3d(meshes.add(mesh))); + entity + .insert(Mesh3d(meshes.add(mesh))) + .insert(*visibil) + .insert(match visibil.get() { + true => Visibility::Visible, + false => Visibility::Hidden, + }); } } diff --git a/src/nodes/drawable/model.rs b/src/nodes/drawable/model.rs index a723033..db43c63 100644 --- a/src/nodes/drawable/model.rs +++ b/src/nodes/drawable/model.rs @@ -67,7 +67,14 @@ impl Plugin for ModelNodePlugin { // No extra data needed for a simple holdout #[derive(Default, Asset, AsBindGroup, TypePath, Debug, Clone)] +#[data(50, u32, binding_array(101))] +#[bindless(index_table(range(50..51), binding(100)))] pub struct HoldoutExtension {} +impl From<&HoldoutExtension> for u32 { + fn from(_: &HoldoutExtension) -> Self { + 0 + } +} impl MaterialExtension for HoldoutExtension { fn fragment_shader() -> ShaderRef { HOLDOUT_SHADER_HANDLE.into() diff --git a/src/nodes/spatial/mod.rs b/src/nodes/spatial/mod.rs index 563e3ed..9021cfc 100644 --- a/src/nodes/spatial/mod.rs +++ b/src/nodes/spatial/mod.rs @@ -194,6 +194,9 @@ impl Spatial { child.mark_dirty(); } } + pub fn get_entity(&self) -> Option { + self.entity.read().as_ref().map(|v| v.0) + } pub fn add_to( node: &Arc, parent: Option>,