fix: properly implement lines by only transforming points, not the mesh, also make lines and holdout bindless
Signed-off-by: Schmarni <marnistromer@gmail.com>
This commit is contained in:
@@ -18,13 +18,6 @@
|
||||
#import bevy_core_pipeline::oit::oit_draw
|
||||
#endif
|
||||
|
||||
struct LineMaterial {
|
||||
unused: u32,
|
||||
}
|
||||
|
||||
@group(2) @binding(100)
|
||||
var<uniform> line_mat: LineMaterial;
|
||||
|
||||
@fragment
|
||||
fn fragment(
|
||||
in: VertexOutput,
|
||||
|
||||
@@ -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<BevyMaterial, LineExtension>;
|
||||
const LINE_SHADER_HANDLE: Handle<Shader> = 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::<Assets<Shader>>().insert(
|
||||
LINE_SHADER_HANDLE.id(),
|
||||
Shader::from_wgsl(
|
||||
@@ -76,6 +89,7 @@ fn build_line_mesh(
|
||||
mut cmds: Commands,
|
||||
mut meshes: ResMut<Assets<Mesh>>,
|
||||
mut materials: ResMut<Assets<LineMaterial>>,
|
||||
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::<u32>::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::<Vec<_>>();
|
||||
|
||||
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,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user