Bevy 0.8
发布于 2022 年 7 月 30 日 作者 Carter Anderson ( @cart @cart_cart cartdev )
感谢 130 位贡献者、461 个拉取请求、社区审阅者以及我们的 慷慨赞助商,我很高兴地宣布 Bevy 0.8 版本已发布至 crates.io!
对于那些不了解 Bevy 的人来说,Bevy 是一个用 Rust 构建的新鲜且简单的、数据驱动的游戏引擎。您可以查看我们的 快速入门指南 以立即尝试它。它永远免费且开源!您可以在 GitHub 上获取完整的 源代码。查看 Bevy 资源 以获取社区开发的插件、游戏和学习资源集合。
要将现有 Bevy 应用或插件更新至 Bevy 0.8,请查看我们的 0.7 到 0.8 迁移指南。
自从我们几个月前的上一次发布以来,我们添加了许多新功能、错误修复和生活质量调整,但以下是一些亮点。
- 新材质系统:现在定义自定义着色器变得容易多了,这要归功于新的 Material 特性以及 AsBindGroup 派生。
- 相机驱动渲染:每个相机现在都配置了它渲染的内容以及渲染方式。轻松地将相机渲染层叠在一起,进行分屏或只需几行代码即可将渲染结果写入纹理。
- 内置着色器模块化:现在可以导入许多内置着色器类型和函数。值得注意的是,自定义着色器现在可以导入 PBR 着色器逻辑。
- 聚光灯:一种新的光源类型,它从固定点以锥形形状发射光线。
- 可见性继承:隐藏实体现在还会隐藏其在层次结构中的所有子实体。
- 升级至 wgpu 0.13:使用新的、更符合人体工学的 WGSL 着色器语法。
- 自动网格切线生成:如果网格缺少切线,则使用 mikktspace 生成它们。
- 渲染器优化:并行视锥剔除和针对未批处理渲染阶段的不稳定排序取得了巨大成功!
- 场景包:使用普通的 Bevy 包轻松生成场景,并使用新的组件和子实体扩展它们。
- 脚本和修改进展:无类型 ECS API:朝着第三方脚本语言支持迈出了一步!通过指针直接与 Bevy ECS 内部进行交互。
- ECS 查询人体工学和可用性:查询现在实现了
IntoIter
,可变查询可以转换为不可变查询。 - ECS 内部重构:对 Bevy ECS 内部进行了重大更改,使其更简单、更安全、更易于维护。
- 反射改进:支持反射更多类型,ECS 资源反射,无类型反射,改进的内部机制。
- 层次结构命令:层次结构更新现在使用“事务性命令”来确保始终保持层次结构的一致性。
- Bevy UI 现在使用 Taffy:我们已切换到(并帮助维护)现在已废弃的 Stretch UI 布局库的协作分支。指数级爆炸错误不再存在!
新材质系统 #
Bevy 拥有全新的 Material
系统,它让定义自定义着色器变得轻而易举。Bevy 之前的材质系统需要数百行“中级”样板代码。这从来都不是长期的计划,只是中间步骤。在 Bevy 0.8 中,自定义着色器材质就像下面这样简单
#[derive(AsBindGroup, TypeUuid, Clone)]
#[uuid = "f690fdae-d598-45ab-8225-97e2a3f056e0"]
pub struct CoolMaterial {
#[uniform(0)]
color: Color,
#[texture(1)]
#[sampler(2)]
color_texture: Handle<Image>,
}
// The Material trait has many optional functions for configuration.
// In this case, all we need to set is a fragment shader. Ergonomics!
impl Material for CoolMaterial {
fn fragment_shader() -> ShaderRef {
"cool_material.wgsl".into()
}
}
以及 cool_material.wgsl
着色器
struct CoolMaterial {
color: vec4<f32>,
};
@group(1) @binding(0)
var<uniform> material: CoolMaterial;
@group(1) @binding(1)
var color_texture: texture_2d<f32>;
@group(1) @binding(2)
var color_sampler: sampler;
@fragment
fn fragment(
#import bevy_pbr::mesh_vertex_output
) -> @location(0) vec4<f32> {
return material.color * textureSample(color_texture, color_sampler, uv);
}
就这样,我们拥有了一个可配置的着色器材质!
这可用于创建您想要的任何效果!例如:@DGriffin91
创建了这种酷炫的“发光球体”效果
他们还制作了一个 不错的视频教程,概述了如何创建这种材质。
这一切都要归功于新的 AsBindGroup
特性/派生,它完成了将材质转换为 GPU 兼容数据类型、将它们写入 GPU 以及创建最终的 BindGroup
的所有繁重工作。AsBindGroup
特性功能强大:它支持将多个字段组合到同一个统一绑定中,配置纹理绑定类型(2D、3D、过滤等)等等。有关详细信息,请查看 AsBindGroup
文档。
所有内置材质,例如 PBR StandardMaterial
,都已移植到使用此新系统。我们努力使 Bevy 的“内部机制”与用户代码保持一致,这也不例外!Material
还与我们更高级的着色器功能(例如 着色器管道专用化)无缝协作。
还有一个等效的 Material2d
特性,它支持在 2D 中使用自定义材质。
相机驱动渲染 #
在 Bevy 的早期版本中,Cameras
被选中并作为“全局”RenderGraph
的一部分运行。对于给定类型,只能有一个“活动”相机,并且该相机只能渲染到一个目标。同时从多个视角进行渲染的唯一方法是手动使用重复逻辑扩展渲染图。这充满了复杂的低级渲染器样板代码,对于普通 Bevy 用户来说是不可取的。
在 Bevy 0.8 中,每个 Camera
现在都配置了它渲染的内容、渲染方式以及渲染到的目标。启用相机将启动 RenderGraph
的新运行,并将渲染结果输出到指定的 RenderTarget
。渲染图定义了 模块化渲染逻辑,用于给定的相机,而渲染目标定义了渲染图将渲染到的窗口或纹理。
这使得以前需要数百行(或数千行)代码才能完成的任务变得简单,只需在 Camera
实体上设置几个字段即可。
渲染到纹理 #
将 Camera
渲染到纹理现在只需一行代码
camera.target = RenderTarget::Image(image_handle);
这使得许多场景成为可能:传送门,将 UI 渲染到纹理并在 3D 空间中渲染它,游戏中的安全摄像头,在 UI 小部件中实时渲染的玩家肖像……一切皆有可能!
这是一个“传送门效果”的示例
这是通过将第二个相机渲染到纹理,将它的方向与主玩家相机同步,并将该纹理用于主相机的场景来实现的。
分屏 #
每个 Camera
现在都具有可选的 Viewport
,如果设置了它,它将渲染到 RenderTarget
的一部分而不是全部。如果您生成两个活动相机,并将每个相机的 Viewport
设置为渲染到窗口的一半,那么您将拥有简单且轻松的分屏功能!
分层渲染 #
现在可以使用新的“相机优先级”字段将相机层叠在一起
// This camera defaults to priority 0 and is rendered "first" / "at the back"
commands.spawn_bundle(Camera3dBundle::default());
commands.spawn_bundle(Camera3dBundle {
camera_3d: Camera3d {
// don't clear the color while rendering this camera
clear_color: ClearColorConfig::None,
..default()
},
camera: Camera {
// renders after / on top of the main camera
priority: 1,
..default()
},
..default()
});
“优先级”决定了相机绘制的顺序。“传送门”效果在 渲染到纹理示例中 使用优先级来优先渲染“传送门”相机,确保它已准备好供主相机使用。
这是一个简单的示例,展示了两个相机渲染到同一个窗口
这可用于“自定义 UI 传递”、“小地图”等功能。
符合人体工学的目标尺寸访问 #
相机现在在本地存储它们的 RenderTarget
尺寸,这使得获取尺寸变得更加简单
// Much nicer than needing to look up the size on the target Window or Image manually,
// like you had to in previous Bevy versions!
let target_size = camera.logical_target_size();
let viewport_size = camera.logical_viewport_size();
这也意味着将世界坐标转换为相机屏幕坐标比以前容易得多
// Bevy 0.7 (old)
camera.world_to_screen(windows, images, camera_transform, world_position);
// Bevy 0.8 (new)
camera.world_to_viewport(camera_transform, world_position);
新的相机包 #
旧的 `OrthographicCameraBundle` 和 `PerspectiveCameraBundle` 已被 Camera3dBundle
和 Camera2dBundle
替换。在大多数情况下,迁移只需将旧名称替换为新名称即可。3D 相机默认使用“透视”投影,但它们仍然可以使用新 Projection
组件在捆绑包中切换到正射投影。
不再有 CameraUiBundle!#
Bevy UI 现在不再需要单独的相机实体来工作。UI 对所有相机类型都“正常工作”,并且可以使用 UiCameraConfig
组件在每个相机上启用或禁用。
commands
.spawn_bundle(Camera3dBundle::default())
.insert(UiCameraConfig {
show_ui: false,
});
自定义渲染图 #
每个 Camera
的默认 2D 和 3D RenderGraphs
可以通过设置 CameraRenderGraph
组件来覆盖。
commands.spawn_bundle(Camera3dBundle {
camera_render_graph: CameraRenderGraph::new(some_custom_graph),
..default()
})
这使您能够使用所需的任何自定义渲染逻辑来绘制相机!例如,您可以用延迟渲染替换内置的集群前向渲染。请注意,这通常不是必需的:大多数自定义渲染场景将由高级 材质 或扩展内置渲染图来覆盖。使用默认渲染图将确保与其他插件的最大兼容性。
启用/禁用相机 #
如果相机处于“活动”状态,它将渲染到其 RenderTarget
。要激活或停用相机,请设置新的 `is_active` 字段。
camera.is_active = true;
渲染层 #
Bevy 的现有 RenderLayers
系统可用于告诉 Camera
仅渲染特定层上的实体。相机驱动的渲染与该功能完美搭配。这使得将一组实体渲染到一个相机,并将另一组实体渲染到另一个相机成为可能。我们已将 RenderLayers
系统移植到所有具有 Visibility
的实体,因此这一切都将“正常工作”。
聚光灯 #
Bevy 现在有一个 SpotLight
实体类型,它从空间中的一个点发出圆锥形的光。
可见性继承 #
实体层次结构中的可见性(使用 Visibility
组件)现在会向下传播到层次结构中。这非常有用,因为游戏中的实体通常嵌套着许多实体。一个“玩家实体”通常由许多部分组成:玩家精灵或网格,玩家穿戴或握持的东西,视觉效果等等。
可见性继承意味着您只需要在代码中隐藏顶层“玩家”实体,它下面的所有内容都将自动隐藏。
这个“飞行头盔”场景包含许多嵌套在主头盔实体下的“部件”。现在,隐藏所有这些“子实体”就像隐藏顶层头盔实体一样简单。
fn hide_helmets(mut helmet_visibilities: Query<&mut Visibility, With<Helmet>>) {
let mut helmet_visibility = helmet_visibilities.single_mut();
helmet_visibility.is_visible = false;
}
在 Bevy 的过去版本中,您必须手动隐藏每个部件!
“继承的可见性”在 PostUpdate
阶段计算,并存储在 ComputedVisibility
组件中。 ComputedVisibility
现在具有以下功能
is_visible_in_hierarchy()
:根据“可见性继承”,实体是否可见。is_visible_in_view()
:实体在任何视图中是否可见。这用于在“视锥体剔除”等情况下剔除实体。is_visible()
:确定实体是否将被绘制的规范位置。结合了“视图可见性”和“层次结构可见性”。
SpatialBundle 和 VisibilityBundle #
随着 可见性继承 的添加,随之而来的是一个约束:可见性传播要求层次结构中的所有元素都具有相应的可见性组件。在构建场景时,开发人员通常希望将实体分组到父级“组织”实体下,这些实体仅仅用于将实体分组在一起,重新定位它们,并将它们作为一个单元隐藏。这些“组织”实体仍然需要可见性组件来将 Transform
和 Visibility
分别传播到 GlobalTransform
和 ComputedVisibility
。
为了简化操作,我们添加了一个新的 SpatialBundle
,它添加了上面提到的组件。这使实体能够配置和传播可见性和变换数据,而不会产生实际渲染它的成本。
commands
// This entity controls the position and visibility of the entities beneath it.
.spawn_bundle(SpatialBundle {
transform: Transform::from_xyz(10.0, 20.0, 30.0),
visibility: Visibility {
is_visible: true,
},
..default()
}).with_children(|parent| {
parent
.spawn_bundle(TableBundle::default())
.spawn_bundle(ShopKeeperBundle::default())
.spawn_bundle(PotionBundle::default());
});
为了确保可见性和变换得到传播,请确保整个层次结构(根 -> 叶)都有这些组件
commands
.spawn_bundle(SpatialBundle::default())
.with_children(|parent| {
parent
.spawn_bundle(SpatialBundle::default())
.with_children(|parent| {
parent.spawn_bundle(SpatialBundle::default());
});
});
如果您知道不需要 Transform
传播(或者您的实体已经有了这些组件),您可以改用新的 VisibilityBundle
,它只添加了可见性传播所需的组件。
内置着色器模块化 #
在 Bevy 0.8 中,我们已经开始对我们的内置着色器进行模块化。值得注意的是,这意味着您现在可以导入和运行内置的 PBR 着色器/照明逻辑。
#import bevy_pbr::utils
#import bevy_pbr::clustered_forward
#import bevy_pbr::lighting
#import bevy_pbr::shadows
#import bevy_pbr::pbr_types
#import bevy_pbr::pbr_functions
@fragment
fn fragment(in: FragmentInput) -> @location(0) vec4<f32> {
var pbr_input: PbrInput = pbr_input_new();
// set the base color to red
pbr_input.material.base_color = vec4<f32>(1.0, 0.0, 0.0, 1.0);
/* set other PbrInput fields here */
return tone_mapping(pbr(pbr_input))
}
我们还对网格和视图绑定着色器逻辑进行了模块化。当与 新的材质系统 配合使用时,用户现在可以合理地编写自定义 PBR 材质,而无需在他们的着色器中重新定义所有 PBR 逻辑。新的 数组纹理示例 说明了如何使用这些新 API 定义自定义 PBR 着色器材质。
我们还计划改进用户体验。现在我们已经将所有内容分解并模块化,我们将努力减少扩展此逻辑所需的样板代码(减少导入,消除设置所有 PbrInput 字段的需要等等)。
wgpu 0.13:新的 WGSL 着色器语法 #
我们已更新到最新版本的 wgpu。wgpu 0.13 带来了大量修复和改进,但最明显的变化是新的更符合人体工程学设计的 WGSL“属性”语法。
绑定现在看起来像这样
// wgpu 0.12 (old)
[[group(1), binding(0)]]
var<uniform> material: Material;
// wgpu 0.13 (new)
@group(1) @binding(0)
var<uniform> material: Material;
着色器阶段入口点和输入现在看起来像这样
// wgpu 0.12 (old)
[[stage(vertex)]]
fn vertex([[location(0)]] position: vec3<f32>, [[location(1)]] normal: vec3<f32>) -> VertexOutput {
}
// wgpu 0.13 (new)
@vertex
fn vertex(@location(0) position: vec3<f32>, @location(1) normal: vec3<f32>) -> VertexOutput {
}
更易于阅读!(也更易于编写!)
场景捆绑包 #
在 Bevy 的早期版本中,场景是这样生成的
commands.spawn_scene(asset_server.load("some.gltf#Scene0"));
这可以工作,但它使得在实践中实际使用场景变得困难。重新定位场景需要手动获取场景的实体 ID,然后在它生成时重新定位它,或者创建一个具有相关变换组件的父实体并“将场景作为子实体生成”。此外,用新组件扩展场景也具有挑战性。
在 Bevy 0.8 中,我们添加了一个 SceneBundle
,它使场景生成与我们其他的实体构建 API 保持一致。
commands.spawn_bundle(SceneBundle {
scene: asset_server.load("some.gltf#Scene0"),
..default()
})
当场景加载时,它将自动在 `spawn_bundle` 命令创建的实体下生成。这使得变换场景并在“根”处添加新组件变得容易得多。
commands
.spawn_bundle(SceneBundle {
scene: asset_server.load("player.gltf#Scene0"),
transform: Transform::from_xyz(10.0, 20.0, 30.0),
..default()
})
.insert(Player::default());
并行视锥体剔除 #
Bevy 使用 “视锥体剔除” 来跳过绘制在相机视野之外的实体。在 Bevy 0.8 中,视锥体剔除现在并行执行。当剔除数千个实体时,这会带来显著的性能提升。
视锥体剔除系统时间与被剔除实体的数量(越低越好) #
请注意,“并行 b”代表“并行批次大小”(每个批次中的实体数量)。我们在 Bevy 0.8 中选择了 1024 作为批次大小,因为它表现得更好。
自动网格切线生成 #
顶点切线与法线贴图一起使用,在渲染网格时为网格提供更详细的法线。一些导入的网格具有法线贴图,但没有计算顶点切线。Bevy 现在可以使用业界事实上的标准 MikkTSpace 库/算法自动为缺少顶点切线的 Meshes
生成顶点切线(Godot、Unity、Unreal 和 Blender 都使用此算法)。
我们已经开始维护 我们自己的 gltf-rs/mikktspace crate 分支,这样我们就可以
- 以 Bevy 所需的速度更新依赖项;
- 开始控制不安全的代码,因为它目前使用从用 C 编写的原始 `mikktspace.h` 自动生成的非安全 Rust 代码。
默认使用线性纹理过滤 #
Bevy 中的图像现在默认使用线性纹理过滤,这更符合游戏开发生态系统中的其他部分(Unity 和 Godot 都默认使用过滤的纹理)。
这意味着需要未过滤像素(例如“像素艺术”精灵)的纹理必须覆盖此默认设置,无论是每个图像
image.sampler_descriptor = ImageSampler::nearest();
还是使用新的 ImageSettings
资源全局设置
app.insert_resource(ImageSettings::default_nearest())
这样,我们就可以获得清晰的像素艺术
新的 GlobalTransform 矩阵表示 #
GlobalTransform
组件(表示实体的“世界空间”变换)的内部表示已从“相似性”(平移 Vec3
/ 旋转 Quat
/ 缩放 Vec3
)更改为“仿射 3D 变换”(Mat3A
和 Vec3
平移)。
值得注意的是,这允许表示剪切。剪切是一个有争议的话题。引擎和物理程序员往往讨厌它。艺术家往往喜欢它。鉴于大多数艺术家工具和游戏引擎在其等效类型中支持剪切,我们认为提供这种选择非常重要。
ShaderType 推导 #
Bevy 0.8 现在使用 ShaderType
特性/推导(由 encase crate 提供)来轻松地将 Rust 数据类型转换为与 GPU 兼容的着色器数据类型。
// ShaderType requires each field to implement ShaderType,
// which Bevy's math types and Color type implement.
#[derive(ShaderType)]
struct SpriteData {
position: Vec2,
color: Color,
}
在 WGSL 着色器方面,它看起来像这样
struct SpriteData {
position: vec2<f32>,
color: vec4<f32>,
};
@group(1) @binding(0)
var<uniform> sprite_data: SpriteData;
如果您需要定义自定义着色器统一或缓冲区绑定,则可以在 新的材质系统 中使用此特性。
ShaderType
替换了以前 Bevy 版本中使用的 AsStd140
和 AsStd430
特性/推导(由 crevice crate 提供)。这简化了(并阐明了)Bevy 中的“如何将数据传输到 GPU”的故事,同时还添加了新功能,例如对无界 Rust 向量(用于存储缓冲区)和对统一和存储缓冲区可配置的动态偏移的支持。
例如,Bevy 的内置照明管道已调整为利用此功能。
#[derive(ShaderType)]
pub struct GpuPointLightsStorage {
#[size(runtime)]
data: Vec<GpuPointLight>,
}
渲染阶段排序优化 #
Bevy 使用“渲染阶段”来收集每个实体的渲染逻辑,用于渲染传递。这些阶段可以排序,以出于多种原因控制绘制顺序:为了透明度的正确性而进行的从后到前的深度排序,以及为了在不透明渲染期间进行早期片段丢弃而进行的从前到后的排序。
在可能的情况下,**Bevy 0.8** 现在使用“不稳定排序”(目前为“基数排序”),这带来了显著的性能提升。
many_cubes 压力测试“不透明阶段”排序时间(以毫秒为单位,越少越好) #
顶点颜色 #
Bevy 的 2D 和 3D 管道以及 Materials
现在支持顶点颜色,如果给定的 Mesh
提供了它们。PBR StandardMaterial
和 2D ColorMaterial
基于此构建,如果设置了顶点颜色,它们将使用这些颜色。
规则多边形和圆形网格基元 #
Bevy 现在有 Circle
和 RegularPolygon
Mesh
形状。
let pentagon = RegularPolygon::new(10., 5);
let handle = meshes.add(Mesh::from(pentagon));
commands.spawn_bundle(ColorMesh2dBundle {
mesh: handle.into(),
..default()
});
脚本编写和修改进度:无类型 ECS API #
Bevy 正式只支持 Rust 作为“定义应用程序逻辑的唯一正确方式”。我们有 充分的理由 这样做,这种理念可能不会很快改变。但是,我们 *确实* 想要提供社区构建其所选语言的第三方脚本/修改插件所需的工具。
当我们 发布 Bevy ECS V2 时,我们有意地构建了我们的内部 ECS 存储,以考虑这些情况。但是,我们没有公开 API,使得能够在没有普通 Rust 类型的情况下与 ECS 数据交互。
**Bevy 0.8** 添加了公共“无类型”ECS API,这些 API 使得能够使用 ComponentId
(而不是实际的 Rust 类型)检索指向组件和资源数据的 带生命周期的指针。
let health_ptr: Ptr = world.entity(player).get_by_id(heath_component_id).unwrap();
这些 API 与我们的反射 API 相结合,提供了开始构建脚本支持所需的工具!
@jakobhellermann
已经 开始为 Bevy 构建他们自己的 JavaScript/TypeScript 插件。请注意:
- 此插件仍处于开发阶段,不适合在项目中使用。
- 这是一项非官方的社区工作。Bevy 不会添加官方的 JavaScript/TypeScript 支持。
以下是从其存储库中的 TypeScript 代码片段,该片段从脚本中查询 Bevy ECS 数据。
const ballQuery = world.query({
components: [ballId, transformId, velocityId],
});
for (const item of ballQuery) {
let [ball, transform, velocity] = item.components;
velocity = velocity[0];
info(velocity.toString());
}
Query IntoIter #
Bevy ECS Queries
现在实现了 IntoIterator
特性,它提供了对 Rust 更友好的迭代语法的访问。
// In previous Bevy versions, iter/iter_mut had to be called manually:
fn system(mut players: Query<&mut Player>) {
for player in players.iter() {
}
for mut player in players.iter_mut() {
}
}
// In Bevy 0.8, you have the option to use this syntax:
fn system(mut players: Query<&mut Player>) {
for player in &players {
}
for mut player in &mut players {
}
}
Query::iter_many #
现在可以将实体列表传递给 Query
,以使用 Query::iter_many
进行迭代,这比对每个单个实体调用 get(entity)
方便得多。
#[derive(Component)]
struct BlueTeam {
members: Vec<Entity>,
}
fn system(blue_team: Res<BlueTeam>, players: Query<&Player>) {
info!("Blue Team Assemble!");
for player in players.iter_many(&blue_team.members) {
info!("{}", player.name);
}
}
还有一个 Query::iter_many_mut
,它为可变查询提供了类似的功能。但为了确保不允许别名可变性,它没有实现迭代器。相反,请使用以下模式。
let mut iter = players.iter_many_mut(&blue_team.members);
while let Some(mut player) = iter.fetch_next() {
player.score += 1;
}
将可变查询转换为只读查询 #
可变 Queries
现在可以转换为其只读版本,这使得更容易构建和使用查询的抽象。
fn system(mut players: Query<&mut Player>) {
for mut player in &mut players {
// mutate players here
}
log_players(players.to_readonly());
}
fn log_players(players: Query<&Players>) {
for player in &players {
info!("{player:?}");
}
}
ECS“带生命周期的指针” #
Bevy ECS 已重构为使用带生命周期的、类型擦除的指针,而不是“原始指针”,这在不影响性能或灵活性的情况下,显著提高了我们内部的安全性,并提高了可读性。
从高层面上来说,这使我们能够在整个内部保留 World 借用的生命周期,同时仍然使用类型擦除的 API 来支持诸如 第三方脚本语言 这样的场景。
通过保留此生命周期,我们可以更多地依赖 Rust 的借用检查器来提醒我们何时正在做一些不安全的事情。而且,正如实际情况一样,这发现了一些健壮性错误!
ECS 查询内部重构 #
@BoxyUwU
一直在努力重构我们的 Query
内部,使其更简单、更容易阅读。
ReadOnlyFetch
被替换为ReadOnlyWorldQuery
,将此特性约束“提升一级”,使其更容易在类型系统中表达。- “QF Fetch 泛型”已从
Query
和QueryState
方法和类型中删除,转而使用WorldQuery
,这使得过滤器和普通获取在类型系统中保持一致,并且更容易表达。
我们计划在下一个版本中进行更多此类更改。Bevy ECS 内部正在变得越来越容易理解!
ECS 优化 #
Bevy ECS 在这次更新中进行了一些优化。
@james7132
通过减少进行的复制次数来加快实体在表格之间移动的速度。对于较大的组件,这将是一个巨大的胜利。many_cubes
压力测试在prepare_uniform_components
系统中看到了约 16% 的速度提升,该系统严重依赖命令/表格移动。@DJMcNab
删除了 ECS 存储内部的无操作删除函数调用,这将many_cubes
压力测试的删除时间从约 150μs 减少到约 80μs。@james7132
将ComponentSparseSet
索引从usize
更改为u32
,这使得它们使用更少的空间/使某些操作更缓存友好。通过此更改,稀疏集迭代速度提高了约 15%。
标签优化 #
Bevy 依赖于“标签”来识别诸如系统、阶段和应用程序之类的事物。这对于诸如 定义系统依赖关系 这样的事情很有用。特性 SystemLabel
、StageLabel
和 AppLabel
基于相同的底层“类型化标签”系统。它使开发人员能够定义自定义标签,同时保留类型安全性。远比使用诸如字符串或整数标签之类的东西好!
在 **Bevy 0.8** 中,我们通过删除装箱/特性对象,转而使用一种廉价的复制和比较的“系统标签 ID”类型,来优化标签的内部表示。
这种新的表示使调度构建速度提高了约 30%!
使用 100 个系统准备和计算调度的耗时(以毫秒为单位,越少越好) #
此更改还从我们的标签派生中删除了许多特性要求。
// Old (Bevy 0.7)
#[derive(SystemLabel, Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum MovementSystem {
Velocity,
Gravity,
}
// New (Bevy 0.8)
#[derive(SystemLabel, Clone)]
enum MovementSystem {
Velocity,
Gravity,
}
层次结构命令 #
Bevy 的实体层次结构系统基于两个组件:Parent
(指向实体的父级)和 Children
(指向实体的子级列表)。这种分离很重要,因为它使查询“层次结构根”变得容易且廉价。
fn system(roots: Query<Entity, Without<Parent>>) { }
在 Bevy 的早期版本中,我们构建了一个复杂的系统来“维护”层次结构的完整性。当 Parent
/ Children
组件对于某个实体被添加/删除/更改时,我们会尽力同步整个层次结构。
但是,这意味着在某个时间点,层次结构可能是“不同步的”和不正确的。
我们对此问题的解决方案是删除延迟的“层次结构维护系统”,转而使层次结构更改成为“事务性的”。层次结构更改现在通过事务性的 Commands
完成,并且不再可能直接修改组件字段。这确保了在某个时间点,层次结构是“正确的”。
对于大多数 Bevy 开发人员来说,这是一个非破坏性更改,因为大多数层次结构已经使用 with_children
命令构建。
commands
.spawn_bundle(SpatialBundle::default())
.with_children(|parent| {
parent.spawn_bundle(SpriteBundle {
texture: player_texture,
..default()
});
parent.spawn_bundle(SpriteBundle {
texture: hat_texture,
..default()
});
});
但是,对于在运行时从父级添加/删除子级实体的逻辑,必须使用以下命令。
// removes the given children from the parent
commands.entity(some_parent).remove_children(&[child1, child2]);
// pushes the given children to the "end" of the parent's Children list
commands.entity(some_parent).push_children(&[child3, child4]);
// inserts the given children into the parent's Children list at the given index
commands.entity(some_parent).insert_children(1, &[child5]);
我们还添加了 HierarchyEvent
,它使开发人员能够跟踪层次结构中的更改。
仍然有一些小的漏洞需要关闭,但是现在保持在“顺利路径”上变得容易多了。
- 只删除其中一个组件是可能的(尽管强烈不建议这样做)。
- 手动添加其中一个组件的默认值仍然是可能的(尽管强烈不建议这样做)。
我们正在讨论解决此类问题的方法,例如 原型规则/不变式。
Bevy 反射改进 #
Bevy 的“Rust 反射”系统 bevy_reflect
是 Bevy 场景系统的核心基础部分。它提供了一种方法,可以在运行时动态地与 Rust 类型进行交互,而无需知道它们的实际类型。我们在这次版本中对其进行了大量投入,为脚本支持和场景系统改进做准备。
bevy_reflect
旨在成为一个“泛型”Rust 反射系统。它可以在没有 Bevy 的情况下使用。我们相信它填补了 Rust 生态系统中的一个真实空白,我们鼓励更广泛的 Rust 社区使用它(并做出贡献!)。
“无类型”反射 #
现在,Reflect
派生会自动将新的 ReflectFromPtr
结构体添加到每个反射类型的 TypeRegistry
中。这使得能够将新的 无类型 ECS API 与反射系统结合使用。这有助于实现诸如第三方脚本和修改之类的事情。
默认特性反射 #
现在可以使用其 Default
特性实现来构建 Reflect
类型,前提是它们将该特性注册为 Reflect
派生的部分。
#[derive(Reflect, Default)]
#[reflect(Default)]
struct MyStruct {
foo: String,
bar: usize,
}
let registration = type_registry.get(TypeId::of::<MyStruct>()).unwrap();
let reflect_default = registration.data::<ReflectDefault>().unwrap();
// This contains a MyStruct instance with default values
let my_struct: Box<dyn Reflect> = reflect_default.default();
这使得能够在 *没有任何* 编译时信息的情况下为实体构建组件,这对于诸如脚本和场景之类的动态场景很有用。
数组反射 #
Bevy 的反射系统现在支持反射 Rust 数组,可以使用新的 Array
特性以类型擦除的方式与它们进行交互。
#[derive(Reflect)]
struct Sprite {
position: [f32; 2],
}
let sprite = Sprite {
position: [0.1, 0.2],
};
let position = sprite.field("position").unwrap();
if let ReflectRef::Array(array) = position.reflect_ref() {
let x = array.get(0).unwrap();
assert_eq!(x.downcast_ref::<f32>(), Some(&0.1));
}
静态类型信息 #
Reflect
特性提供了对类型 *特定实例* 的动态访问,但某些场景(如反序列化)从在拥有类型实例 *之前* 了解类型信息中受益。这为构建基于 Reflect 的 serde
替代方案(或者至少是无 serde 的 Bevy 场景反序列化器)打开了大门。
Bevy 0.8 添加了获取 TypeInfo
的功能,用于实现 Reflect
的任何类型。
#[derive(Reflect)]
struct Foo {
a: f32,
b: usize,
}
let info = Foo::type_info();
if let TypeInfo::Struct(info) = info {
assert!(info.is::<Foo>());
assert_eq!(info.type_name(), std::any::type_name::<Foo>(),);
assert!(info.field("a").unwrap().is::<f32>());
assert!(info.field_at(1).unwrap().is::<usize>());
}
请注意 type_info()
返回 &'static TypeInfo
:它将在第一次请求时延迟分配并存储 TypeInfo
,然后在每次后续请求中重复使用。
泛型类型也支持 TypeInfo
#[derive(Reflect)]
struct Foo<T> {
value: T
}
let info = Foo::<f32>::type_info();
if let TypeInfo::Struct(info) = info {
assert!(info.field("value").unwrap().is::<f32>());
}
资源反射 #
Bevy ECS 资源现在可以反射。
#[derive(Reflect)]
#[reflect(Resource)]
struct Scoreboard {
points: usize,
}
这将在 TypeRegistry
条目中为该类型注册一个 ReflectResource
,从而在 ECS World
中启用类型擦除的资源读写操作。
漂亮的反射调试格式 #
“调试打印” Reflect
引用现在提供漂亮/有用的输出。
考虑以下示例
#[derive(Reflect)]
struct Foo {
a: f32,
b: Bar,
}
#[derive(Reflect)]
struct Bar {
x: String,
y: usize,
}
let foo = Foo {
a: 42.0,
b: Bar {
x: "hello".to_string(),
y: 123,
},
};
let foo_reflect: &dyn Reflect = &foo;
println!("{:#?}", foo_reflect);
在 Bevy 的先前版本中,这将打印
Reflect(my_crate::Foo)
在 Bevy 0.8 中,它打印
my_crate::Foo {
a: 42.0,
b: my_crate::Bar {
x: "hello",
y: 123,
},
}
好多了!
bevy_reflect 内部重构 #
现在 bevy_reflect
开始获得一些重大的投资和使用,我们已经投入时间重新设计内部结构,使它们更容易维护和扩展。
Reflect
导出重组:导出逻辑被分解成更小、更易于维护的部分。“元数据结构”被添加进来以收集和整理导出输入。(@MrGVSV
)Reflect
特性现在可以安全地实现:健壮性不再取决于实现者做正确的事情,这要归功于Reflect
接口的一些更改。因此,我们能够从Reflect
特性中删除unsafe
关键字。(@PROMETHIA-27
)Serialize
逻辑现在使用TypeRegistry
类型数据(就像其他反射特性逻辑一样)实现,而不是硬编码到Reflect
实现中。(@jakobhellermann
)
渲染世界提取 #
注意:这里讨论的渲染器 API 适用于高级自定义渲染功能的开发人员和核心 Bevy 渲染器开发人员。如果这看起来过于冗长或意图令人困惑,请不要担心!
Bevy 的 新渲染器 从“主”Bevy 应用程序中“提取”渲染所需的数据,这使得 流水线渲染 并行化成为可能。为了促进这一点,在 Bevy 的先前版本中,我们使 ECS RenderStage::Extract
变得“特殊”(而且有点奇怪)。该阶段的系统在“主”应用程序世界中运行,但将系统 Commands
应用于“渲染”应用程序世界。
这实现了目标,但它
- 令人困惑:渲染功能开发人员必须“知道”这个阶段的行为与调度中的其他“正常”ECS 阶段不同。隐式地,
Commands
的行为也不同,ECS 数据访问被“翻转”。使用“正常”的实体生成 API 将无法按预期工作,因为Commands
参数在内部仍然使用主应用程序的 Entities 集合。 - 阻止并行化:直接修改现有的“渲染世界”资源需要对
ResMut<RenderWorld>
进行独占访问,这阻止了这些系统并行运行。使此访问并行需要使用Commands
进行不必要的分配,对于“大型”(或增量更新)提取,这效率低下。
// Old: Bevy 0.7 (limited parallelism)
fn extract_score(score: Res<Score>, mut render_world: ResMut<RenderWorld>) {
*render_world.resource_mut::<ExtractedScore>() = ExtractedScore::from(score);
}
// Old: Bevy 0.7 (unnecessary allocations / prevents incremental updates)
fn extract_score(mut commands: Commands, score: Res<Score>) {
commands.insert_resource(ExtractedScore::from(&score));
}
在 Bevy 0.8 中,我们使提取阶段变得“正常”。它直接在“渲染世界”中运行,就像其他渲染应用程序阶段一样。要从主应用程序世界中“提取”数据,只需将相关的系统参数包装在新的 Extract
类型中,以从主应用程序世界中检索该参数。
// New: Bevy 0.8 (parallel and not weird!)
fn extract_score(mut extracted_score: ResMut<ExtractedScore>, score: Extract<Res<Score>>) {
*extracted_score = ExtractedScore::from(&score);
}
提取系统现在是并行的,数据访问与其他渲染器 ECS 阶段一致,并且系统的意图更加清晰。
ExtractResource 特性和插件 #
一些 ECS 资源具有非常简单的提取逻辑。
fn extract_cool_color(mut extracted_cool_color: ResMut<CoolColor>, cool_color: Extract<Res<CoolColor>>) {
*extracted_cool_color = cool_color.clone();
}
而不是强迫开发人员手动编写这些逻辑,Bevy 0.8 现在提供了 ExtractResource
特性/导出。
#[derive(ExtractResource, Clone)]
struct CoolColor {
color: Color,
}
然后,只需将 ExtractResourcePlugin<CoolColor>
添加到您的 App
中,资源将被自动提取。
ExtractResource
也可以在您需要自定义逻辑(或类型需要更改)时手动实现。
impl ExtractResource for ExtractedCoolColor {
type Source = CoolColor;
fn extract_resource(source: &CoolColor) -> Self {
Self {
color: source.color.as_rgba_linear(),
}
}
}
Taffy 迁移:一个焕然一新的 UI 布局库 #
Bevy 已经从被遗弃的 stretch
UI 布局库迁移到其新的社区维护硬分叉:taffy
。与 Dioxus 团队一起,我们大幅清理了代码库,解决了深层 UI 树的严重性能问题,并更新了文档。
我们期待着它继续维护和开发,因为该团队将继续改进其性能,修复错误,并添加对替代布局范式的支持。
ECS 健壮性/正确性改进 #
Bevy ECS 在本次发布中获得了大量的健壮性和正确性错误修复。
- 删除了
EntityMut::get_unchecked
:安全使用此 API 的唯一方法已经被封装在EntityMut::get
中。因此,没有理由保留这个不安全的 API。 - 修复了某些
Or
/AnyOf
/Option
组件访问中的不健壮性:以前的 Bevy 版本允许使用这些查询的不健壮版本。我们现在正确地阻止了这些使用。 - 提高了
CommandQueue
的健壮性:现在可以使用填充或未初始化字节存储命令。还删除了一个“移动后使用”的情况。 - 修复了 Miri 检测到的一些内存泄漏:Miri 检测到我们
BlobVec
drop impl 中存在内存泄漏。现在已修复。 - 在
bevy_ecs
中对缺少 SAFETY 注释进行 lint:我们现在要求bevy_ecs
中的不安全代码块包含安全注释。
随着 Bevy ECS 的成熟,我们对不安全代码块和健壮性的要求也必须提高。Bevy ECS 可能永远无法完全摆脱不安全代码块,因为我们正在对 Rust 无法在没有我们帮助的情况下推理的并行数据访问进行建模。但我们致力于尽可能多地删除不安全的代码,并提高剩余不安全代码的质量。
Android 进度:我们还没有实现,但我们更近了! #
Bevy 现在又可以“某种程度上”在 Android 上运行了!
然而,Android 支持尚未准备好。我们管理渲染上下文的某些问题必须得到解决,这些问题有时会破坏启动时的渲染,并且始终会破坏应用程序最小化时的渲染。音频目前也不起作用。
这是 load_gltf
Bevy 示例在我的 Pixel 6 上运行。
话虽如此,这是向前迈出的一大步,因为 Bevy 开发人员现在可以在 Android 上构建、部署(以及在某些情况下测试)Bevy 应用程序!
如果您渴望在移动平台上测试 Bevy,我们的 iOS 支持 更加完善。Bevy 开发人员已经开始 将基于 Bevy 的 iOS 应用程序发布到 Apple App Store!
CI/构建系统改进 #
与往常一样,Bevy 的 CI 在本周期获得了许多改进。
- 验证构建时,现在在 WASM 中运行示例。拍摄屏幕截图并将其存储为构建输出的一部分,以确保渲染正常工作 (
@mockersf
)。 - Bevy 示例现在每天在 Windows VM 上运行一次,以确保它们没有被破坏 (
@mockersf
)。 - 现在,许可证文件会自动添加到所有发布的板条箱中 (
@NiklasEi
)。 - 现在有一个工作流程可以自动生成一个 PR,为所有 Bevy 板条箱添加版本号增量 (
@mockersf
)。 - 为了使偶尔的 nightly Rust 故障不那么具有破坏性,我们对 nightly 工具链进行了参数化,使其更容易固定到特定的 nightly 版本。(
@mockersf
)
示例:后期处理 #
我们添加了一个新的示例,展示了如何使用新的 相机驱动渲染 和 着色器材质 使用全屏四边形和“渲染到纹理”构建“色差”后期处理效果。
我们计划在未来的版本中构建更正式的后期处理 API,但这种方法相对简单,并且打开了通往更多领域的大门。比扩展低级别的 RenderGraph
简单得多!
克隆 Bevy 仓库并运行 cargo run --release --example post_processing
来运行它。
示例:许多动画狐狸 #
这是一个有趣的压力测试,测试了我们的 骨骼动画系统,它渲染了许多在圆圈中走动动画狐狸。
克隆 Bevy 仓库并运行 cargo run --release --example many_foxes
来运行它。
WASM 示例构建工具 #
我们构建了一个工具,使在浏览器中构建和运行 Bevy 的示例变得更容易。
在 Bevy 仓库的根目录中,运行以下命令
cargo run -p build-wasm-example -- lighting
这将运行 cargo build
和 wasm-bindgen
命令,并将输出放置在 examples/wasm
文件夹中。在那里运行您最喜欢的“本地 web 服务器”命令,例如 python3 -m http.server
,并在浏览器中打开该 URL!
网站:改进的示例页面 #
Bevy WASM 示例 页面已重新设计。
- 它们现在在 Bevy 应用程序内容和资产加载时显示加载栏。
- 页面的设计/布局现在更美观了。
Bevy 组织变更 #
随着 Bevy 的发展,我们不断重新评估我们的开发流程,以适应不断增长的开发量。我们早就过了我能做出所有决定的阶段,并且随着我对社区成员的知识和经验的信任不断增强,我一直在逐渐委托责任。
在本发布周期中,Bevy 组织发生了两项重大变更。
- 所有拥有“委托合并权限”(
@mockersf
和@alice-i-cecile
)的现有开发人员现在拥有“维护者”的头衔。 - Rob Swain (
@superdump
) 现在是维护者。你可能从他在 Bevy 渲染器上的工作中认出他。他一直是自然界的一股不可阻挡的力量,推动着集群前向渲染、方向光和点光阴影、可见性/视锥剔除、alpha 混合、压缩 GPU 纹理等等。Rob 表现出对渲染算法、Bevy 内部机制和 Bevy 项目方向的深刻理解。我非常期待他接下来会构建什么!
现在,“维护者” 的工作方式是这样的
- 维护者现在对他们可以合并的 PR 的“领域”没有(硬性)限制。不再限制“仅限文档”、“仅限渲染”等等。现在,每个维护者都有责任评估他们擅长的领域。这在一定程度上增加了风险,但我认为这是允许维护者有机成长的重要一步。
- 维护者可以合并至少有两个社区批准的“相对无争议的”PR。维护者将共同决定和执行什么是无争议的。有争议的 PR 应该贴上
S-Controversial
标签。请注意,“两个社区批准” 是最低要求。维护者有责任确保适当的人员已批准 PR。 - 维护者可以合并“完全微不足道”的 PR,无需两个社区批准。以下是一些“完全微不足道”的示例:修复错别字、删除未使用的依赖项或代码,以及对小型“API 一致性”的修复。
- 关于有争议的决策的计时器:对于所有有争议的 PR(包括 RFC),如果两位维护者批准,则 PR 可以贴上
S-Ready-For-Final-Review
标签。一旦添加了此标签并且我被 ping 了,计时器就会开始。如果我在一个半月(45 天)内没有对 PR做出任何回应,包括可操作的反馈、一个“暂停按钮”/“我们还没有准备好”或否决,则维护者可以自由合并 PR。这使我有能力在重要的领域内指导项目方向,同时也有助于维护者在有意义的情况下并行推进项目。我们将随着时间的推移来校准这种方法,以确保我们在进度、质量和一致的愿景之间取得正确的平衡。 - 我仍然保留否决所有代码更改和单方面进行代码更改的权利。这包括撤销通过(4)合并的“有争议的更改”。
我们已经使用了这个流程大部分时间,而且我非常喜欢它目前的运作方式:更多信任、更多人参与每个决策、更快的开发速度、不再有微不足道的修复停滞不前。我仍然可以在需要的时候强制执行一致的愿景,但社区有能力推动工作向前发展。
下一步是什么?#
- 后期处理:我们还有很多后期处理工作正在进行中(其中一些差点就进入了这个版本)。下一个版本将使编写后期处理效果变得更容易(得益于中间 HDR 纹理和单独的色调映射步骤),并且还将包括诸如光晕和上采样之类的内置效果。
- 资产预处理:我们将投入大量资源到我们的资产管道中,重点在于
- 预处理资产以在“开发时间”执行昂贵的操作,这样 Bevy 应用程序就可以使用更漂亮、更小或加载速度更快的资产部署。
- 使用
.meta
文件配置资产。例如,您可以定义纹理压缩级别、它应该使用的过滤器或目标格式。
- 场景系统改进:此版本在 Reflection 上投入了大量资源。我们现在可以在其基础上构建下一代场景系统,包括更友好的场景格式、嵌套场景和改进的工作流程。
- Bevy UI 改进:为了准备可视化的 Bevy 编辑器,我们将改进 Bevy UI 的功能和用户体验。
- Bevy Jam #2:Bevy Jam #1 取得了巨大成功:74 个参赛作品、1,618 个评分以及良好的社区氛围。现在 Bevy 0.8 已发布,是时候再次进行 jam 了!我们很快就会发布有关此活动的详细信息。要时刻了解最新消息,请关注 Twitter 上的 @BevyEngine 以及加入 官方 Bevy Discord。
支持 Bevy #
赞助有助于使我们在 Bevy 上的工作可持续。如果您相信 Bevy 的使命,请考虑赞助我们……每一份支持都至关重要!
- Carter Anderson (@cart):Bevy 的全职首席开发者、项目经理和创建者。专注于构建核心引擎系统、指导项目方向以及管理社区。
- Alice Cecile (@alice-i-cecile):全职技术项目经理、疯狂科学家和文档负责人。虽然她经常带领探险队进入新的领域,但 ECS 永远是她的基地。
- François Mockers (@mockersf):CI 专家。确保一切顺利运行,并通过一次次 PR 来改进 Bevy。
- Rob Swain (@superdump):光之掌控者。利用大规模并行计算将数据转化为闪耀的光芒。目前正在进行业余爱好黑客攻击,所以请捐赠给/赞助团队的其他成员。❤️
贡献者 #
非常感谢 130 位贡献者,他们使这个版本(以及相关的文档)成为可能!以下以随机顺序列出
- @spooky-th-ghost
- @afonsolage
- @mlodato517
- @ostwilkens
- @mattwilkinsonn
- @geckoxx
- @SarthakSingh31
- @zicklag
- @teoxoy
- @nsarlin
- @HackerFoo
- @elijaharita
- @inact1v1ty
- @bjorn3
- @james-j-obrien
- @Daniikk1012
- @nihohit
- @Ku95
- @superdump
- @dilyankostov
- @SkiFire13
- @edwardvear
- @jakobhellermann
- @KDecay
- @TheRawMeatball
- @fadhliazhari
- @colepoirier
- @brandon-reinhart
- @Davier
- @ManevilleF
- @Bobox214
- @RalfJung
- @robtfm
- @its-danny
- @alice-i-cecile
- @MonaMayrhofer
- @yilinwei
- @MrGVSV
- @ickshonpe
- @bzm3r
- @nagisa
- @fgiordana
- @DJMcNab
- @oliverpauffley
- @64kramsystem
- @alteous
- @maniwani
- @hoshino111
- @Kanabenki
- @JoJoJet
- @x-52
- @djeedai
- @BoxyUwU
- @MDeiml
- @GarettCooper
- @hymm
- @mockersf
- @nebkor
- @2ne1ugly
- @BGR360
- @SUPERCILEX
- @CGMossa
- @infmagic2047
- @CleanCut
- @YoshieraHuang
- @kornelski
- @mdickopp
- @SpecificProtagonist
- @PROMETHIA-27
- @eiei114
- @Hoidigan
- @Wcubed
- @adsick
- @nicopap
- @siph
- @C-BJ
- @tamasfe
- @object71
- @LegNeato
- @Elabajaba
- @bytemuck
- @AronDerenyi
- @makspll
- @cryscan
- @NiklasEi
- @grace125
- @NathanSWard
- @IceSentry
- @Vrixyz
- @Piturnah
- @its-justus
- @dataphract
- @thomas992
- @Olexorus
- @ShadowCurse
- @LoipesMas
- @ImDanTheDev
- @johanhelsing
- @wrapperup
- @james7132
- @rebelroad-reinhart
- @SuperSamus
- @manokara
- @Nilirad
- @NeoRaider
- @thebracket
- @sarkahn
- @MrPicklePinosaur
- @Shatur
- @themasch
- @devil-ira
- @fluunke
- @DGriffin91
- @aevyrie
- @henryksloan
- @bwasty
- @MiniaczQ
- @rparrett
- @komadori
- @ChristopherBiscardi
- @dtaralla
- @Sheepyhead
- @TethysSvensson
- @Neopallium
- @FraserLee
- @cart
- @Obdzen
- @oddfacade
- @CAD97
- @XBagon
完整变更日志 #
添加了 #
- 可调用的 PBR 函数
- 聚光灯
- 相机驱动渲染
- 相机驱动视口
- 可见性继承、通用
ComputedVisibility
和RenderLayers
支持 - 更好的材质:
AsBindGroup
特性及其派生,更简单的Material
特性 - 派生
AsBindGroup
改进:更好的错误、更多选项、更新示例 - 为 2D 材质也支持
AsBindGroup
- 并行视锥剔除
- 层次结构命令化
- 使用 mikktspace 生成顶点切线
- 添加一个带有
Visibility
和Transform
组件的SpatialBundle
- 添加
RegularPolygon
和Circle
网格 - 添加一个
SceneBundle
来生成场景 - 允许使用更高阶系统
- 为所有新类型的
TaskPools
添加全局init()
和get()
访问器 - 添加可重用的着色器函数,用于变换位置/法线/切线
- 添加对顶点颜色的支持
- 添加对从网格中删除属性的支持
- 添加一个选项来居中窗口
- 为
Camera3d
添加depth_load_op
配置字段 - 重构
Camera
方法并添加视口矩形 - 为
Image
添加TextureFormat::R16Unorm
支持 - 添加一个带有
Visibility
和ComputedVisibility
组件的VisibilityBundle
- 添加 ExtractResourcePlugin
- 为 SpecializedMaterial 添加 depth_bias
- 为
TextureAtlas::from_grid_with_padding
添加offset
参数 - 添加创建自定义 2D 正交相机的可能性
- bevy_render:为
Mesh
添加attributes
和attributes_mut
方法 - 添加用于旋转
Transform
的辅助方法 - 在使用 Bevy 的跟踪功能时启用 wgpu 跟踪范围
- bevy_pbr:重构
extract_meshes
- 为着色器视图统一添加
inverse_projection
和inverse_view_proj
字段 - 添加
ViewRangefinder3d
,以减少在排队标准 3DPhaseItems
时所需的样板代码 - 创建独立的
bevy_ptr
crate - 为
&Query
和&mut Query
添加IntoIterator
实现 - 为
Components
和Resources
添加无类型 API - 为
WorldCell
添加不可失败的资源获取器 - 为
EntityRef
和EntityMut
添加get_change_ticks
方法 - 为
FilteredAccessSet
添加比较方法 - 添加
Commands::new_from_entities
- 添加
QueryState::get_single_unchecked_manual
及其家族成员 - 添加
ParallelCommands
系统参数 - 添加用于查询实体列表的方法
- 为符合条件的
Iterator
类型实现FusedIterator
- 为
World
和Components
添加component_id()
函数 - 添加检查实体组件的能力
- 添加一个更有帮助的错误,以帮助调试在已销毁实体上恐慌的命令
- 为
QueryCombinatonIter
添加ExactSizeIterator
实现 - 为
*Label
类型的派生宏添加ignore_fields
属性 - 精确大小的事件迭代器
- 为
EventReader
添加clear()
方法,该方法会消耗迭代器 - 添加从
World
发送Events
的辅助程序 - 为
AssetIo
添加文件元数据 - 添加缺失的音频/ogg 文件扩展名:.oga、.spx
- 为
AssetServer
添加reload_asset
方法 - 允许使用环境变量指定 Chrome 跟踪文件路径
- 创建一个简单的工具来比较不同执行之间的跟踪
- 为运行条件添加跟踪范围
- 为
Query::par_for_each
及其变体添加跟踪范围。 - 在
Input
上添加release_all
方法 - 在
Input
上添加reset_all
方法 - 添加一个辅助工具,用于构建 wasm 示例
- bevy_reflect:添加
ReflectFromPtr
类型,用于从*const ()
创建&dyn Reflect
- 添加
ReflectDefault
类型,并将#[reflect(Default)]
添加到所有实现Default
且面向用户的组件类型 - 添加一个宏来实现结构体类型的
Reflect
,并将 glam 类型迁移到此以进行反射 - bevy_reflect:反射数组
- bevy_reflect:反射 char
- bevy_reflect:为反射元组添加
GetTypeRegistration
实现 - 为
Resources
添加反射 - bevy_reflect:在
Reflect
上添加as_reflect
和as_reflect_mut
方法 - 为
ReflectResource
和ReflectComponent
添加apply_or_insert
方法 - bevy_reflect:
DynamicList
和DynamicMap
的IntoIter
- bevy_reflect:为反射的
f32
和f64
添加PartialEq
- 创建
TypeRegistry
方法的可变版本 - bevy_reflect:为
reflect_trait
添加get_boxed
方法 - bevy_reflect:为
FromReflect
添加#[reflect(default)]
属性 - bevy_reflect:为反射类型添加静态可用的类型信息
- 添加
assert_is_exclusive_system
函数 - bevy_ui:为
Interaction
添加多窗口检查(我们还不支持多个窗口)
更改了 #
- 依赖于 Taffy(Dioxus 和 Bevy 维护的 Stretch 分支)
- 在 bevy_ecs 中使用生命周期受限的、类型擦除的指针
- 从
crevice
迁移到encase
- 将
wgpu
更新到 0.13 - 指针化后续操作:类型安全性和清理
- bevy_ptr 在 no_std 环境中工作
- 在 16 位平台上无法编译
- 提高人体工程学并减少围绕创建文本元素的样板代码
- 不要剔除具有旋转的
Ui
节点 - 将
ElementState
重命名为ButtonState
- 将
Size
移动到bevy_ui
- 将
Rect
移动到bevy_ui
并将其重命名为UiRect
- 修改
FontAtlas
使其能够处理任何尺寸的字体 - 重命名
CameraUi
- 从
par_for_each(_mut)
中删除task_pool
参数 - 将
TaskPool
资源复制到子应用程序 - 允许在运行时关闭窗口
- 将
WindowPlugin
的配置移动到Resource
- 可选地调整
Window
画布元素的大小以适合父元素 - 将窗口分辨率类型从元组更改为
Vec2
- 通过通道发送帧
Instant
来更新时间 - 将时间功能拆分为
bevy_time
- 拆分网格着色器文件以使着色器更可重用
- 设置与
wgpu
功能相对应的naga
功能 - 从 pbr.wgsl 中分离出 PBR 照明、阴影、集群前向和实用程序
- 将 PBR 和色调映射分离到 2 个函数中
- 使
RenderStage::Extract
在渲染世界中运行 - 将
Image
的默认FilterMode
更改为Linear
- bevy_render:修复 KTX2 UASTC 格式映射
- 允许渲染没有 UV 坐标数据的网格
- 在插入时验证顶点属性格式
- 使用
Affine3A
作为GlobalTransform
以允许任何仿射变换 - 当网格发生变化时重新计算实体
AABB
- 更改
check_visibility
以使用线程本地队列而不是通道 - 允许未批处理渲染阶段使用不稳定的排序
- 将资源提取到目标位置
- 启用加载无限大小的纹理
- 不要创建或执行没有
PhaseItems
可绘制的渲染通道 - 在提取时过滤材质句柄
- 将顶点颜色应用于
ColorMaterial
和Mesh2D
- 使
MaterialPipelineKey
字段公开 - 简化的 API 用于从相机和世界位置获取 NDC
- 根据 alpha 值设置
alpha_mode
- 使
Wireframe
尊重VisibleEntities
- 在灯光集群和边界框中尽可能使用 const
Vec2
- 使网格顶点和索引的访问器公开
- 对
SkinnedMeshUniform
使用BufferUsages::UNIFORM
- 在使用
ScalingMode::WindowSize
时,将OrthographicProjection
的原点放置在整数像素处 - 使
ScalingMode
更灵活 - 将纹理采样移出
prepare_normal
中的分支 - 使
Material2dKey
的字段公开 - 使用 collect 来构建网格属性
- 将
ReadOnlyFetch
替换为ReadOnlyWorldQuery
- 将
ComponentSparseSet
的内部替换为Column
- 从所有
Query/State
方法和类型中删除 QF 泛型 - 删除
.system()
- 使更改生命周期确定性并更新文档
- 如果可能,使派生的
SystemParam
只读 - 合并
matches_archetype
和matches_table
- 允许将可变查询转换为不可变查询
- 当
needs_drop
为false
时跳过drop
- 对
ComponentSparseSet
索引使用 u32 而不是 usize - 删除
Column
中多余的ComponentId
- 直接将移动的
Table
组件复制到目标位置 SystemSet::before
和SystemSet::after
现在接受AsSystemLabel
- 尽可能将排他性系统转换为并行系统
- 改进
QueryIter
上的size_hint
- 改进更改检测的调试工具
- 使
RunOnce
成为非手动System
实现 - 在
ParamSet
中应用缓冲区 - 不要为非动态组件类型的
ComponentDescriptors
分配内存 - 将 ECS 存储中的可变 API 标记为
pub(crate)
- 更新
ExactSizeIterator
实现以支持原型过滤器(With
、Without
) - 从不需要拆分可变访问的地方删除世界单元
- 将事件添加到
bevy_ecs
前缀 - 改进
EntityMap
API - 为
ShouldRun
实现From<bool>
。 - 允许对自定义世界查询进行迭代组合
- 简化
*Label
的设计 - 整理事件代码
- 将
send_default_event
重命名为send_event_default
在世界中 - 启用可选依赖项以保持可选
- 删除依赖项循环
- 强制对
Handle::get
进行类型安全使用 - 为自定义资产加载器导出
anyhow::error
- 更新
shader_material_glsl
示例以包含纹理采样 - 删除生命游戏着色器中未使用的代码
- 使贡献者小鸟反弹到窗口高度
- 改进游戏手柄方向键按钮检测
- bevy_reflect:支持地图插入
- bevy_reflect:改进反射类型的调试格式
- bevy_reflect_derive:大幅重构,整理代码
- bevy_reflect:小幅重构和默认
Reflect
方法 - 使
Reflect
的实现安全 bevy_reflect
:将serialize
放入外部ReflectSerialize
类型- 删除
dyn Array
及其朋友的Serialize
实现 - 重新启用
#[derive(TypeUuid)]
用于泛型 - 将原始类型注册移入
bevy_reflect
- 为更多
glam
类型实现反射 - 使
reflect_partial_eq
返回更准确的结果 - 使用
$crate
使公共宏更健壮 - 确保父级始终是预期的实体
- 支持从
with_children
中返回数据 - 删除
EntityMut::get_unchecked
- 诊断:当图形节点输入数量错误时,显示有意义的错误
- 删除多余的
Size
导入 - 导出并注册
Mat2
。 - 为
Gamepads
实现Debug
- 更新代码库以尽可能使用
IntoIterator
。 - 将
headless_defaults
示例重命名为no_renderer
以提高清晰度 - 删除已弃用的
SystemLabelMarker
结构体 - bevy_reflect:从一个在没有 glam 特征的情况下激活的测试中删除
glam
- 为压力测试禁用垂直同步
- 将
get_short_name
实用程序方法从bevy_reflect
移入bevy_utils
- 如果可能,为枚举派生
Default
- 为
MouseScrollUnit
实现Eq
和PartialEq
- 对
bevy_ptr
进行一些清理 - 将 float_ord 从
bevy_core
移动到bevy_utils
- 删除未使用的
CountdownEvent
- 对 asset_server 进行一些小的清理
- 对
Instant
使用elapsed()
- 使暂停的
Timers
在滴答时更新just_finished
- bevy_utils:删除硬编码的日志级别限制
- 使
Time::update_with_instant
公开供测试使用 - 不要为 Task 实现 Component
- 删除不存在的
WgpuResourceDiagnosticsPlugin
- 将 ndk-glue 要求从 0.5 更新到 0.6
- 将 tracing-tracy 要求从 0.8.0 更新到 0.9.0
- 将 image 更新到 0.24
- 将 xshell 更新到 0.2
- 将 gilrs 更新到 v0.9
- bevy_log:升级到 tracing-tracy 0.10.0
- 将 hashbrown 更新到 0.12
- 在使用
value_parser
的工具中将clap
更新到 3.2 - 将
glam
更新到0.21
。 - 更新 Notify 依赖项
修复了 #
- bevy_ui:将
Color
保持为 4 个f32
- 修复了除渲染以外的 bevy 在 android 上的问题
- 当缩放系数更改时,也更新布局/样式
- 修复
Overflow::Hidden
使其与scale_factor_override
一起正常工作 - 修复
bevy_ui
触摸输入 - 修复物理视窗计算
- 最小程度地修复了
bevy_mikktspace
中已知的非安全性 - 使
Transform
传播在更新子级的情况下正确 StorageBuffer
使用错误的类型来计算缓冲区大小。- 修复了相机中令人困惑的近端和远端字段
- 如果使用 2D 相机,允许最小化窗口
- WGSL:使用正确的语法进行矩阵访问
- Gltf:不要在 wasm 中导入
IoTaskPool
- 修复了网格着色器中带蒙皮网格法线的处理
- 当
StandardMaterial
normal_map
尚未加载时,不要出现恐慌 - 修复了
Transform::rotate_around
中不正确的旋转 - 修复
extract_wireframes
- 修复
#[derive(Bundle)]
的类型参数名称冲突 - 删除
ParallelSystemContainer
的不必要的unsafe impl
的Send+Sync
- 修复线材质着色器
- 修复了触摸的
mouse_clicked
检查 - 修复了
Or
/AnyOf
/Option
组件访问的非安全性 - 提高
CommandQueue
的安全性 - 修复了 miri 检测到的一些内存泄漏
- 修复 Android 示例图标
- 修复了损坏的
WorldCell
测试 - 修复了
State::set
转换条件无限循环的错误 - 修复了使用
Duration::MAX
时的崩溃 - 修复了发行版构建:将断言移动到
#[cfg(debug_assertions)]
下 - 修复了帧计数是浮点数的错误
- 修复了在使用
render
特征但没有animation
时出现的“未用”警告 - 修复了将插件重新添加到
PluginGroup
中的问题 - 修复了圆环法线
- 在需要时添加
NO_STORAGE_BUFFERS_SUPPORT
shaderdef