Sdf 2d shape renderer for Bevy

Overview

bevy_smud

Sdf 2d shape rendering for Bevy.

screenshot of a bird drawn with bevy_smud

Bevy smud is a way to conveniently construct and render sdf shapes with Bevy.

Given a shape function/expression, and a fill type, it generates shaders at run-time.

If you keep the number of different sdf and fill combinations relatively low it's pretty performant. My machine easily handles 100k shapes at 60 fps, with 40 different shape/fill combinations in randomized order (see gallery example).

Usage

A signed distance field (sdf) is a way to map points in space to distances to a surface. If a point maps to a positive value, it's outside the shape, if it's negative, it's inside the shape. These "mappings" can be described by functions, which takes a point as input and returns a distance to a surface. For instance, if you wanted to make a circle, it could be described as length(position - center) - radius. That way, all the points that are radius away from center would be 0 and would define the edge of the shape.

Many such functions describing geometric primitives are included in this library, they are imported automatically when using the single-expression or body shorthand for adding sdfs. For instance, the circle above could also be described as:

sd_circle(p - center, 50.)

Similarly there are a bunch of other shapes (sd_ellipse, sd_box, sd_rounded_box, sd_egg etc. etc.)

Most of the built-in shapes are direct ports of the ones on this page, which includes screenshots of the various shapes. So that page might act as a good reference. The ports here use snake_case instead of camelCase.

To put together a shape, you can do:

fn spawn_circle(
    mut commands: Commands,
    mut shaders: ResMut<Assets<Shader>>,
) {
    let circle = shaders.add_sdf_expr("sd_circle(p, 50.)");

    commands.spawn_bundle(ShapeBundle {
        shape: SmudShape {
            color: Color::TOMATO,
            sdf: circle,
            frame: Frame::Quad(55.),
            ..Default::default()
        },
        ..Default::default()
    });
}

Make sure you reuse the shaders, i.e. don't call add_sdf_expr every frame.

You can also define shapes in .wgsl files. Note that in order to use the built-in shapes, you have to import bevy_smud::shapes, and you must create a function named sdf that takes a vec2<f32> and returns f32.

Other than that, make sure you understand how to combine shapes, use symmetries and change domains. For instance, the bevy in the screenshot above is built up of several circles, ellipses, and a vesica for the beak.

Also, check out the examples. In particular, the basic example should be a good place to start.

The library also has some level of ui support. The ui example shows how to create a "bevy" button.

Word of caution

This crate should still be considered highly experimental.

If you want something more finished, you should probably check out bevy_prototype_lyon.

Bevy version support

The main branch targets the latest bevy release.

I intend to support the main branch of Bevy in the bevy-main branch.

bevy bevy_smud
0.6 0.1, main

Thanks!

Little of this crate is original work. It's mostly a mishmash of bevy_sprite and Inigo Quilez sdf rendering primitives ported to wgsl. I just put the two together in a way I found convenient.

Comments
  • Shader compilation errors on

    Shader compilation errors on "fwidth" on wasm

    I think this is a bug in wasm/naga.

    A workaround in the meantime would be to just disable the derivative-based anti-alias fills on wasm. Perhaps it could be done with shader defines.

    bug 
    opened by johanhelsing 2
  • Gray borders around shapes

    Gray borders around shapes

    Basically the title i'm not sure if it's due to my intel gpu or what. My console spits out some things but I'm pretty sure it's unrelated in case though here:

    2022-11-05T00:18:39.528209Z  INFO winit::platform_impl::platform::x11::window: Guessed window scale factor: 1.5
    2022-11-05T00:18:39.548085Z  INFO bevy_render::renderer: AdapterInfo { name: "Intel(R) UHD Graphics (CML GT2)", vendor: 32902, device: 39745, device_type: IntegratedGpu, backend: Vulkan }
    2022-11-05T00:18:39.548672Z ERROR wgpu_hal::vulkan::instance: VALIDATION [VUID-VkDeviceCreateInfo-pNext-02830 (0x211e533b)]
            Validation Error: [ VUID-VkDeviceCreateInfo-pNext-02830 ] Object 0: handle = 0x55d6e0ac6500, type = VK_OBJECT_TYPE_INSTANCE; | MessageID = 0x211e533b | If the pNext chain includes a VkPhysicalDeviceVulkan12Features structure, then it must not include a VkPhysicalDevice8BitStorageFeatures, VkPhysicalDeviceShaderAtomicInt64Features, VkPhysicalDeviceShaderFloat16Int8Features, VkPhysicalDeviceDescriptorIndexingFeatures, VkPhysicalDeviceScalarBlockLayoutFeatures, VkPhysicalDeviceImagelessFramebufferFeatures, VkPhysicalDeviceUniformBufferStandardLayoutFeatures, VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures, VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures, VkPhysicalDeviceHostQueryResetFeatures, VkPhysicalDeviceTimelineSemaphoreFeatures, VkPhysicalDeviceBufferDeviceAddressFeatures, or VkPhysicalDeviceVulkanMemoryModelFeatures structure The Vulkan spec states: If the pNext chain includes a VkPhysicalDeviceVulkan12Features structure, then it must not include a VkPhysicalDevice8BitStorageFeatures, VkPhysicalDeviceShaderAtomicInt64Features, VkPhysicalDeviceShaderFloat16Int8Features, VkPhysicalDeviceDescriptorIndexingFeatures, VkPhysicalDeviceScalarBlockLayoutFeatures, VkPhysicalDeviceImagelessFramebufferFeatures, VkPhysicalDeviceUniformBufferStandardLayoutFeatures, VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures, VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures, VkPhysicalDeviceHostQueryResetFeatures, VkPhysicalDeviceTimelineSemaphoreFeatures, VkPhysicalDeviceBufferDeviceAddressFeatures, or VkPhysicalDeviceVulkanMemoryModelFeatures structure (https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-VkDeviceCreateInfo-pNext-02830)
    2022-11-05T00:18:39.548723Z ERROR wgpu_hal::vulkan::instance:   objects: (type: INSTANCE, hndl: 0x55d6e0ac6500, name: ?)
    2022-11-05T00:18:39.598406Z ERROR wgpu_hal::vulkan::instance: VALIDATION [VUID-VkDescriptorSetLayoutCreateInfo-descriptorType-03001 (0x8ac432cd)]
            Validation Error: [ VUID-VkDescriptorSetLayoutCreateInfo-descriptorType-03001 ] Object 0: handle = 0x55d6e13a95a0, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0x8ac432cd | vkCreateDescriptorSetLayout(): binding (8) has VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT flag, but binding (1) has descriptor type VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC. The Vulkan spec states: If any binding has the VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT bit set, then all bindings must not have descriptorType of VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC or VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC (https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-VkDescriptorSetLayoutCreateInfo-descriptorType-03001)
    2022-11-05T00:18:39.598511Z ERROR wgpu_hal::vulkan::instance
    

    and heres a screenshot: 20221104_19h17m54s_grim

    opened by Vixeliz 1
  • Update to Bevy 0.9

    Update to Bevy 0.9

    • [x] Ui example is broken. Fix it or drop the feature. Removed
    • [x] release bevy_pancam for Bevy 0.9
    • [x] wait for bevy_asset_loader to release for Bevy 0.9
    enhancement 
    opened by johanhelsing 0
  • Fix time uniform alignment on wasm yet again

    Fix time uniform alignment on wasm yet again

    I'm not completely sure what broke it, but I took some inspiration from recent fixes to Bevy's GlobalsUniform and got it working again.

    And a couple of drive-by fixes

    opened by johanhelsing 0
  • Shaders that make use of `time.seconds_since_startup` don't work on wasm

    Shaders that make use of `time.seconds_since_startup` don't work on wasm

    Currently if sdfs make use of time, they will not show on wasm.

    The time uniform code is based on the animate_shader example in the bevy repo, which has the same problem (so solution should also be the same).

    https://github.com/bevyengine/bevy/issues/4813

    bug wasm 
    opened by johanhelsing 0
  • Add time uniform

    Add time uniform

    Based on https://github.com/omphalosprime/bevy_smud/commit/72b2043082d0fb51f487675b0c65d37d5d46dcaa#diff-b1a35a68f14e696205874893c07fd24fdb88882b47c23cc0e0c80a30c7d53759R88

    Closes: #2

    enhancement 
    opened by johanhelsing 0
  • Add time uniform

    Add time uniform

    I think using time to animate things in shaders is such a basic thing to want that it should probably just always be available. It allows implementing really cool stuff with very little effort.

    Also, the performance overhead of needlessly adding the time uniform when not used is probably very low (but should double check this)

    @omphalosprime did this in their fork: https://github.com/omphalosprime/bevy_smud/commit/72b2043082d0fb51f487675b0c65d37d5d46dcaa

    Also relevant: https://github.com/bevyengine/bevy/blob/main/examples/shader/animate_shader.rs

    enhancement good first issue 
    opened by johanhelsing 0
  • Allow supplying a dynamic number of positions

    Allow supplying a dynamic number of positions

    It seems like currently only one dynamic position is supplied to the sdf function. I would prefer if the user could define how many dynamic positions you supply to each shader. At least up to 4 positions would be necessary for common bezier curves. Having dynamic curves is pretty important for my use cases.

    enhancement 
    opened by porky11 1
  • Add params for sdfs

    Add params for sdfs

    • [x] add a working example
    • [ ] try to make it backwards compatible
    • [ ] or fix the examples I broke
    • [ ] update documentation
    • [ ] avoid overhead when not needed/used?
    • [ ] see if it can be generalized to n parameters?

    image

    Fixes: #3

    opened by johanhelsing 0
  • Pass custom instance data to sdf shader function (to allow single-shader parametrized shapes)

    Pass custom instance data to sdf shader function (to allow single-shader parametrized shapes)

    For some shapes, for instance rectangles, circles, rounded rectangels, it makes a lot of sense to be able to send per instance data into the sdf function so you could change side length/radius without compiling a new shader.

    I'm not really sure what the best way to implement this would be... One simple way could be to just have a couple of floats of "user data" that will just always be passed around. It may come with a performance cost, though.

    Perhaps some way to toggle it with shader defs would be good, and then have it be an optional component SdfParameters(Vec4) so we don't pay the price for it when not used.

    enhancement 
    opened by johanhelsing 0
Releases(v0.4.0)
  • v0.4.0(Nov 20, 2022)

    What's Changed

    • Add rust docs for everything #21
    • bevy-inspector-egui feature is now replaced by simple Reflect derives
    • time global has now been replaced by the new globals struct in Bevy. See time example.
    • Update to Bevy 0.9 by @johanhelsing in https://github.com/johanhelsing/bevy_smud/pull/20

    Full Changelog: https://github.com/johanhelsing/bevy_smud/compare/v0.3.1...v0.4.0

    Source code(tar.gz)
    Source code(zip)
  • v0.3.1(Nov 13, 2022)

    What's Changed

    • Fix time uniform alignment on wasm yet again by @johanhelsing in https://github.com/johanhelsing/bevy_smud/pull/19

    Full Changelog: https://github.com/johanhelsing/bevy_smud/compare/v0.3.0...v0.3.1

    Source code(tar.gz)
    Source code(zip)
  • v0.3.0(Aug 11, 2022)

    What's Changed

    • Upgrade to Bevy 0.8
    • Add bevy-inspector-egui integration by @johanhelsing in https://github.com/johanhelsing/bevy_smud/pull/6
    • Add time uniform by @johanhelsing in https://github.com/johanhelsing/bevy_smud/pull/12

    Full Changelog: https://github.com/johanhelsing/bevy_smud/compare/v0.2.0...v0.3.0

    Source code(tar.gz)
    Source code(zip)
  • v0.2.0(Apr 18, 2022)

  • v0.1.1(Feb 22, 2022)

  • v0.1.0(Feb 22, 2022)

Owner
Johan Klokkhammer Helsing
Making names and taking games
Johan Klokkhammer Helsing
Pixel-Perfect, 2D Renderer for Bevy that Seamlessly Targets Desktop and Web

bevy_retro ( Screenshot of Bounty Bros. game made with Bevy Retro and Skip'n Go ) Bevy Retro is a 2D, pixel-perfect renderer for Bevy that can target

Katharos Technology 224 Dec 23, 2022
A plugin to use the kajiya renderer with bevy

??️ ?? bevy-kajiya A plugin that enables use of the kajiya renderer in bevy WARNING: This plugin is barebones and supports a limited set of features.

Sebastian Hamel 79 Jan 5, 2023
Rust-based replacement for the default Minecraft renderer

wgpu-mc ?? A blazing fast alternative renderer for Minecraft Intro WebGPU is a new web specification designed to provide modern graphics and compute c

Birb 1 Jun 28, 2022
Text Renderer written in Rust using HarfBuzz for shaping, FreeType for rasterization and OpenGL for rendering.

Provok Text Renderer written in Rust using HarfBuzz for shaping, FreeType for rasterization and OpenGL for rendering. Input Provok is fed with a JSON

Ossama Hjaji 67 Dec 10, 2022
A high-performance renderer to render glTF models that use the `KHR_materials_transmission` and `KHR_materials_volume` extensions.

This is a high-performance renderer designed among other things to render glTF models that use the KHR_materials_transmission and KHR_materials_volume

Ashley 21 Dec 5, 2022
🦅🦁 Fast, simple 2D text renderer for wgpu

?? glyphon ?? Fast, simple 2D text rendering for wgpu What is this? This crate provides a simple way to render 2D text with wgpu by: rasterizing glyph

Josh Groves 60 Nov 5, 2022
Renderer-agnostic toolkit for Indie Game Developers

Indie Toolkit Renderer-agnostic toolkit for Indie Game Developers Features Not yet implemented: app_kit debug_kit input_kit asset_kit audio_kit Implem

null 2 May 25, 2022
Minecraft-esque voxel engine prototype made with the bevy game engine. Pending bevy 0.6 release to undergo a full rewrite.

vx_bevy A voxel engine prototype made using the Bevy game engine. Goals and features Very basic worldgen Animated chunk loading (ala cube world) Optim

Lucas Arriesse 125 Dec 31, 2022
bevy-hikari is an implementation of voxel cone tracing global illumination with anisotropic mip-mapping in Bevy

Bevy Voxel Cone Tracing bevy-hikari is an implementation of voxel cone tracing global illumination with anisotropic mip-mapping in Bevy. Bevy Version

研究社交 208 Dec 27, 2022
A simple extension for `bevy-editor-pls` to support tilemap editing right inside the bevy app.

What is this This is a simple tilemap editor plugin, that hooks right into bevy_editor_pls to work with bevy_ecs_tilemap. It works completely within i

null 3 May 8, 2023
Bevy Simple Portals is a Bevy game engine plugin aimed to create portals.

Portals for Bevy Bevy Simple Portals is a Bevy game engine plugin aimed to create portals. Those portals are (for now) purely visual and can be used t

Sélène Amanita 11 May 28, 2023
Minecraft using Bevy and Bevy-Meshem

minecraft_bevy Minecraft_bevy was built to showcase bevy_meshem. After a week of developing it has: Chunk loading / unloading each chunk's mesh is bei

Adam 7 Oct 4, 2023
A Bevy plugin for loading the LDtk 2D tile map format.

bevy_ldtk ( Tileset from "Cavernas" by Adam Saltsman ) A Bevy plugin for loading LDtk tile maps. Usage use bevy::prelude::*; use bevy_ldtk::*; fn mai

Katharos Technology 23 Jul 4, 2022
Basic first-person fly camera for the Bevy game engine

bevy_flycam A basic first-person fly camera for Bevy 0.4 Controls WASD to move horizontally SPACE to ascend LSHIFT to descend ESC to grab/release curs

Spencer Burris 85 Dec 23, 2022
An ergonomic physics API for bevy games.

Heron An ergonomic physics API for 2d and 3d bevy games. (powered by rapier) How it looks like fn main() { App::build() .add_plugins(DefaultPlug

Jonathan Cornaz 313 Dec 16, 2022
Inspector plugin for the bevy game engine

bevy-inspector-egui This crate provides the ability to annotate structs with a #[derive(Inspectable)], which opens a debug interface using egui where

Jakob Hellermann 517 Dec 31, 2022
A plugin for Egui integration into Bevy

bevy_egui This crate provides a Egui integration for the Bevy game engine. Features: Desktop and web (bevy_webgl2) platforms support Clipboard (web su

Vladyslav Batyrenko 453 Jan 3, 2023
Crossterm plugin for the bevy game engine

What is bevy_crossterm? bevy_crossterm is a Bevy plugin that uses crossterm as a renderer. It provides custom components and events which allow users

null 79 Nov 2, 2022
A 4X style camera for bevy.

A 4X style camera for bevy. Demo Default Key Bindings: W / A / S / D / Arrow Keys / Mouse Left - Move along the horizontal plane Q / E / Mouse Right -

null 30 Jan 4, 2023