Skip to content

Commit d6d9377

Browse files
committed
Add params for sdfs
Issue #3
1 parent 750dccb commit d6d9377

File tree

7 files changed

+126
-13
lines changed

7 files changed

+126
-13
lines changed

assets/fragment.wgsl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
struct FragmentInput {
22
@location(0) color: vec4<f32>,
33
@location(1) pos: vec2<f32>,
4+
@location(2) params: vec4<f32>,
45
};
56

67
@fragment
78
fn fragment(in: FragmentInput) -> @location(0) vec4<f32> {
8-
let d = sdf(in.pos);
9+
let d = sdf(in.pos, in.params);
910
return fill(d, in.color);
1011
}

assets/vertex.wgsl

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,20 @@ var<uniform> view: View;
99

1010
// as specified in `specialize()`
1111
struct Vertex {
12+
<<<<<<< HEAD
1213
@location(0) position: vec3<f32>,
1314
@location(1) color: vec4<f32>,
14-
@location(2) rotation: vec2<f32>,
15-
@location(3) scale: f32,
16-
@location(4) frame: f32,
15+
@location(2) params: vec4<f32>,
16+
@location(3) rotation: vec2<f32>,
17+
@location(4) scale: f32,
18+
@location(5) frame: f32,
1719
};
1820

1921
struct VertexOutput {
2022
@builtin(position) clip_position: vec4<f32>,
2123
@location(0) color: vec4<f32>,
2224
@location(1) pos: vec2<f32>,
25+
@location(2) params: vec4<f32>,
2326
};
2427

2528
@vertex
@@ -40,6 +43,7 @@ fn vertex(
4043
// Project the world position of the mesh into screen position
4144
out.clip_position = view.view_proj * vec4<f32>(pos, 1.);
4245
out.color = vertex.color;
46+
out.params = vertex.params;
4347
out.pos = vec2<f32>(x, y) * vertex.frame;
4448
return out;
4549
}

examples/params.rs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
use std::f32::consts::PI;
2+
3+
use bevy::prelude::*;
4+
use bevy_asset_loader::{AssetCollection, AssetLoader};
5+
use bevy_smud::prelude::*;
6+
use rand::{prelude::IteratorRandom, random};
7+
8+
// this example shows how to use per-instance parameters in shapes
9+
// in this simple example, a width and height is passed to a box shape,
10+
// but it could be used for almost anything.
11+
12+
fn main() {
13+
let mut app = App::new();
14+
15+
AssetLoader::new(GameState::Loading)
16+
.continue_to_state(GameState::Running)
17+
.with_collection::<AssetHandles>()
18+
.build(&mut app);
19+
20+
app.add_state(GameState::Loading)
21+
.insert_resource(Msaa { samples: 4 })
22+
.add_plugins(DefaultPlugins)
23+
.add_plugin(SmudPlugin)
24+
.add_plugin(bevy_lospec::PalettePlugin)
25+
.add_system_set(SystemSet::on_enter(GameState::Running).with_system(setup))
26+
.run();
27+
}
28+
29+
#[derive(Clone, Eq, PartialEq, Debug, Hash)]
30+
enum GameState {
31+
Loading,
32+
Running,
33+
}
34+
35+
#[derive(AssetCollection)]
36+
struct AssetHandles {
37+
#[asset(path = "vinik24.json")]
38+
palette: Handle<bevy_lospec::Palette>,
39+
}
40+
41+
fn setup(
42+
mut commands: Commands,
43+
mut shaders: ResMut<Assets<Shader>>,
44+
assets: Res<AssetHandles>,
45+
palettes: Res<Assets<bevy_lospec::Palette>>,
46+
) {
47+
let box_sdf = shaders.add_sdf_expr("sd_box(p, params.xy)");
48+
let padding = 5.; // need some padding for the outline/falloff
49+
let spacing = 70.;
50+
let palette = palettes.get(assets.palette.clone()).unwrap();
51+
52+
let clear_color = palette.lightest();
53+
commands.insert_resource(ClearColor(clear_color));
54+
let mut rng = rand::thread_rng();
55+
56+
for i in 0..100 {
57+
let size = Vec2::new(random::<f32>() * 20. + 1., random::<f32>() * 20. + 1.);
58+
let x = ((i % 10) as f32 - 4.5) * spacing;
59+
let y = ((i / 10) as f32 - 4.5) * spacing;
60+
61+
let transform = Transform {
62+
scale: Vec3::splat(1.),
63+
translation: Vec3::new(x, y, 0.),
64+
rotation: Quat::from_rotation_z(random::<f32>() * PI),
65+
};
66+
67+
let color = palette
68+
.iter()
69+
.filter(|c| *c != &clear_color)
70+
.choose(&mut rng)
71+
.copied()
72+
.unwrap_or(Color::PINK);
73+
74+
commands.spawn_bundle(ShapeBundle {
75+
transform,
76+
shape: SmudShape {
77+
color,
78+
sdf: box_sdf.clone(),
79+
frame: Frame::Quad(f32::max(size.x, size.y) + padding),
80+
params: Some(Vec4::new(size.x, size.y, 0., 0.)),
81+
..Default::default()
82+
},
83+
..Default::default()
84+
});
85+
}
86+
87+
commands.spawn_bundle(OrthographicCameraBundle::new_2d());
88+
}

src/components.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ pub struct SmudShape {
2121
pub fill: Handle<Shader>, // todo: wrap in newtypes?
2222
/// The outer bounds for the shape, should be bigger than the sdf shape
2323
pub frame: Frame,
24+
/// Parameters to pass to shapes, for things such as width of a box
25+
// perhaps it would be a better idea to have this as a separate component?
26+
// keeping it here for now...
27+
pub params: Option<Vec4>,
2428
}
2529

2630
impl Default for SmudShape {
@@ -29,6 +33,7 @@ impl Default for SmudShape {
2933
color: Color::PINK,
3034
sdf: default(),
3135
frame: default(),
36+
params: default(),
3237
fill: DEFAULT_FILL_HANDLE.typed(),
3338
}
3439
}

src/lib.rs

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ impl SpecializedRenderPipeline for SmudPipeline {
272272
debug!("specializing for {shader:?}");
273273

274274
// Customize how to store the meshes' vertex attributes in the vertex buffer
275-
// Our meshes only have position and color
275+
// Our meshes only have position, color and params
276276
let vertex_attributes = vec![
277277
// (GOTCHA! attributes are sorted alphabetically, and offsets need to reflect this)
278278
// Color
@@ -285,29 +285,36 @@ impl SpecializedRenderPipeline for SmudPipeline {
285285
VertexAttribute {
286286
format: VertexFormat::Float32,
287287
offset: (4) * 4,
288-
shader_location: 4,
288+
shader_location: 5,
289+
},
290+
// perf: Maybe it's possible to pack this more efficiently?
291+
// Params
292+
VertexAttribute {
293+
format: VertexFormat::Float32x4,
294+
offset: (4 + 1) * 4,
295+
shader_location: 2,
289296
},
290297
// Position
291298
VertexAttribute {
292299
format: VertexFormat::Float32x3,
293-
offset: (4 + 1) * 4,
300+
offset: (4 + 1 + 4) * 4,
294301
shader_location: 0,
295302
},
296303
// Rotation
297304
VertexAttribute {
298305
format: VertexFormat::Float32x2,
299-
offset: (4 + 1 + 3) * 4,
300-
shader_location: 2,
306+
offset: (4 + 1 + 4 + 3) * 4,
307+
shader_location: 3,
301308
},
302309
// Scale
303310
VertexAttribute {
304311
format: VertexFormat::Float32,
305-
offset: (4 + 1 + 3 + 2) * 4,
306-
shader_location: 3,
312+
offset: (4 + 1 + 4 + 3 + 2) * 4,
313+
shader_location: 4,
307314
},
308315
];
309316
// This is the sum of the size of the attributes above
310-
let vertex_array_stride = (4 + 1 + 3 + 2 + 1) * 4;
317+
let vertex_array_stride = (4 + 1 + 4 + 3 + 2 + 1) * 4;
311318

312319
RenderPipelineDescriptor {
313320
vertex: VertexState {
@@ -434,6 +441,7 @@ var<uniform> time: Time;
434441
#[derive(Component, Clone, Debug)]
435442
struct ExtractedShape {
436443
color: Color,
444+
params: Option<Vec4>,
437445
frame: f32,
438446
sdf_shader: Handle<Shader>, // todo could be HandleId?
439447
fill_shader: Handle<Shader>, // todo could be HandleId?
@@ -458,6 +466,7 @@ fn extract_shapes(
458466

459467
extracted_shapes.0.alloc().init(ExtractedShape {
460468
color: shape.color,
469+
params: shape.params,
461470
transform: *transform,
462471
sdf_shader: shape.sdf.clone_weak(),
463472
fill_shader: shape.fill.clone_weak(),
@@ -585,6 +594,7 @@ fn queue_shapes(
585594
// | ((color[3] * 255.0) as u32) << 24;
586595

587596
let color = extracted_shape.color.as_linear_rgba_f32();
597+
let params = extracted_shape.params.unwrap_or_default().to_array();
588598

589599
let position = extracted_shape.transform.translation();
590600
let z = position.z;
@@ -602,6 +612,7 @@ fn queue_shapes(
602612
let vertex = ShapeVertex {
603613
position,
604614
color,
615+
params,
605616
rotation,
606617
scale,
607618
frame: extracted_shape.frame,
@@ -664,6 +675,7 @@ fn queue_time(
664675
struct ShapeVertex {
665676
pub color: [f32; 4],
666677
pub frame: f32,
678+
pub params: [f32; 4], // for now all shapes have 4 f32 parameters
667679
pub position: [f32; 3],
668680
pub rotation: [f32; 2],
669681
pub scale: f32,

src/sdf_assets.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ impl SdfAssets for Assets<Shader> {
1313
let shader = Shader::from_wgsl(format!(
1414
r#"
1515
#import bevy_smud::shapes
16-
fn sdf(p: vec2<f32>) -> f32 {{
16+
fn sdf(p: vec2<f32>, params: vec4<f32>) -> f32 {{
1717
{body}
1818
}}
1919
"#

src/ui.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ fn extract_ui_shapes(
107107
sdf_shader: shape.sdf.clone_weak(),
108108
fill_shader: shape.fill.clone_weak(),
109109
frame,
110+
params: shape.params,
110111
});
111112
}
112113
}
@@ -195,6 +196,7 @@ fn prepare_ui_shapes(
195196
}
196197

197198
let color = extracted_shape.color.as_linear_rgba_f32();
199+
let params = extracted_shape.params.unwrap_or_default().to_array();
198200

199201
let position = position.into();
200202
// let position = Vec3::ZERO.into();
@@ -211,6 +213,7 @@ fn prepare_ui_shapes(
211213
let vertex = ShapeVertex {
212214
position,
213215
color,
216+
params,
214217
rotation,
215218
scale,
216219
frame: extracted_shape.frame,

0 commit comments

Comments
 (0)