Skip to content

Commit

Permalink
Add params for sdfs
Browse files Browse the repository at this point in the history
Issue #3
  • Loading branch information
johanhelsing committed Apr 19, 2022
1 parent 618f285 commit c203111
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 13 deletions.
3 changes: 2 additions & 1 deletion assets/fragment.wgsl
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
struct FragmentInput {
[[location(0)]] color: vec4<f32>;
[[location(1)]] pos: vec2<f32>;
[[location(2)]] params: vec4<f32>;
};

[[stage(fragment)]]
fn fragment(in: FragmentInput) -> [[location(0)]] vec4<f32> {
let d = sdf(in.pos);
let d = sdf(in.pos, in.params);
return fill(d, in.color);
// return vec4<f32>(1.0, 1.0, 0.0, 1.0);
}
9 changes: 6 additions & 3 deletions assets/vertex.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,17 @@ var<uniform> view: View;
struct Vertex {
[[location(0)]] position: vec3<f32>;
[[location(1)]] color: vec4<f32>;
[[location(2)]] rotation: vec2<f32>;
[[location(3)]] scale: f32;
[[location(4)]] frame: f32;
[[location(2)]] params: vec4<f32>;
[[location(3)]] rotation: vec2<f32>;
[[location(4)]] scale: f32;
[[location(5)]] frame: f32;
};

struct VertexOutput {
[[builtin(position)]] clip_position: vec4<f32>;
[[location(0)]] color: vec4<f32>;
[[location(1)]] pos: vec2<f32>;
[[location(2)]] params: vec4<f32>;
};

[[stage(vertex)]]
Expand All @@ -40,6 +42,7 @@ fn vertex(
// Project the world position of the mesh into screen position
out.clip_position = view.view_proj * vec4<f32>(pos, 1.);
out.color = vertex.color;
out.params = vertex.params;
out.pos = vec2<f32>(x, y) * vertex.frame;
return out;
}
88 changes: 88 additions & 0 deletions examples/params.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
use std::f32::consts::PI;

use bevy::prelude::*;
use bevy_asset_loader::{AssetCollection, AssetLoader};
use bevy_smud::prelude::*;
use rand::{prelude::IteratorRandom, random};

// this example shows how to use per-instance parameters in shapes
// in this simple example, a width and height is passed to a box shape,
// but it could be used for almost anything.

fn main() {
let mut app = App::new();

AssetLoader::new(GameState::Loading)
.continue_to_state(GameState::Running)
.with_collection::<AssetHandles>()
.build(&mut app);

app.add_state(GameState::Loading)
.insert_resource(Msaa { samples: 4 })
.add_plugins(DefaultPlugins)
.add_plugin(SmudPlugin)
.add_plugin(bevy_lospec::PalettePlugin)
.add_system_set(SystemSet::on_enter(GameState::Running).with_system(setup))
.run();
}

#[derive(Clone, Eq, PartialEq, Debug, Hash)]
enum GameState {
Loading,
Running,
}

#[derive(AssetCollection)]
struct AssetHandles {
#[asset(path = "vinik24.json")]
palette: Handle<bevy_lospec::Palette>,
}

fn setup(
mut commands: Commands,
mut shaders: ResMut<Assets<Shader>>,
assets: Res<AssetHandles>,
palettes: Res<Assets<bevy_lospec::Palette>>,
) {
let box_sdf = shaders.add_sdf_expr("sd_box(p, params.xy)");
let padding = 5.; // need some padding for the outline/falloff
let spacing = 70.;
let palette = palettes.get(assets.palette.clone()).unwrap();

let clear_color = palette.lightest();
commands.insert_resource(ClearColor(clear_color));
let mut rng = rand::thread_rng();

for i in 0..100 {
let size = Vec2::new(random::<f32>() * 20. + 1., random::<f32>() * 20. + 1.);
let x = ((i % 10) as f32 - 4.5) * spacing;
let y = ((i / 10) as f32 - 4.5) * spacing;

let transform = Transform {
scale: Vec3::splat(1.),
translation: Vec3::new(x, y, 0.),
rotation: Quat::from_rotation_z(random::<f32>() * PI),
};

let color = palette
.iter()
.filter(|c| *c != &clear_color)
.choose(&mut rng)
.copied()
.unwrap_or(Color::PINK);

commands.spawn_bundle(ShapeBundle {
transform,
shape: SmudShape {
color,
sdf: box_sdf.clone(),
frame: Frame::Quad(f32::max(size.x, size.y) + padding),
params: Some(Vec4::new(size.x, size.y, 0., 0.)),
..Default::default()
},
..Default::default()
});
}

commands.spawn_bundle(OrthographicCameraBundle::new_2d());
}
5 changes: 5 additions & 0 deletions src/components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ pub struct SmudShape {
pub fill: Handle<Shader>, // todo: wrap in newtypes?
/// The outer bounds for the shape, should be bigger than the sdf shape
pub frame: Frame,
/// Parameters to pass to shapes, for things such as width of a box
// perhaps it would be a better idea to have this as a separate component?
// keeping it here for now...
pub params: Option<Vec4>,
}

impl Default for SmudShape {
Expand All @@ -25,6 +29,7 @@ impl Default for SmudShape {
color: Color::PINK,
sdf: Default::default(),
frame: Default::default(),
params: Default::default(),
fill: DEFAULT_FILL_HANDLE.typed(),
}
}
Expand Down
28 changes: 20 additions & 8 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ impl SpecializedRenderPipeline for SmudPipeline {
debug!("specializing for {shader:?}");

// Customize how to store the meshes' vertex attributes in the vertex buffer
// Our meshes only have position and color
// Our meshes only have position, color and params
let vertex_attributes = vec![
// (GOTCHA! attributes are sorted alphabetically, and offsets need to reflect this)
// Color
Expand All @@ -241,29 +241,36 @@ impl SpecializedRenderPipeline for SmudPipeline {
VertexAttribute {
format: VertexFormat::Float32,
offset: (4) * 4,
shader_location: 4,
shader_location: 5,
},
// perf: Maybe it's possible to pack this more efficiently?
// Params
VertexAttribute {
format: VertexFormat::Float32x4,
offset: (4 + 1) * 4,
shader_location: 2,
},
// Position
VertexAttribute {
format: VertexFormat::Float32x3,
offset: (4 + 1) * 4,
offset: (4 + 1 + 4) * 4,
shader_location: 0,
},
// Rotation
VertexAttribute {
format: VertexFormat::Float32x2,
offset: (4 + 1 + 3) * 4,
shader_location: 2,
offset: (4 + 1 + 4 + 3) * 4,
shader_location: 3,
},
// Scale
VertexAttribute {
format: VertexFormat::Float32,
offset: (4 + 1 + 3 + 2) * 4,
shader_location: 3,
offset: (4 + 1 + 4 + 3 + 2) * 4,
shader_location: 4,
},
];
// This is the sum of the size of the attributes above
let vertex_array_stride = (4 + 1 + 3 + 2 + 1) * 4;
let vertex_array_stride = (4 + 1 + 4 + 3 + 2 + 1) * 4;

RenderPipelineDescriptor {
vertex: VertexState {
Expand Down Expand Up @@ -382,6 +389,7 @@ fn extract_sdf_shaders(
#[derive(Component, Clone, Debug)]
struct ExtractedShape {
color: Color,
params: Option<Vec4>,
frame: f32,
sdf_shader: Handle<Shader>, // todo could be HandleId?
fill_shader: Handle<Shader>, // todo could be HandleId?
Expand All @@ -407,6 +415,7 @@ fn extract_shapes(

extracted_shapes.0.alloc().init(ExtractedShape {
color: shape.color,
params: shape.params,
transform: *transform,
sdf_shader: shape.sdf.clone_weak(),
fill_shader: shape.fill.clone_weak(),
Expand Down Expand Up @@ -537,6 +546,7 @@ fn queue_shapes(
// | ((color[3] * 255.0) as u32) << 24;

let color = extracted_shape.color.as_linear_rgba_f32();
let params = extracted_shape.params.unwrap_or_default().to_array();

let position = extracted_shape.transform.translation;
let z = position.z;
Expand All @@ -548,6 +558,7 @@ fn queue_shapes(
let vertex = ShapeVertex {
position,
color,
params,
rotation,
scale: extracted_shape.transform.scale.x,
frame: extracted_shape.frame,
Expand Down Expand Up @@ -578,6 +589,7 @@ fn queue_shapes(
struct ShapeVertex {
pub color: [f32; 4],
pub frame: f32,
pub params: [f32; 4], // for now all shapes have 4 f32 parameters
pub position: [f32; 3],
pub rotation: [f32; 2],
pub scale: f32,
Expand Down
2 changes: 1 addition & 1 deletion src/sdf_assets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ impl SdfAssets for Assets<Shader> {
let shader = Shader::from_wgsl(format!(
r#"
#import bevy_smud::shapes
fn sdf(p: vec2<f32>) -> f32 {{
fn sdf(p: vec2<f32>, params: vec4<f32>) -> f32 {{
{body}
}}
"#
Expand Down
3 changes: 3 additions & 0 deletions src/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ fn extract_ui_shapes(
sdf_shader: shape.sdf.clone_weak(),
fill_shader: shape.fill.clone_weak(),
frame,
params: shape.params,
});
}
}
Expand Down Expand Up @@ -191,6 +192,7 @@ fn prepare_ui_shapes(
}

let color = extracted_shape.color.as_linear_rgba_f32();
let params = extracted_shape.params.unwrap_or_default().to_array();

let position = position.into();
// let position = Vec3::ZERO.into();
Expand All @@ -201,6 +203,7 @@ fn prepare_ui_shapes(
let vertex = ShapeVertex {
position,
color,
params,
rotation,
scale: extracted_shape.transform.scale.x,
frame: extracted_shape.frame,
Expand Down

0 comments on commit c203111

Please sign in to comment.