Making bevy_render an optional dependency for bevy_gizmos (#14448)

# Objective

This PR makes `bevy_render` an optional dependency for `bevy_gizmos`,
thereby allowing `bevy_gizmos` to be used with alternative rendering
backend.

Previously `bevy_gizmos` assumes that one of `bevy_pbr` or `bevy_sprite`
will be enabled. Here we introduced a new feature named `bevy_render`
which disables all rendering-related code paths. An alternative renderer
will then take the `LineGizmo` assets (made public in this PR) and issue
draw calls on their own. A new field `config_ty` was added to
`LineGizmo` to help looking up the related configuration info.

---

## Migration Guide
No user-visible changes needed from the users.
This commit is contained in:
Zhixing Zhang 2024-08-06 07:09:10 -06:00 committed by GitHub
parent e85c072372
commit 5fd0661c15
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 103 additions and 67 deletions

View File

@ -91,6 +91,10 @@ impl AssetProcessor {
Self { server, data } Self { server, data }
} }
pub fn data(&self) -> &Arc<AssetProcessorData> {
&self.data
}
/// The "internal" [`AssetServer`] used by the [`AssetProcessor`]. This is _separate_ from the asset processor used by /// The "internal" [`AssetServer`] used by the [`AssetProcessor`]. This is _separate_ from the asset processor used by
/// the main App. It has different processor-specific configuration and a different ID space. /// the main App. It has different processor-specific configuration and a different ID space.
pub fn server(&self) -> &AssetServer { pub fn server(&self) -> &AssetServer {

View File

@ -11,6 +11,7 @@ keywords = ["bevy"]
[features] [features]
webgl = [] webgl = []
webgpu = [] webgpu = []
bevy_render = ["dep:bevy_render", "bevy_core_pipeline"]
[dependencies] [dependencies]
# Bevy # Bevy
@ -21,10 +22,10 @@ bevy_color = { path = "../bevy_color", version = "0.15.0-dev" }
bevy_ecs = { path = "../bevy_ecs", version = "0.15.0-dev" } bevy_ecs = { path = "../bevy_ecs", version = "0.15.0-dev" }
bevy_math = { path = "../bevy_math", version = "0.15.0-dev" } bevy_math = { path = "../bevy_math", version = "0.15.0-dev" }
bevy_asset = { path = "../bevy_asset", version = "0.15.0-dev" } bevy_asset = { path = "../bevy_asset", version = "0.15.0-dev" }
bevy_render = { path = "../bevy_render", version = "0.15.0-dev" } bevy_render = { path = "../bevy_render", version = "0.15.0-dev", optional = true }
bevy_utils = { path = "../bevy_utils", version = "0.15.0-dev" } bevy_utils = { path = "../bevy_utils", version = "0.15.0-dev" }
bevy_reflect = { path = "../bevy_reflect", version = "0.15.0-dev" } bevy_reflect = { path = "../bevy_reflect", version = "0.15.0-dev" }
bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.15.0-dev" } bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.15.0-dev", optional = true }
bevy_transform = { path = "../bevy_transform", version = "0.15.0-dev" } bevy_transform = { path = "../bevy_transform", version = "0.15.0-dev" }
bevy_gizmos_macros = { path = "macros", version = "0.15.0-dev" } bevy_gizmos_macros = { path = "macros", version = "0.15.0-dev" }
bevy_time = { path = "../bevy_time", version = "0.15.0-dev" } bevy_time = { path = "../bevy_time", version = "0.15.0-dev" }

View File

@ -5,7 +5,6 @@ pub use bevy_gizmos_macros::GizmoConfigGroup;
use bevy_ecs::{component::Component, reflect::ReflectResource, system::Resource}; use bevy_ecs::{component::Component, reflect::ReflectResource, system::Resource};
use bevy_reflect::{std_traits::ReflectDefault, Reflect, TypePath}; use bevy_reflect::{std_traits::ReflectDefault, Reflect, TypePath};
use bevy_render::view::RenderLayers;
use bevy_utils::TypeIdMap; use bevy_utils::TypeIdMap;
use core::panic; use core::panic;
use std::{ use std::{
@ -164,7 +163,8 @@ pub struct GizmoConfig {
/// Describes which rendering layers gizmos will be rendered to. /// Describes which rendering layers gizmos will be rendered to.
/// ///
/// Gizmos will only be rendered to cameras with intersecting layers. /// Gizmos will only be rendered to cameras with intersecting layers.
pub render_layers: RenderLayers, #[cfg(feature = "bevy_render")]
pub render_layers: bevy_render::view::RenderLayers,
/// Describe how lines should join /// Describe how lines should join
pub line_joints: GizmoLineJoint, pub line_joints: GizmoLineJoint,
@ -178,6 +178,7 @@ impl Default for GizmoConfig {
line_perspective: false, line_perspective: false,
line_style: GizmoLineStyle::Solid, line_style: GizmoLineStyle::Solid,
depth_bias: 0., depth_bias: 0.,
#[cfg(feature = "bevy_render")]
render_layers: Default::default(), render_layers: Default::default(),
line_joints: GizmoLineJoint::None, line_joints: GizmoLineJoint::None,
@ -185,13 +186,15 @@ impl Default for GizmoConfig {
} }
} }
#[cfg(feature = "bevy_render")]
#[derive(Component)] #[derive(Component)]
pub(crate) struct GizmoMeshConfig { pub(crate) struct GizmoMeshConfig {
pub line_perspective: bool, pub line_perspective: bool,
pub line_style: GizmoLineStyle, pub line_style: GizmoLineStyle,
pub render_layers: RenderLayers, pub render_layers: bevy_render::view::RenderLayers,
} }
#[cfg(feature = "bevy_render")]
impl From<&GizmoConfig> for GizmoMeshConfig { impl From<&GizmoConfig> for GizmoMeshConfig {
fn from(item: &GizmoConfig) -> Self { fn from(item: &GizmoConfig) -> Self {
GizmoMeshConfig { GizmoMeshConfig {

View File

@ -31,6 +31,7 @@ pub enum GizmoRenderSystem {
QueueLineGizmos3d, QueueLineGizmos3d,
} }
#[cfg(feature = "bevy_render")]
pub mod aabb; pub mod aabb;
pub mod arcs; pub mod arcs;
pub mod arrows; pub mod arrows;
@ -42,19 +43,20 @@ pub mod grid;
pub mod primitives; pub mod primitives;
pub mod rounded_box; pub mod rounded_box;
#[cfg(feature = "bevy_pbr")] #[cfg(all(feature = "bevy_pbr", feature = "bevy_render"))]
pub mod light; pub mod light;
#[cfg(feature = "bevy_sprite")] #[cfg(all(feature = "bevy_sprite", feature = "bevy_render"))]
mod pipeline_2d; mod pipeline_2d;
#[cfg(feature = "bevy_pbr")] #[cfg(all(feature = "bevy_pbr", feature = "bevy_render"))]
mod pipeline_3d; mod pipeline_3d;
/// The `bevy_gizmos` prelude. /// The `bevy_gizmos` prelude.
pub mod prelude { pub mod prelude {
#[cfg(feature = "bevy_render")]
pub use crate::aabb::{AabbGizmoConfigGroup, ShowAabbGizmo};
#[doc(hidden)] #[doc(hidden)]
pub use crate::{ pub use crate::{
aabb::{AabbGizmoConfigGroup, ShowAabbGizmo},
config::{ config::{
DefaultGizmoConfigGroup, GizmoConfig, GizmoConfigGroup, GizmoConfigStore, DefaultGizmoConfigGroup, GizmoConfig, GizmoConfigGroup, GizmoConfigStore,
GizmoLineJoint, GizmoLineStyle, GizmoLineJoint, GizmoLineStyle,
@ -64,13 +66,12 @@ pub mod prelude {
AppGizmoBuilder, AppGizmoBuilder,
}; };
#[cfg(feature = "bevy_pbr")] #[cfg(all(feature = "bevy_pbr", feature = "bevy_render"))]
pub use crate::light::{LightGizmoColor, LightGizmoConfigGroup, ShowLightGizmo}; pub use crate::light::{LightGizmoColor, LightGizmoConfigGroup, ShowLightGizmo};
} }
use aabb::AabbGizmoPlugin;
use bevy_app::{App, FixedFirst, FixedLast, Last, Plugin, RunFixedMainLoop}; use bevy_app::{App, FixedFirst, FixedLast, Last, Plugin, RunFixedMainLoop};
use bevy_asset::{load_internal_asset, Asset, AssetApp, Assets, Handle}; use bevy_asset::{Asset, AssetApp, Assets, Handle};
use bevy_color::LinearRgba; use bevy_color::LinearRgba;
use bevy_ecs::{ use bevy_ecs::{
component::Component, component::Component,
@ -83,6 +84,7 @@ use bevy_ecs::{
}; };
use bevy_math::Vec3; use bevy_math::Vec3;
use bevy_reflect::TypePath; use bevy_reflect::TypePath;
#[cfg(feature = "bevy_render")]
use bevy_render::{ use bevy_render::{
extract_component::{ComponentUniforms, DynamicUniformIndex, UniformComponentPlugin}, extract_component::{ComponentUniforms, DynamicUniformIndex, UniformComponentPlugin},
render_asset::{PrepareAssetError, RenderAsset, RenderAssetPlugin, RenderAssets}, render_asset::{PrepareAssetError, RenderAsset, RenderAssetPlugin, RenderAssets},
@ -100,14 +102,15 @@ use bevy_utils::TypeIdMap;
use bytemuck::cast_slice; use bytemuck::cast_slice;
use config::{ use config::{
DefaultGizmoConfigGroup, GizmoConfig, GizmoConfigGroup, GizmoConfigStore, GizmoLineJoint, DefaultGizmoConfigGroup, GizmoConfig, GizmoConfigGroup, GizmoConfigStore, GizmoLineJoint,
GizmoMeshConfig,
}; };
use gizmos::{GizmoStorage, Swap}; use gizmos::{GizmoStorage, Swap};
#[cfg(feature = "bevy_pbr")] #[cfg(feature = "bevy_pbr")]
use light::LightGizmoPlugin; use light::LightGizmoPlugin;
use std::{any::TypeId, mem}; use std::{any::TypeId, mem};
#[cfg(feature = "bevy_render")]
const LINE_SHADER_HANDLE: Handle<Shader> = Handle::weak_from_u128(7414812689238026784); const LINE_SHADER_HANDLE: Handle<Shader> = Handle::weak_from_u128(7414812689238026784);
#[cfg(feature = "bevy_render")]
const LINE_JOINT_SHADER_HANDLE: Handle<Shader> = Handle::weak_from_u128(1162780797909187908); const LINE_JOINT_SHADER_HANDLE: Handle<Shader> = Handle::weak_from_u128(1162780797909187908);
/// A [`Plugin`] that provides an immediate mode drawing api for visual debugging. /// A [`Plugin`] that provides an immediate mode drawing api for visual debugging.
@ -118,58 +121,60 @@ pub struct GizmoPlugin;
impl Plugin for GizmoPlugin { impl Plugin for GizmoPlugin {
fn build(&self, app: &mut bevy_app::App) { fn build(&self, app: &mut bevy_app::App) {
// Gizmos cannot work without either a 3D or 2D renderer. #[cfg(feature = "bevy_render")]
#[cfg(all(not(feature = "bevy_pbr"), not(feature = "bevy_sprite")))] {
bevy_utils::tracing::error!( use bevy_asset::load_internal_asset;
"bevy_gizmos requires either bevy_pbr or bevy_sprite. Please enable one." load_internal_asset!(app, LINE_SHADER_HANDLE, "lines.wgsl", Shader::from_wgsl);
); load_internal_asset!(
app,
load_internal_asset!(app, LINE_SHADER_HANDLE, "lines.wgsl", Shader::from_wgsl); LINE_JOINT_SHADER_HANDLE,
load_internal_asset!( "line_joints.wgsl",
app, Shader::from_wgsl
LINE_JOINT_SHADER_HANDLE, );
"line_joints.wgsl", }
Shader::from_wgsl
);
app.register_type::<GizmoConfig>() app.register_type::<GizmoConfig>()
.register_type::<GizmoConfigStore>() .register_type::<GizmoConfigStore>()
.add_plugins(UniformComponentPlugin::<LineGizmoUniform>::default())
.init_asset::<LineGizmo>() .init_asset::<LineGizmo>()
.add_plugins(RenderAssetPlugin::<GpuLineGizmo>::default())
.init_resource::<LineGizmoHandles>() .init_resource::<LineGizmoHandles>()
// We insert the Resource GizmoConfigStore into the world implicitly here if it does not exist. // We insert the Resource GizmoConfigStore into the world implicitly here if it does not exist.
.init_gizmo_group::<DefaultGizmoConfigGroup>() .init_gizmo_group::<DefaultGizmoConfigGroup>();
.add_plugins(AabbGizmoPlugin);
#[cfg(feature = "bevy_render")]
app.add_plugins(aabb::AabbGizmoPlugin)
.add_plugins(UniformComponentPlugin::<LineGizmoUniform>::default())
.add_plugins(RenderAssetPlugin::<GpuLineGizmo>::default());
#[cfg(feature = "bevy_pbr")] #[cfg(feature = "bevy_pbr")]
app.add_plugins(LightGizmoPlugin); app.add_plugins(LightGizmoPlugin);
let Some(render_app) = app.get_sub_app_mut(RenderApp) else { #[cfg(feature = "bevy_render")]
return; if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
}; render_app.add_systems(
Render,
prepare_line_gizmo_bind_group.in_set(RenderSet::PrepareBindGroups),
);
render_app.add_systems( render_app.add_systems(ExtractSchedule, extract_gizmo_data);
Render,
prepare_line_gizmo_bind_group.in_set(RenderSet::PrepareBindGroups),
);
render_app.add_systems(ExtractSchedule, extract_gizmo_data); #[cfg(feature = "bevy_sprite")]
if app.is_plugin_added::<bevy_sprite::SpritePlugin>() {
#[cfg(feature = "bevy_sprite")] app.add_plugins(pipeline_2d::LineGizmo2dPlugin);
if app.is_plugin_added::<bevy_sprite::SpritePlugin>() { } else {
app.add_plugins(pipeline_2d::LineGizmo2dPlugin); bevy_utils::tracing::warn!("bevy_sprite feature is enabled but bevy_sprite::SpritePlugin was not detected. Are you sure you loaded GizmoPlugin after SpritePlugin?");
}
#[cfg(feature = "bevy_pbr")]
if app.is_plugin_added::<bevy_pbr::PbrPlugin>() {
app.add_plugins(pipeline_3d::LineGizmo3dPlugin);
} else {
bevy_utils::tracing::warn!("bevy_pbr feature is enabled but bevy_pbr::PbrPlugin was not detected. Are you sure you loaded GizmoPlugin after PbrPlugin?");
}
} else { } else {
bevy_utils::tracing::warn!("bevy_sprite feature is enabled but bevy_sprite::SpritePlugin was not detected. Are you sure you loaded GizmoPlugin after SpritePlugin?"); bevy_utils::tracing::warn!("bevy_render feature is enabled but RenderApp was not detected. Are you sure you loaded GizmoPlugin after RenderPlugin?");
}
#[cfg(feature = "bevy_pbr")]
if app.is_plugin_added::<bevy_pbr::PbrPlugin>() {
app.add_plugins(pipeline_3d::LineGizmo3dPlugin);
} else {
bevy_utils::tracing::warn!("bevy_pbr feature is enabled but bevy_pbr::PbrPlugin was not detected. Are you sure you loaded GizmoPlugin after PbrPlugin?");
} }
} }
#[cfg(feature = "bevy_render")]
fn finish(&self, app: &mut bevy_app::App) { fn finish(&self, app: &mut bevy_app::App) {
let Some(render_app) = app.get_sub_app_mut(RenderApp) else { let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
return; return;
@ -361,14 +366,14 @@ fn update_gizmo_meshes<Config: GizmoConfigGroup>(
list.positions = mem::take(&mut storage.list_positions); list.positions = mem::take(&mut storage.list_positions);
list.colors = mem::take(&mut storage.list_colors); list.colors = mem::take(&mut storage.list_colors);
} else { } else {
let mut list = LineGizmo { let list = LineGizmo {
strip: false, strip: false,
..Default::default() config_ty: TypeId::of::<Config>(),
positions: mem::take(&mut storage.list_positions),
colors: mem::take(&mut storage.list_colors),
joints: GizmoLineJoint::None,
}; };
list.positions = mem::take(&mut storage.list_positions);
list.colors = mem::take(&mut storage.list_colors);
*handle = Some(line_gizmos.add(list)); *handle = Some(line_gizmos.add(list));
} }
} }
@ -384,20 +389,20 @@ fn update_gizmo_meshes<Config: GizmoConfigGroup>(
strip.colors = mem::take(&mut storage.strip_colors); strip.colors = mem::take(&mut storage.strip_colors);
strip.joints = config.line_joints; strip.joints = config.line_joints;
} else { } else {
let mut strip = LineGizmo { let strip = LineGizmo {
strip: true, strip: true,
joints: config.line_joints, joints: config.line_joints,
..Default::default() config_ty: TypeId::of::<Config>(),
positions: mem::take(&mut storage.strip_positions),
colors: mem::take(&mut storage.strip_colors),
}; };
strip.positions = mem::take(&mut storage.strip_positions);
strip.colors = mem::take(&mut storage.strip_colors);
*handle = Some(line_gizmos.add(strip)); *handle = Some(line_gizmos.add(strip));
} }
} }
} }
#[cfg(feature = "bevy_render")]
fn extract_gizmo_data( fn extract_gizmo_data(
mut commands: Commands, mut commands: Commands,
handles: Extract<Res<LineGizmoHandles>>, handles: Extract<Res<LineGizmoHandles>>,
@ -431,11 +436,12 @@ fn extract_gizmo_data(
_padding: Default::default(), _padding: Default::default(),
}, },
(*handle).clone_weak(), (*handle).clone_weak(),
GizmoMeshConfig::from(config), config::GizmoMeshConfig::from(config),
)); ));
} }
} }
#[cfg(feature = "bevy_render")]
#[derive(Component, ShaderType, Clone, Copy)] #[derive(Component, ShaderType, Clone, Copy)]
struct LineGizmoUniform { struct LineGizmoUniform {
line_width: f32, line_width: f32,
@ -447,16 +453,22 @@ struct LineGizmoUniform {
_padding: f32, _padding: f32,
} }
#[derive(Asset, Debug, Default, Clone, TypePath)] /// A gizmo asset that represents a line.
struct LineGizmo { #[derive(Asset, Debug, Clone, TypePath)]
positions: Vec<Vec3>, pub struct LineGizmo {
colors: Vec<LinearRgba>, /// Positions of the gizmo's vertices
pub positions: Vec<Vec3>,
/// Colors of the gizmo's vertices
pub colors: Vec<LinearRgba>,
/// Whether this gizmo's topology is a line-strip or line-list /// Whether this gizmo's topology is a line-strip or line-list
strip: bool, pub strip: bool,
/// Whether this gizmo should draw line joints. This is only applicable if the gizmo's topology is line-strip. /// Whether this gizmo should draw line joints. This is only applicable if the gizmo's topology is line-strip.
joints: GizmoLineJoint, pub joints: GizmoLineJoint,
/// The type of the gizmo's configuration group
pub config_ty: TypeId,
} }
#[cfg(feature = "bevy_render")]
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct GpuLineGizmo { struct GpuLineGizmo {
position_buffer: Buffer, position_buffer: Buffer,
@ -466,6 +478,7 @@ struct GpuLineGizmo {
joints: GizmoLineJoint, joints: GizmoLineJoint,
} }
#[cfg(feature = "bevy_render")]
impl RenderAsset for GpuLineGizmo { impl RenderAsset for GpuLineGizmo {
type SourceAsset = LineGizmo; type SourceAsset = LineGizmo;
type Param = SRes<RenderDevice>; type Param = SRes<RenderDevice>;
@ -498,16 +511,19 @@ impl RenderAsset for GpuLineGizmo {
} }
} }
#[cfg(feature = "bevy_render")]
#[derive(Resource)] #[derive(Resource)]
struct LineGizmoUniformBindgroupLayout { struct LineGizmoUniformBindgroupLayout {
layout: BindGroupLayout, layout: BindGroupLayout,
} }
#[cfg(feature = "bevy_render")]
#[derive(Resource)] #[derive(Resource)]
struct LineGizmoUniformBindgroup { struct LineGizmoUniformBindgroup {
bindgroup: BindGroup, bindgroup: BindGroup,
} }
#[cfg(feature = "bevy_render")]
fn prepare_line_gizmo_bind_group( fn prepare_line_gizmo_bind_group(
mut commands: Commands, mut commands: Commands,
line_gizmo_uniform_layout: Res<LineGizmoUniformBindgroupLayout>, line_gizmo_uniform_layout: Res<LineGizmoUniformBindgroupLayout>,
@ -525,7 +541,9 @@ fn prepare_line_gizmo_bind_group(
} }
} }
#[cfg(feature = "bevy_render")]
struct SetLineGizmoBindGroup<const I: usize>; struct SetLineGizmoBindGroup<const I: usize>;
#[cfg(feature = "bevy_render")]
impl<const I: usize, P: PhaseItem> RenderCommand<P> for SetLineGizmoBindGroup<I> { impl<const I: usize, P: PhaseItem> RenderCommand<P> for SetLineGizmoBindGroup<I> {
type Param = SRes<LineGizmoUniformBindgroup>; type Param = SRes<LineGizmoUniformBindgroup>;
type ViewQuery = (); type ViewQuery = ();
@ -551,7 +569,9 @@ impl<const I: usize, P: PhaseItem> RenderCommand<P> for SetLineGizmoBindGroup<I>
} }
} }
#[cfg(feature = "bevy_render")]
struct DrawLineGizmo; struct DrawLineGizmo;
#[cfg(feature = "bevy_render")]
impl<P: PhaseItem> RenderCommand<P> for DrawLineGizmo { impl<P: PhaseItem> RenderCommand<P> for DrawLineGizmo {
type Param = SRes<RenderAssets<GpuLineGizmo>>; type Param = SRes<RenderAssets<GpuLineGizmo>>;
type ViewQuery = (); type ViewQuery = ();
@ -597,7 +617,9 @@ impl<P: PhaseItem> RenderCommand<P> for DrawLineGizmo {
} }
} }
#[cfg(feature = "bevy_render")]
struct DrawLineJointGizmo; struct DrawLineJointGizmo;
#[cfg(feature = "bevy_render")]
impl<P: PhaseItem> RenderCommand<P> for DrawLineJointGizmo { impl<P: PhaseItem> RenderCommand<P> for DrawLineJointGizmo {
type Param = SRes<RenderAssets<GpuLineGizmo>>; type Param = SRes<RenderAssets<GpuLineGizmo>>;
type ViewQuery = (); type ViewQuery = ();
@ -649,6 +671,7 @@ impl<P: PhaseItem> RenderCommand<P> for DrawLineJointGizmo {
} }
} }
#[cfg(feature = "bevy_render")]
fn line_gizmo_vertex_buffer_layouts(strip: bool) -> Vec<VertexBufferLayout> { fn line_gizmo_vertex_buffer_layouts(strip: bool) -> Vec<VertexBufferLayout> {
use VertexFormat::*; use VertexFormat::*;
let mut position_layout = VertexBufferLayout { let mut position_layout = VertexBufferLayout {
@ -705,6 +728,7 @@ fn line_gizmo_vertex_buffer_layouts(strip: bool) -> Vec<VertexBufferLayout> {
} }
} }
#[cfg(feature = "bevy_render")]
fn line_joint_gizmo_vertex_buffer_layouts() -> Vec<VertexBufferLayout> { fn line_joint_gizmo_vertex_buffer_layouts() -> Vec<VertexBufferLayout> {
use VertexFormat::*; use VertexFormat::*;
let mut position_layout = VertexBufferLayout { let mut position_layout = VertexBufferLayout {

View File

@ -152,7 +152,11 @@ accesskit_unix = ["bevy_winit/accesskit_unix"]
bevy_text = ["dep:bevy_text", "bevy_ui?/bevy_text"] bevy_text = ["dep:bevy_text", "bevy_ui?/bevy_text"]
bevy_render = ["dep:bevy_render", "bevy_scene?/bevy_render"] bevy_render = [
"dep:bevy_render",
"bevy_scene?/bevy_render",
"bevy_gizmos?/bevy_render",
]
# Enable assertions to check the validity of parameters passed to glam # Enable assertions to check the validity of parameters passed to glam
glam_assert = ["bevy_math/glam_assert"] glam_assert = ["bevy_math/glam_assert"]