Bevy 0.14
发布日期:2024 年 7 月 4 日,作者:Bevy 贡献者
感谢 **256** 位贡献者、**993** 个拉取请求、社区审阅者以及我们慷慨的捐赠者,我们很高兴地宣布 **Bevy 0.14** 在 crates.io 上发布!
对于那些不了解 Bevy 的人,它是一个使用 Rust 构建的,令人耳目一新的简单、数据驱动的游戏引擎。您可以查看我们的 快速入门指南,立即尝试一下。它永远免费且开源!您可以在 GitHub 上获取完整的 源代码。查看 Bevy 资源,获取社区开发的插件、游戏和学习资源的集合。
要将现有的 Bevy App 或插件更新到 **Bevy 0.14**,请查看我们的 0.13 到 0.14 迁移指南。
自从我们几个月前发布以来,我们添加了许多新功能、错误修复和质量改进,但以下是一些亮点
- 虚拟几何体:将网格预处理成“网格片”,使渲染大量几何体变得高效
- 锐利的屏幕空间反射:近似实时光线追踪屏幕空间反射
- 景深:使特定深度的物体“失焦”,模仿物理镜头的行为
- 逐物体运动模糊:对相对于摄像机快速移动的物体进行模糊处理
- 体积雾/光照:模拟 3D 空间中的雾,使灯光能够产生美丽的光线轴
- 胶片色彩分级:使用一组完整的胶片色彩分级工具,微调游戏中的色调映射
- PBR 各向异性:改善表面渲染,这些表面的粗糙度沿网格的切线和副切线方向变化,例如刷过的金属和头发
- 自动曝光:配置摄像机以根据它们所观察到的内容动态调整曝光
- 点光源的 PCF:使点光源阴影变得平滑,改善其质量
- 动画混合:我们的新型低级动画图增加了对动画混合的支持,并为第一方和第三方图形、资产驱动的动画工具奠定了基础。
- ECS 钩子和观察者:自动(且立即)响应任意事件,例如组件添加和删除
- 更好的色彩:类型安全的色彩使操作的色彩空间变得清晰,并提供了一系列有用的方法。
- 计算状态和子状态:使用这些对
States
抽象的类型安全扩展,对复杂应用程序状态进行建模变得轻而易举。 - 圆角:在
bevy_ui
的最粗糙的边缘中,您现在可以程序化地设置 UI 元素的角半径。
Bevy 0.14 是第一次使用 **发布候选版** 流程进行准备的,以确保您能够放心地立即升级。我们与插件作者和普通用户紧密合作,捕捉关键错误,完善新功能的不足之处,并改进迁移指南。在准备修复程序时,我们已 在 crates.io 上发布了新的发布候选版,让核心生态系统箱子进行更新,并密切关注关键问题。非常感谢 所有提供帮助的人:这些努力是将 Bevy 打造成团队无论大小都可以信赖的可靠工具的关键步骤。
虚拟几何体(实验性) #
- 作者:@JMS55、@atlv24、@zeux、@ricky26
- PR #10164
经过几个月的努力,我们很高兴地为您带来新的虚拟几何体功能的实验性版本!
这种新的渲染功能与虚幻引擎 5 的 Nanite 渲染器非常相似。您可以获取一个非常高精度的网格,在构建时对其进行预处理以生成 MeshletMesh
,然后在运行时渲染大量的几何体——远超 Bevy 的标准渲染器所能支持的范围。不需要显式的 LOD——这一切都是自动的,并且几乎无缝。
此功能仍在开发中,与 Bevy 的标准渲染器相比,它有一些限制,因此请务必阅读文档并报告遇到的任何错误。我们还有很多工作要做,所以请期待未来版本中更多的性能改进(以及相关的重大变更)!
请注意,此功能不使用 GPU“网格着色器”,因此旧的 GPU 目前可以兼容。但是,不建议使用旧的 GPU,并且它们可能会在不久的将来被取消支持。
除了以下用户指南之外,请查看
想要使用虚拟几何体的用户应该在运行时使用 meshlet
Cargo 功能进行编译,在构建时使用 meshlet_processor
Cargo 功能对网格进行预处理,使其转换为网格片专用格式 (MeshletMesh
),这是网格片渲染器使用的格式。
启用网格片功能将解锁一个新模块:bevy::pbr::experimental::meshlet
.
第一步,将 MeshletPlugin
添加到您的应用程序
app.add_plugins(MeshletPlugin);
接下来,将您的 Mesh
预处理成 MeshletMesh
。目前,这需要通过 MeshletMesh::from_mesh()
手动完成(再次强调,您需要启用 meshlet_processor
功能)。此步骤相当缓慢,应该在事先完成一次,然后保存到资产文件中。请注意,对支持的网格和材质类型存在限制,请务必阅读文档。
计划通过 Bevy 的资产预处理系统实现自动 GLTF/场景转换,但不幸的是,它没有及时完成这次发布。目前,您需要自己创建资产转换和管理系统。如果您找到了一个好的系统,请告诉我们!
现在,生成您的实体。与 MaterialMeshBundle
相似,有一个 MaterialMeshletMeshBundle
,它使用 MeshletMesh
而不是传统的 Mesh
。
commands.spawn(MaterialMeshletMeshBundle {
meshlet_mesh: meshlet_mesh_handle.clone(),
material: material_handle.clone(),
transform,
..default()
});
最后,关于材质说明一下。Meshlet 实体使用与普通网格实体相同的 Material
特性,但标准的材质方法未使用。取而代之的是 3 种新方法:meshlet_mesh_fragment_shader
、meshlet_mesh_prepass_fragment_shader
和 meshlet_mesh_deferred_fragment_shader
。支持所有 3 种方法,包括前向渲染、带预渲染的前向渲染和延迟渲染。
但是请注意,无法访问顶点着色器。Meshlet 渲染使用一个硬编码的顶点着色器,无法更改。
Meshlet 材质的实际片段着色器代码与普通网格实体的片段着色器代码基本相同。主要区别在于,您应该使用以下代码,而不是:
@fragment
fn fragment(vertex_output: VertexOutput) -> @location(0) vec4<f32> {
// ...
}
#import bevy_pbr::meshlet_visibility_buffer_resolve::resolve_vertex_output
@fragment
fn fragment(@builtin(position) frag_coord: vec4<f32>) -> @location(0) vec4<f32> {
let vertex_output = resolve_vertex_output(frag_coord);
// ...
}
锐利屏幕空间反射 #
- 作者:@pcwalton
- PR #13418
将此图片拖动以进行比较


屏幕空间反射 (SSR) 通过在深度缓冲区中进行光线步进并从最终渲染帧中复制样本,来近似实时反射。我们的初始实现相对简单,目的是提供一个灵活的基础,以便于在此基础上构建,但它基于 Tomasz Stachowiak 创建的生产级 光线步进代码,他是独立游戏大作 Tiny Glade 的创作者之一。因此,需要注意一些事项
- 目前,此功能构建在延迟渲染器之上,并且目前仅在该模式下受支持。向前屏幕空间反射是可能的,尽管并不常见(例如,Doom Eternal 使用了它们);但是,它们需要从上一帧进行追踪,这会增加复杂性。此补丁为在向前渲染路径中实现 SSR 留下了空间,但本身并没有这样的实现。
- 屏幕空间反射在 WebGL 2 中不受支持,因为它们需要从深度缓冲区中采样,而
naga
由于存在错误无法执行此操作(sampler2DShadow
错误地生成了sampler2D
;这就是景深在该平台上禁用的原因)。 - 根本没有执行时间滤波或模糊。因此,SSR 目前仅在非常低粗糙度/光滑表面上运行。
- 我们不通过分层 Z 缓冲区进行加速,并且反射在全分辨率下进行追踪。因此,您可能会注意到性能问题,具体取决于您的场景和硬件。
要将屏幕空间反射添加到相机中,请插入 ScreenSpaceReflectionsSettings
组件。除了 ScreenSpaceReflectionsSettings
之外,还必须存在 DepthPrepass
和 DeferredPrepass
,才能显示反射。方便的是,ScreenSpaceReflectionsBundle
将所有这些捆绑在一起!虽然 ScreenSpaceReflectionsSettings
带有合理的默认值,但它还包含艺术家可以调整的多个设置。
体积雾和体积光照(光束/上帝之光) #
- 作者:@pcwalton
- PR #13057
并非所有雾都是平等的。Bevy 的现有实现涵盖了 距离雾,它速度快、简单,但并不特别逼真。
在 Bevy 0.14 中,这是基于 体积光照 的体积雾的补充,它使用实际的 3D 空间来模拟雾,而不是简单地使用与相机的距离。正如您可能预期的那样,这既更漂亮也更耗费计算资源!
特别是,这允许创建惊人美丽的“上帝之光”(更准确地说是黄昏光线),从雾中照射出来。
将此图片拖动以进行比较


Bevy 的算法(作为后期处理效果实现)结合了 Scratchapixel 和 Alexandre Pestana 的博客文章 中描述的技术。它使用屏幕空间中的光线步进(由 h3r2tic 移植到 WGSL),转换为阴影贴图空间以进行采样,并与基于物理的吸收和散射建模相结合。Bevy 使用广泛使用的 Henyey-Greenstein 相位函数来模拟不对称性;这本质上允许光束在用户查看它们时淡入淡出。
要将体积雾添加到场景中,请将 VolumetricFogSettings
添加到相机中,并将 VolumetricLight
添加到您希望成为体积光的方向光中。 VolumetricFogSettings
具有许多设置,允许您定义模拟的精度以及雾的外观。目前,仅支持与具有阴影贴图的方向光交互。请注意,效果的开销与使用的方向光数量直接相关,因此谨慎使用 VolumetricLight
以获得最佳结果。
使用我们的 volumetric_fog
示例 亲身体验一下。
每个物体运动模糊 #
- 作者:@aevyrie、@torsteingrindvik
- PR #9924
我们添加了一种后期处理效果,可以在运动方向上模糊快速移动的物体。我们的实现使用运动向量,这意味着它适用于 Bevy 的内置 PBR 材质、蒙皮网格或任何其他写入运动向量和深度的对象。该效果用于传达高速运动,否则在图像完美锐利时看起来像是闪烁或瞬移。
模糊随物体相对于相机的运动而缩放。如果相机跟踪快速移动的物体(例如,车辆),则车辆将保持清晰,而静止物体将被模糊。相反,如果相机指向一个静止物体,而一个快速移动的车辆穿过画面,那么只有快速移动的物体会被模糊。
该实现使用 相机快门角 进行配置,它对应于虚拟快门在帧期间打开的时间。实际上,这意味着该效果随帧率而缩放,因此以高刷新率运行的用户不会受到过度模糊的影响。
您可以通过将 MotionBlurBundle
添加到相机实体来启用运动模糊,如我们的 motion blur
示例 中所示。
电影色彩分级 #
- 作者:@pcwalton
- PR #13121
艺术家希望为他们的游戏获得完全正确的外观,而颜色起着至关重要的作用。
为了支持这一点,Bevy 的 现有色调映射工具 已扩展到包含一组完整的电影色彩分级工具。除了 基本色调映射 之外,您现在还可以配置
- 白点调整。这受 Unity 实现此功能的启发,但进行了简化和优化。温度和色调控制 CIE 1931 的 x 和 y 色度值的调整。与 Unity 一致,这些调整是在 LMS 颜色空间中相对于 D65 标准光源进行的。
- 色调旋转:将 RGB 值转换为 HSV,改变色调,然后转换回来。
- 颜色校正:允许根据标准 ASC CDL 组合函数调整 gamma、增益和提升值。这可以分别针对阴影、中间调和高光进行。为了避免颜色变化突然,在图像的不同部分之间使用了一个小的交叉淡入淡出。
我们尽可能地遵循了 Blender 的实现,以确保您在建模软件中看到的内容与您在游戏中看到的内容相匹配。
我们提供了一个新的 color_grading
示例,它带有一个闪亮的 GUI,用于更改所有色彩分级设置。非常适合复制粘贴到您自己的游戏的开发工具中,并使用这些设置进行玩耍!请注意,所有这些设置都可以在运行时更改:让艺术家可以控制场景的确切气氛,或者根据天气或一天中的时间动态地改变气氛。
自动曝光 #
- 作者:@Kurble、@alice-i-cecile
- PR #12792
自 Bevy 0.13 以来,您可以 配置相机的 EV100,这使您能够以基于物理的方式调整相机的曝光。这也使您能够动态更改各种效果的曝光值。但是,这是一个手动过程,需要您自己调整曝光值。
Bevy 0.14 引入了 自动曝光,它会根据场景的亮度自动调整相机的曝光。当您想要营造非常高动态范围的感觉时,这很有用,因为您的眼睛也会适应亮度的大幅变化。请注意,这不是手动调整曝光值的替代品,而是一种额外的工具,您可以使用它在亮度快速变化时营造戏剧性的效果。查看从 示例 中录制的视频,以查看它的实际效果!
Bevy 的自动曝光是通过在后期处理步骤中对场景亮度进行 直方图 来实现的。然后根据直方图的平均值调整曝光。由于直方图是使用计算着色器计算的,因此 自动曝光在 WebGL 上不可用。它默认情况下也不启用,因此您需要将 AutoExposurePlugin
添加到您的应用程序中。
自动曝光由 AutoExposureSettings
组件控制,您可以将其添加到相机实体中。您可以配置一些内容
- 曝光可以改变的 F 档 范围。
- 曝光改变的 速度。
- 可选的 测光蒙版,它使您可以例如,对图像的中心赋予更大的权重。
- 可选的直方图 滤波器,它使您可以忽略非常亮或非常暗的像素。
快速景深 #
- 作者:@pcwalton、@alice-i-cecile、@Kurble
- PR #13009
在渲染中,景深 是一种模拟 物理透镜的局限性 的效果。由于光的运作方式,透镜(如人眼或胶片相机的透镜)只能聚焦在距其特定范围(深度)内的物体上,导致所有其他物体变得模糊并失焦。
Bevy 现在附带此效果,它作为后期处理着色器实现。有两种选项可用:快速的 Gaussian 模糊或更逼真的六边形散景技术。散景模糊通常比 Gaussian 模糊更美观,因为它更准确地模拟了相机的效果。散景圆的形状由光圈叶片的数量决定。在本例中,我们使用六边形,这通常被认为是较低质量相机的特点。
将此图片拖动以进行比较


模糊量通常由 f 档 指定,我们用它来从胶片尺寸和 视野 计算 焦距。默认情况下,我们使用 f/1 f 档和对应于经典 Super 35 胶片格式的胶片尺寸来模拟标准电影相机。开发人员可以根据需要自定义这些值。
要查看此新 API,请查看专门的 depth_of_field
示例。
PBR 各向异性 #
- 作者:@pcwalton
- PR #13450
各向异性材料 随运动轴变化,例如木材沿纹理方向和逆纹理方向的性能差异很大。但在基于物理的渲染中,**各向异性** 特指一种允许粗糙度沿网格的切线和副切线方向变化的特性。实际上,这会导致镜面光线拉伸成线条而不是圆形光瓣。这对于模拟磨砂金属、头发和类似表面非常有用。各向异性支持是主要游戏和图形引擎的常见功能;Unity、Unreal、Godot、three.js 和 Blender 都在不同程度上支持它。
将此图片拖动以进行比较


已向 StandardMaterial
添加了两个新参数:anisotropy_strength
和 anisotropy_rotation
。各向异性强度取值范围为 0 到 1,表示网格切线和副切线之间的粗糙度差异程度。实际上,它控制镜面高光拉伸的程度。各向异性旋转允许粗糙度方向与模型的切线方向不同。
除了这两个固定参数外,还可以提供各向异性纹理,使用 KHR_materials_anisotropy
指定的线性纹理格式。
与往常一样,请在相应的 anisotropy
示例 中试用一下。
点光源的百分比更近滤波 (PCF) #
- 作者:@pcwalton
- PR #12910
百分比更近滤波是一种标准的抗锯齿技术,用于获得更柔和、更不生硬的阴影。为此,我们使用高斯核从阴影贴图中对感兴趣像素附近的像素进行采样,对结果进行平均,从而减少阴影中突然的过渡。
因此,Bevy 的点光源现在看起来更柔和、更自然,而无需更改最终用户代码。与之前一样,您可以通过设置 3D 相机上的 ShadowFilteringMethod
组件来配置用于对阴影进行抗锯齿的具体策略。
将此图片拖动以进行比较


百分比更近阴影的全面支持 正在进行中:测试和评论,与往常一样,非常欢迎。
亚像素形态抗锯齿 (SMAA) #
- 作者:@pcwalton、@alice-i-cecile
- PR #13423
锯齿边缘是游戏开发人员的梦魇:为了解决这些问题,而不降低图像质量,已经发明了各种各样的抗锯齿技术,并且仍在使用。除了 MSAA、FXAA 和 TAA 外,Bevy 现在还实现了 SMAA:亚像素形态抗锯齿。
SMAA 是一种 2011 年的抗锯齿技术,它检测图像中的边界,然后对附近的边界像素进行平均,从而消除令人讨厌的锯齿。尽管它已经很老了,但在过去的十年中,它一直是游戏的持续支柱。提供四种质量预设:低、中、高和超高。由于消费级硬件的进步,Bevy 的默认值为高。
您可以从下面的两张图片中看到它与无抗锯齿的效果对比。
将此图片拖动以进行比较


要了解各种抗锯齿方法的权衡,最好的方法是使用 anti_aliasing
示例 对测试场景进行实验,或者直接在自己的游戏中进行尝试。
可见范围(分层细节级别 / HLOD) #
- 作者:@pcwalton、@cart
- PR #12916
当我们观察远处物体时,很难看清细节!这一显而易见的事实,在渲染中和现实生活中都是一样的。因此,对远处的物体使用复杂的、高保真度的模型是一种浪费:我们可以用简化的等效模型替换它们的网格。
通过以这种方式自动改变我们模型的**细节级别**(LOD),我们可以渲染更大的场景(或使用更高的绘制距离渲染相同的开放世界),根据模型与玩家的距离动态切换网格。Bevy 现在支持其中最基础的工具之一:**可见范围**(有时称为分层细节级别,因为它允许用户将多个网格替换为单个物体)。
通过在网格实体上设置 VisibilityRange
组件,开发人员可以自动控制其网格在相机中的哪个范围出现和消失,并使用抖动在两个选项之间自动淡入淡出。隐藏网格是在渲染管道的早期进行的,因此此功能可以有效地用于细节级别优化。此外,此功能会针对每个视图进行正确评估,因此不同的视图可以显示不同的细节级别。
请注意,此功能不同于真正的网格 LOD(其中几何体本身会自动简化),后者将在稍后实现。虽然网格 LOD 有助于优化,并且不需要任何额外设置,但它们不如可见范围灵活。游戏通常希望使用网格以外的物体来替换远处的模型,例如八面体或 广告牌 蒙版:首先实现可见范围,可以让用户灵活地从现在开始实施这些解决方案。
您可以在 visibility_range
示例 中查看此功能的用法。
ECS 钩子和观察者 #
- 作者:@james-j-obrien、@cart
- PR #10839
我们很高兴在 Bevy 中遍历同质数据块,但并非所有任务都完美适合简单的 ECS 模型。响应更改和/或处理事件是任何应用程序中必不可少的任务,游戏也不例外。
Bevy 已经具有一系列用于处理此问题的工具
- 缓冲的
Event
:多生产者、多消费者队列。灵活且高效,但需要定期轮询作为计划的一部分。事件会在两帧后被丢弃。 - 通过
Added
和Changed
进行更改检测:允许编写可以响应添加或更改的组件的查询。这些查询会线性扫描匹配查询的组件的更改状态,以查看它们是否已添加或更改。 RemovedComponents
:一种特殊的事件形式,当从实体中删除组件或具有该组件的实体被销毁时触发。
所有这些(以及系统本身!)都使用 "拉式机制":无论是否有监听者,都会发送事件,监听者必须定期轮询以询问是否有任何更改。这是一个有用的模式,我们打算保留它!通过轮询,我们可以批量处理事件,获得更多上下文并提高数据局部性(这会让 CPU 嗡嗡作响)。
但这有一些限制
- 在触发事件和处理响应之间存在不可避免的延迟
- 轮询会在每一帧引入少量(但非零)开销
这种延迟是一个关键问题
- 数据(例如索引或层次结构)即使在短暂的时间内也可能存在于无效状态
- 我们无法在一个周期内处理任意事件链或递归逻辑
为了克服这些限制,**Bevy 0.14** 引入了**组件生命周期钩子**和**观察者**:两种互补的“推式”机制,灵感来自始终出色的 flecs ECS。
组件生命周期钩子
组件钩子 是为特定组件类型(作为 Component
特性实现的一部分)注册的函数(能够与 ECS 世界进行交互),这些函数会在响应“组件生命周期事件”时自动运行,例如当该组件被添加、覆盖或删除时。
对于给定的组件类型,只能为给定的生命周期事件注册一个钩子,并且不能覆盖它。
钩子用于强制与该组件相关的约束(例如:维护索引或层次结构的正确性)。钩子不能被删除,并且始终优先于观察者:它们在任何添加或插入观察者之前运行,但在任何删除观察者之后运行。因此,可以将它们视为更接近于构造函数和析构函数,更适合于维护关键的安全或正确性约束。钩子也比观察者快一些,因为它们的灵活性较低,意味着涉及的查找次数较少。
让我们检查一个简单的示例,在这个示例中,我们关心维护约束:一个实体(带有 Target
组件)目标另一个实体(带有 Targetable
组件)。
#[derive(Component)]
struct Target(Option<Entity>);
#[derive(Component)]
struct Targetable {
targeted_by: Vec<Entity>
};
我们希望在目标实体被销毁时自动清除 Target
:我们该怎么做呢?
如果我们使用基于拉式的方案(在本例中为 RemovedComponents
),则在实体被销毁和 Target
组件被更新之间可能存在延迟。我们可以使用钩子消除这种延迟!
让我们看看在 Targetable
上使用钩子时的样子
// Rather than a derive, let's configure the hooks with a custom
// implementation of Component
impl Component for Targetable {
const STORAGE_TYPE: StorageType = StorageType::Table;
fn register_component_hooks(hooks: &mut ComponentHooks) {
// Whenever this component is removed, or an entity with
// this component is despawned...
hooks.on_remove(|mut world, targeted_entity, _component_id|{
// Grab the data that's about to be removed
let targetable = world.get::<Targetable>(targeted_entity).unwrap();
for targeting_entity in targetable.targeted_by {
// Track down the entity that's targeting us
let mut targeting = world.get_mut::<Target>(targeting_entity).unwrap();
// And clear its target, cleaning up any dangling references
targeting.0 = None;
}
})
}
}
观察者
观察者是按需运行的系统,用于监听“触发”的事件。这些事件可以针对特定实体触发,也可以“全局”触发(没有实体目标)。
与钩子相比,观察者是一种灵活的工具,用于更高级别的应用程序逻辑。它们可以观察何时触发用户定义的事件。
#[derive(Event)]
struct Message {
text: String
}
world.observe(|trigger: Trigger<Message>| {
println!("{}", trigger.event().message.text);
});
观察者会在触发它们正在监听的事件时立即运行
// All registered `Message` observers are immediately run here
world.trigger(Message { text: "Hello".to_string() });
如果事件是通过 Command
触发的,则观察者会在 Command
被刷新时运行
fn send_message(mut commands: Commands) {
// This will trigger all `Message` observers when this system's commands are flushed
commands.trigger(Message { text: "Hello".to_string() } );
}
事件也可以使用实体目标触发
#[derive(Event)]
struct Resize { size: usize }
commands.trigger_targets(Resize { size: 10 }, some_entity);
您可以同时为多个实体触发事件
commands.trigger_targets(Resize { size: 10 }, [e1, e2]);
当任何目标被触发时,将执行“全局”观察者
fn main() {
App::new()
.observe(on_resize)
.run()
}
fn on_resize(trigger: Trigger<Resize>, query: Query<&mut Size>) {
let size = query.get_mut(trigger.entity()).unwrap();
size.value = trigger.event().size;
}
请注意,观察者可以使用系统参数,例如 Query
,就像普通系统一样。
您还可以添加仅对特定实体运行的观察者
commands
.spawn(Widget)
.observe(|trigger: Trigger<Resize>| {
println!("This specific widget entity was resized!");
});
观察者实际上只是一个带有 Observer
组件的实体。上面使用的所有 observe()
方法只是生成新观察者实体的简写。这就是“全局”观察者实体的样子
commands.spawn(Observer::new(|trigger: Trigger<Message>| {}));
同样,监听特定实体的观察者看起来像这样
commands.spawn(
Observer::new(|trigger: Trigger<Resize>| {})
.with_entity(some_entity)
);
此 API 使管理和清理观察者变得很容易。它还支持高级用例,例如跨多个目标共享观察者!
现在我们已经了解了一些有关观察者的知识,让我们通过一个简单的以游戏玩法为中心的示例来检查 API
单击以展开...
use bevy::prelude::*;
#[derive(Event)]
struct DealDamage {
damage: u8,
}
#[derive(Event)]
struct LoseLife {
life_lost: u8,
}
#[derive(Event)]
struct PlayerDeath;
#[derive(Component)]
struct Player;
#[derive(Component)]
struct Life(u8);
#[derive(Component)]
struct Defense(u8);
#[derive(Component, Deref, DerefMut)]
struct Damage(u8);
#[derive(Component)]
struct Monster;
fn main() {
App::new()
.add_systems(Startup, spawn_player)
.add_systems(Update, attack_player)
.observe(on_player_death);
}
fn spawn_player(mut commands: Commands) {
commands
.spawn((Player, Life(10), Defense(2)))
.observe(on_damage_taken)
.observe(on_losing_life);
}
fn attack_player(
mut commands: Commands,
monster_query: Query<&Damage, With<Monster>>,
player_query: Query<Entity, With<Player>>,
) {
let player_entity = player_query.single();
for damage in &monster_query {
commands.trigger_targets(DealDamage { damage: damage.0 }, player_entity);
}
}
fn on_damage_taken(
trigger: Trigger<DealDamage>,
mut commands: Commands,
query: Query<&Defense>,
) {
let defense = query.get(trigger.entity()).unwrap();
let damage = trigger.event().damage;
let life_lost = damage.saturating_sub(defense.0);
// Observers can be chained into each other by sending more triggers using commands.
// This is what makes observers so powerful ... this chain of events is evaluated
// as a single transaction when the first event is triggered.
commands.trigger_targets(LoseLife { life_lost }, trigger.entity());
}
fn on_losing_life(
trigger: Trigger<LoseLife>,
mut commands: Commands,
mut life_query: Query<&mut Life>,
player_query: Query<Entity, With<Player>>,
) {
let mut life = life_query.get_mut(trigger.entity()).unwrap();
let life_lost = trigger.event().life_lost;
life.0 = life.0.saturating_sub(life_lost);
if life.0 == 0 && player_query.contains(trigger.entity()) {
commands.trigger(PlayerDeath);
}
}
fn on_player_death(_trigger: Trigger<PlayerDeath>, mut app_exit: EventWriter<AppExit>) {
println!("You died. Game over!");
app_exit.send_default();
}
未来,我们计划使用钩子和观察者来 替换RemovedComponents
,使我们的层次结构管理更加健壮,创建 bevy_eventlistener
的第一方替代品作为我们 UI 工作的一部分,以及 构建关系。这些都是功能强大、通用的工具:我们迫不及待地想要看到社区用它们创造的疯狂科学!
当你准备好开始时,请查看 component hooks
和 observers
示例以了解更多 API 细节。
glTF KHR_texture_transform 支持 #
- 作者:@janhohenheim、@yrns、@Kanabenki
- PR #11904
GLTF 扩展 KHR_texture_transform
用于在应用纹理之前对其进行变换。通过读取此扩展,Bevy 现在可以支持各种新的工作流程。我们这里想要强调的是能够轻松地将纹理重复一定的次数。这对于创建旨在跨表面平铺的纹理很有用。我们将展示如何使用 Blender 来做到这一点,但相同的原则适用于任何 3D 建模软件。
让我们看一个我们在 Blender 中准备好的示例场景,它被导出为 GLTF 文件并加载到 Bevy 中。我们首先使用 Blender 中最基本的着色器节点设置
结果是在 Bevy 中的以下场景
哦,不!一切都拉伸了!这是因为我们将 UV 设置为将纹理恰好映射到网格上一次。有一些方法可以解决这个问题,但最方便的方法是添加着色器节点来缩放纹理,使其重复
Mapping
节点的數據是导出到 KHR_texture_transform
中的。看看红色部分。这些缩放因子决定了纹理在材质中应重复多少次。调整所有纹理的此值会导致更好的渲染结果
UI 节点边框半径 #
- 作者:@chompaa、@pablo-lua、@alice-i-cecile、@bushrat011899
- PR #12500
UI 节点的边框半径一直是 Bevy 的一个长期请求的功能。现在它得到了支持!
要将边框半径应用于 UI 节点,有一个新的组件 BorderRadius
。 NodeBundle
和 ButtonBundle
现在都有一个用于此组件的字段,名为 border_radius
commands.spawn(NodeBundle {
style: Style {
width: Val::Px(50.0),
height: Val::Px(50.0),
// We need a border to round a border, after all!
border: UiRect::all(Val::Px(5.0)),
..default()
},
border_color: BorderColor(Color::BLACK),
// Apply the radius to all corners.
// Optionally, you could use `BorderRadius::all`.
border_radius: BorderRadius {
top_left: Val::Px(50.0),
top_right: Val::Px(50.0),
bottom_right: Val::Px(50.0),
bottom_left: Val::Px(50.0),
},
..default()
});
有一个 新示例 展示了这个新的 API,下面可以看到它的截图
使用 AnimationGraph
进行动画混合 #
- 作者:@pcwalton、@rparrett、@james7132
- PR #11989
从初学者的角度来看,处理动画似乎很简单。定义一系列关键帧,这些关键帧将模型的各个部分转换为与这些姿势相匹配。我们在那里添加了一些插值以使它们之间平滑过渡,用户告诉您何时启动和停止动画。容易!
但现代动画管道(尤其是在 3D 中!)要复杂得多:动画师希望能够平滑地混合和以编程方式动态地更改不同的动画以响应游戏玩法。为了捕捉这种丰富性,业界已经发展出了动画图的概念,它用于将游戏对象的底层 状态机与应该播放的动画以及每个不同状态之间应该发生的过渡联系起来。
一个玩家角色可能正在行走、奔跑、挥舞剑、用剑防御……为了创造出精致的效果,动画师需要能够平滑地在这几项动画之间切换,改变步行循环的速度以匹配地面上的移动速度,甚至同时执行多项动画!
在 Bevy 0.14 中,我们已经实现了 动画组合 RFC,提供了一个低级 API,它为 Bevy 带来了代码驱动和资产驱动的动画混合。
#[derive(Resource)]
struct ExampleAnimationGraph(Handle<AnimationGraph>);
fn programmatic_animation_graph(
mut commands: Commands,
asset_server: ResMut<AssetServer>,
animation_graphs: ResMut<Assets<AnimationGraph>>,
) {
// Create the nodes.
let mut animation_graph = AnimationGraph::new();
let blend_node = animation_graph.add_blend(0.5, animation_graph.root);
animation_graph.add_clip(
asset_server.load(GltfAssetLabel::Animation(0).from_asset("models/animated/Fox.glb")),
1.0,
animation_graph.root,
);
animation_graph.add_clip(
asset_server.load(GltfAssetLabel::Animation(1).from_asset("models/animated/Fox.glb")),
1.0,
blend_node,
);
animation_graph.add_clip(
asset_server.load(GltfAssetLabel::Animation(2).from_asset("models/animated/Fox.glb")),
1.0,
blend_node,
);
// Add the graph to our collection of assets.
let handle = animation_graphs.add(animation_graph);
// Hold onto the handle
commands.insert_resource(ExampleAnimationGraph(handle));
}
虽然它今天可以发挥出巨大的作用,但大多数动画师最终会更喜欢使用 GUI 编辑这些图。我们计划在传奇的 Bevy 编辑器中,在这个 API 之上构建一个 GUI。如今,也有一些第三方解决方案,比如 bevy_animation_graph
。
要了解更多信息并查看资产驱动的方法是什么样的,请查看新的 animation_graph
示例。
改进的颜色 API #
- 作者:@viridia、@mockersf
- PR #12013
颜色是构建良好游戏的重要组成部分:UI、效果、着色器等等都需要功能齐全、正确且便捷的颜色工具。
Bevy 现在支持各种各样的颜色空间,每个颜色空间都有自己的类型(例如 LinearRgba
、Hsla
、Oklaba
),并提供了一系列针对它们的经过充分记录的操作和转换。
新的 API 更加防错、更符合习惯用法,并允许我们通过在渲染内部存储 LinearRgba
类型来节省工作。这个坚实的基础让我们能够实现各种有用的操作,这些操作被聚集成像 Hue
或 Alpha
这样的特征,让你可以对任何具有所需属性的颜色空间进行操作。重要的是,现在支持颜色混合/混合:非常适合程序化生成调色板和处理动画。
use bevy_color::prelude::*;
// Each color space now corresponds to a specific type
let red = Srgba::rgb(1., 0., 0.);
// All non-standard color space conversions are done through the shortest path between
// the source and target color spaces to avoid a quadratic explosion of generated code.
// This conversion...
let red = Oklcha::from(red);
// ...is implemented using
let red = Oklcha::from(Oklaba::from(LinearRgba::from(red)));
// We've added the `tailwind` palette colors: perfect for quick-but-pretty prototyping!
// And the existing CSS palette is now actually consistent with the industry standard :p
let blue = tailwind::BLUE_500;
// The color space that you're mixing your colors in has a huge impact!
// Consider using the scientifically-motivated `Oklcha` or `Oklaba` for a perceptually uniform effect.
let purple = red.mix(blue, 0.5);
大多数面向用户的 API 仍然接受与颜色空间无关的 Color
(它现在包装了我们的颜色空间类型),而渲染内部使用基于物理的 LinearRgba
类型。有关不同颜色空间的概述以及它们各自的用途,请查看我们的 颜色空间使用 文档。
bevy_color
提供了一个可靠的、类型安全的 foundation,但它才刚刚起步。如果你想要另一个颜色空间,或者你想对你的颜色做更多事情,请打开一个 issue 或 PR,我们很乐意提供帮助!
另请注意,bevy_color
旨在作为独立的 crate 有效地运行:随时在你的非 Bevy 项目中依赖它。
挤压形状 #
- 作者:@lynn-lumen
- PR #13270
Bevy 0.14 引入了一组全新的基元:挤压!
挤压是一个二维基元(基本形状),它通过某种深度挤压到三维空间中。生成的形状是棱柱(或者在圆形的特殊情况下,是圆柱体)。
// Create an ellipse with width 2 and height 1.
let my_ellipse = Ellipse::from_size(2.0, 1.0);
// Create an extrusion of this ellipse with a depth of 1.
let my_extrusion = Extrusion::new(my_ellipse, 1.);
所有挤压都沿 Z 轴挤压。这保证了深度为 0 的挤压与其对应的基本形状是相同的,正如人们所期望的那样。
测量和采样
由于所有具有实现 Measured2d
的基本形状的挤压都实现了 Measured3d
,因此你可以轻松地获得挤压的表面积或体积。如果你有一个自定义二维基元的挤压,你只需为你的基元实现 Measured2d
,Measured3d
就会自动为挤压实现。
同样,如果你挤压的基本形状实现了 ShapeSample<Output = Vec2>
和 Measured2d
,则可以对任何挤压的边界和内部进行采样。
// Create a 2D capsule with radius 1 and length 2, extruded to a depth of 3
let extrusion = Extrusion::new(Capsule2d::new(1.0, 2.0), 3.0);
// Get the volume of the extrusion
let volume = extrusion.volume();
// Get the surface area of the extrusion
let surface_area = extrusion.area();
// Create a random number generator
let mut rng = StdRng::seed_from_u64(4);
// Sample a random point inside the extrusion
let interior_sample = extrusion.sample_interior(&mut rng);
// Sample a random point on the surface of the extrusion
let boundary_sample = extrusion.sample_boundary(&mut rng);
绑定
你还可以获得挤压的包围球体和轴对齐包围盒 (AABB)。如果你有一个实现 Bounded2d
的自定义二维基元,你只需为你的基元实现 BoundedExtrusion
)。默认实现将提供最佳结果,但可能比适合你的基元的解决方案速度慢。
网格化
但是挤压并不仅仅存在于数学世界中。它们也可以被网格化并在屏幕上显示!
同样,Bevy 使为你的自定义基元添加网格化支持变得容易!你只需为你的二维基元实现网格化,然后为你的二维基元的 MeshBuilder
实现 Extrudable
。
在实现 Extrudable
时,你必须提供有关基本形状周边的哪些段应进行平滑着色或平面着色以及哪些顶点属于这些周边段的每个的信息。
Extrudable
特征允许你轻松地为自定义基元的挤压实现网格化。当然,你也可以为你的挤压手动实现网格化。
如果你想查看此功能的完整实现,你可以查看 自定义基元示例。
更多 Gizmo #
- 作者:@mweatherley、@Kanabenki、@MrGVSV、@solis-lumine-vorago、@alice-i-cecile
- PR #12211
Bevy 中的 Gizmo 允许开发人员轻松地绘制任意形状以帮助调试或创作内容,但也用于可视化场景的特定属性,例如网格的 AABB。
在 0.14 中,几个新的 Gizmo 已被添加到 bevy::gizmos
圆角盒子 Gizmo
圆角盒子和立方体非常适合可视化区域和碰撞体。
如果你将 corner_radius
或 edge_radius
设置为正值,则角将向外圆角。但是,如果你提供负值,则角将翻转并向内弯曲。
网格 Gizmo
新的网格 Gizmo 类型已通过 Gizmos::grid_2d
和 Gizmos::grid
添加,用于在二维或三维空间中绘制平面网格,以及 Gizmos::grid_3d
用于绘制三维网格。
每种网格类型都可以沿其轴倾斜、缩放和细分,并且你可以分别控制要绘制哪些外边缘。
坐标轴 Gizmo
新的 Gizmos::axes
添加了一种简单的方法来显示任何对象的 Transform
以及基本大小的位置、方向和比例。每个轴箭头的尺寸与其在提供的 Transform
中的相应轴比例成正比。
灯光 Gizmo
新的 ShowLightGizmo
组件实现了保留的 gizmo,用于可视化 SpotLight
、PointLight
和 DirectionalLight
的灯光。大多数灯光属性都通过 gizmo 可视化表示,并且可以设置 gizmo 颜色以匹配灯光实例或使用各种其他行为。
与其他保留的 gizmo 类似,ShowLightGizmo
可以通过 LightGizmoConfigGroup
在每个实例或全局范围内进行配置。
Gizmo 线样式和接头 #
- 作者:@lynn-lumen
- PR #12394
以前的 Bevy 版本支持绘制线条 gizmo。
fn draw_gizmos(mut gizmos: Gizmos) {
gizmos.line_2d(Vec2::ZERO, Vec2::splat(-80.), RED);
}
但是,自定义 gizmo 的唯一方法是更改其颜色,这对于某些用例来说可能有限制。此外,线条条带中两条线的交汇点(其接头)存在小的间隙。
从 Bevy 0.14 开始,您可以更改每个 gizmo 配置组的线条样式及其接头。
fn draw_gizmos(mut gizmos: Gizmos) {
gizmos.line_2d(Vec2::ZERO, Vec2::splat(-80.), RED);
}
fn setup(mut config_store: ResMut<GizmoConfigStore>) {
// Get the config for you gizmo config group
let (config, _) = config_store.config_mut::<DefaultGizmoConfigGroup>();
// Set the line style and joints for this config group
config.line_style = GizmoLineStyle::Dotted;
config.line_joints = GizmoLineJoint::Bevel;
}
新的线条样式可用于 2D 和 3D,并尊重其配置组的 line_perspective
选项。
可用的线条样式包括
GizmoLineStyle::Dotted
:绘制点线,每个点都是一个正方形。GizmoLineStyle::Solid
:绘制实线 - 这是默认行为,也是 Bevy 0.14 之前唯一的可用行为。
类似地,新的线条接头提供各种选项。
GizmoLineJoint::Miter
,它将两条线都延伸到它们在共同斜接点处相遇为止。GizmoLineJoint::Round(resolution)
,它将近似一个弧线,填补两条线之间的间隙。resolution
决定用于近似弧线几何形状的三角形数量。GizmoLineJoint::Bevel
,它使用直线段连接两条连接线的端点。GizmoLineJoint::None
,它不使用任何接头,并留下小的间隙 - 这是默认行为,也是 Bevy 0.14 之前唯一的可用行为。
您可以查看 2D gizmo 示例,它演示了线条样式和接头的使用!
UI 节点轮廓 Gizmo #
- 作者:@pablo-lua、@nicopap、@alice-i-cecile
- PR #11237
在网络上使用 UI 时,能够快速调试所有框的大小非常有用。我们现在有一个原生 布局工具,它为所有 节点 添加了 gizmo 轮廓。
启用工具后的示例
use bevy::prelude::*;
// You first have to add the DebugUiPlugin to your app
let mut app = App::new()
.add_plugins(bevy::dev_tools::ui_debug_overlay::DebugUiPlugin);
// In order to enable the tool at runtime, you can add a system to toggle it
fn toggle_overlay(
input: Res<ButtonInput<KeyCode>>,
mut options: ResMut<bevy::dev_tools::ui_debug_overlay::UiDebugOptions>,
) {
info_once!("The debug outlines are enabled, press Space to turn them on/off");
if input.just_pressed(KeyCode::Space) {
// The toggle method will enable the debug_overlay if disabled and disable if enabled
options.toggle();
}
}
// And add the system to the app
app.add_systems(Update, toggle_overlay);
上下文清除 Gizmo #
- 作者:@Aceeri
- PR #10973
Gizmo 通过立即模式 API 绘制。这意味着您在每次更新时绘制要显示的所有 gizmo,并且只有这些 gizmo 会显示。以前,更新指的是“每次 Main
调度运行时”。这与帧速率相匹配,因此它通常非常有效!但是,当您尝试在 FixedMain
期间绘制 gizmo 时,它们会闪烁或渲染多次。在 Bevy 0.14 中,这现在可以正常工作了!
这可以扩展到与自定义调度一起使用。不再是单个存储,而是有多个 存储,它们通过上下文类型参数区分。您也可以在 Gizmos
系统参数上设置类型参数,以选择要写入的存储。您可以选择何时绘制或清除添加的存储:默认存储(()
上下文)中的任何 gizmo 在 Last
调度期间都会显示。
查询连接 #
- 作者:@hymm
- PR #11535
ECS 查询现在可以组合,返回包含在两个查询中的实体的数据。
fn helper_function(a: &mut Query<&A>, b: &mut Query<&B>){
let a_and_b: QueryLens<(Entity, &A, &B)> = a.join(b);
assert!(a_and_b.iter().len() <= a.len());
assert!(a_and_b.iter().len() <= b.len());
}
在大多数情况下,您应该继续简单地在原始查询中添加更多参数。Query<&A, &B>
通常比稍后连接它们更清晰。但是,当复杂的系统或帮助程序函数将您逼入困境时,如果需要,查询连接就在那里。
如果您熟悉数据库术语,这是一种 "内连接"。正在考虑其他类型的查询连接。也许您可以尝试 后续问题?
计算状态和子状态 #
- 作者:@lee-orr、@marcelchampagne、@MiniaczQ、@alice-i-cecile
- PR #11426
Bevy 的 States
是一种简单但功能强大的抽象,用于管理应用程序的控制流。
但是,随着用户游戏的(以及非游戏应用程序!)复杂程度的提高,它们的局限性变得更加明显。如果我们想捕捉“在菜单中”的概念,但又有不同的状态对应于应该打开哪个子菜单,该怎么办?如果我们想问“游戏是否暂停”这样的问题,而这个问题只有在游戏内才有意义,该怎么办?
找到一个好的抽象来解决这个问题需要 多次 尝试,并进行大量的实验和讨论。
虽然您现有的 States
代码将与以前一样工作,但如果您正在寻找更多表现力,现在还有两种额外的工具可以使用:计算状态和子状态。
让我们从一个简单的状态声明开始
#[derive(States, Clone, PartialEq, Eq, Hash, Debug, Default)]
enum GameState {
#[default]
Menu,
InGame {
paused: bool
},
}
添加 pause
字段意味着仅仅检查 GameState::InGame
并不起作用……状态因其值而异,我们可能希望区分游戏暂停或不暂停时运行的游戏系统!
计算状态
虽然我们可以简单地执行 OnEnter(GameState::InGame{paused: true})
,但我们需要能够推断“在游戏期间,暂停或不暂停”。为此,我们定义 InGame
计算状态
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
struct InGame;
impl ComputedStates for InGame {
// Computed states can be calculated from one or many source states.
type SourceStates = GameState;
// Now, we define the rule that determines the value of our computed state.
fn compute(sources: GameState) -> Option<InGame> {
match sources {
// We can use pattern matching to express the
//"I don't care whether or not the game is paused" logic!
GameState::InGame {..} => Some(InGame),
_ => None,
}
}
}
子状态
相反,子状态应该在您想要通过 NextState
保持对值的控制,但仍将其存在绑定到某个父状态时使用。
#[derive(SubStates, Clone, PartialEq, Eq, Hash, Debug, Default)]
// This macro means that `GamePhase` will only exist when we're in the `InGame` computed state.
// The intermediate computed state is helpful for clarity here, but isn't required:
// you can manually `impl SubStates` for more control, multiple parent states and non-default initial value!
#[source(InGame = InGame)]
enum GamePhase {
#[default]
Setup,
Battle,
Conclusion
}
初始化
初始化我们的状态很容易:只需在 App
上调用适当的方法,所有必需的机制都会为您设置。
App::new()
.init_state::<GameState>()
.add_computed_state::<InGame>()
.add_sub_state::<GamePhase>()
与任何其他状态一样,计算状态和子状态适用于您习惯使用的所有工具:State
和 NextState
资源、OnEnter
、OnExit
和 OnTransition
调度以及 in_state
运行条件。请务必访问 两者 示例 以获取更多信息!
唯一的例外是,为了正确性,计算状态不能通过 NextState
更改。相反,它们严格地从其父状态派生;根据提供的 compute
方法,在状态转换期间自动添加、删除和更新。
所有 Bevy 的状态工具现在都位于专门的 bevy_state
crate 中,可以通过功能标志进行控制。渴望回到状态堆栈的日子?希望有一种方法可以重新进入状态?所有状态机制仅依赖于公共 ECS 工具:资源、调度和运行条件,使其易于构建在之上。我们知道状态机很大程度上取决于个人喜好;因此,如果我们的设计不符合您的口味,请考虑利用 Bevy 的模块化特性并编写自己的抽象或使用社区提供的抽象!
状态范围内的实体 #
- 作者:@MiniaczQ、@alice-i-cecile、@mockersf
- PR #13649
状态范围内的实体是一种在社区项目中自然出现的模式。Bevy 0.14 已经接受了它!
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default, States)]
enum GameState {
#[default]
Menu,
InGame,
}
fn spawn_player(mut commands: Commands) {
commands.spawn((
// We mark this entity with the `StateScoped` component.
// When the provided state is exited, the entity will be
// deleted recursively with all children.
StateScoped(GameState::InGame)
SpriteBundle { ... }
))
}
App::new()
.init_state::<GameState>()
// We need to install the appropriate machinery for the cleanup code
// to run, once for each state type.
.enable_state_scoped_entities::<GameState>()
.add_systems(OnEnter(GameState::InGame), spawn_player);
通过在设置期间将实体生命周期绑定到状态,我们可以大大减少需要编写的清理代码量!
状态标识转换 #
- 作者:@MiniaczQ、@alice-i-cecile
- PR #13579
用户有时会要求我们在从一个状态移动到自身时触发退出和进入步骤。虽然这有其用途(刷新是核心思想),但在其他情况下它可能会令人惊讶且不受欢迎。我们找到了一种折衷方案,允许用户在需要时挂接到这种类型的转换。
StateEventTransition
事件现在将包括从一个状态到自身的转换,这也会传播到所有依赖的 ComputedStates
和 SubStates
。
由于它是一个利基功能,OnExit
和 OnEnter
调度默认情况下会忽略新的标识转换,但您可以访问新的 custom_transitions
示例以查看如何绕过或更改该行为!
GPU 视锥剔除 #
- 作者:@pcwalton
- PR #12889
Bevy 的渲染堆栈通常是 CPU 密集型的:通过将更多工作转移到 GPU 上,我们可以更好地平衡负载并更快地渲染更多闪亮的东西。视锥剔除是一种优化技术,它会自动隐藏位于相机视野(其视锥)之外的物体。在 Bevy 0.14 中,用户可以选择在 GPU 上执行这项工作,具体取决于其项目的性能特征。
有两个新的组件可用于控制视锥剔除:GpuCulling
和 NoCpuCulling
。将这些组件的适当组合附加到相机上,就可以了。
commands.spawn((
Camera3dBundle::default(),
// Enable GPU frustum culling (does not automatically disable CPU frustum culling).
GpuCulling,
// Disable CPU frustum culling.
NoCpuCulling
));
世界命令队列 #
- 作者:@james7132、@james-j-obrien
- PR #11823
当您拥有独占世界访问权限时,使用 Commands
一直很痛苦。创建一个 CommandQueue
,从中生成一个 Commands
,发送您的命令,然后应用它?这并非最直观的解决方案。
现在,您可以访问 World
自己的命令队列
let mut world = World::new();
let mut commands = world.commands();
commands.spawn(TestComponent);
world.flush_commands();
虽然这不是性能最好的方法(直接将更改应用到世界并跳过间接调用),但此 API 非常适合快速原型设计或轻松测试您的自定义命令。它还在内部用于为组件生命周期钩子和观察者提供支持。
作为奖励,一次性系统现在会在运行时立即应用其命令(和其他延迟的系统参数)!我们已经拥有独占世界访问权限:为什么要引入延迟和微妙的错误?
降低的多线程执行开销 #
- 作者:@chescock、@james7132
- PR #11906
Bevy 的多线程系统执行器中最大的开销来源来自 线程上下文切换,即启动和停止线程。每次唤醒线程时,如果线程的缓存很冷,则可能需要多达 30us。最大限度地减少这些切换对于执行器来说是一项重要的优化。在本周期中,我们实施了两项更改,这些更改显示了改进
在每个系统任务结束时运行多线程执行器
系统执行器负责检查系统的依赖项是否已运行,并评估运行条件,然后为该系统运行任务。旧版多线程执行器作为一项单独的任务运行,该任务在每个任务完成后被唤醒。这有时会导致唤醒一个新线程,以便执行器处理系统完成。
通过将其更改为使系统任务尝试在每个系统完成后运行多线程执行器,我们确保多线程执行器始终在已唤醒的线程上运行。这防止了一个上下文切换来源。在实践中,这将每个 Schedule
运行的上下文切换次数减少了 1 到 3 倍,提高了约 30us/调度。当应用程序具有多个调度时,这可能会累积起来!
组合事件更新系统
以前每个事件类型都只有一个“事件更新系统”实例。仅仅使用 `DefaultPlugins`,就会导致 20 多个系统实例。
每个实例运行速度都很快,因此生成系统任务和唤醒线程以运行所有这些系统所产生的开销,占用了 `First` 调度运行时间的绝大部分。因此,将所有这些系统合并为一个系统,可以避免这种开销,并使 `First` 调度运行得更快。在测试中,这使得调度运行时间从 140us 降至 25us。再次强调,这并不是一个 *巨大* 的进步,但我们始终致力于节省每一微秒的时间!
将 `BackgroundColor` 与 `UiImage` 解耦 #
- 作者: @benfrankel
- PR #11165
UI 图像现在可以设置纯色背景。
`BackgroundColor` 组件现在适用于 UI 图像,而不是在图像本身应用颜色色调。您仍然可以通过设置 `UiImage::color` 来应用颜色色调。例如
commands.spawn((
ImageBundle {
image: UiImage {
handle: assets.load("logo.png"),
color: DARK_RED.into(),
..default()
},
..default()
},
BackgroundColor(ANTIQUE_WHITE.into()),
Outline::new(Val::Px(8.0), Val::ZERO, CRIMSON.into()),
));
合并 WinitEvent #
- 作者: @UkoeHB
- PR #12100
在处理输入时,接收到的事件的精确顺序通常非常重要,即使这些事件类型不同!考虑一个简单的拖放操作。用户何时确切地释放鼠标按钮,相对于他们执行的许多微小移动?正确获取这些细节对于实现响应迅速、精确的用户体验至关重要。
除了现有的独立事件流之外,我们现在还公开了覆盖所有事件的 `WinitEvent` 事件流,可以直接读取和匹配这些事件流,以便在出现这些问题时进行处理。
递归反射注册 #
- 作者: @MrGVSV, @soqb, @cart, @james7132
- PR #5781
Bevy 使用 反射 来动态处理数据,例如序列化和反序列化。Bevy 应用有一个 `TypeRegistry` 来跟踪存在的类型。用户可以在初始化应用或插件时注册自定义类型。
#[derive(Reflect)]
struct Data<T> {
value: T,
}
#[derive(Reflect)]
struct Blob {
contents: Vec<u8>,
}
app
.register_type::<Data<Blob>>()
.register_type::<Blob>()
.register_type::<Vec<u8>>()
在上面的代码中,`Data<Blob>` 依赖于 `Blob`,而 `Blob` 又依赖于 `Vec<u8>`,这意味着所有三种类型都需要手动注册,即使我们只关心 `Data<Blob>`。
这既繁琐又容易出错,尤其是在这些类型依赖项仅在其他类型上下文中使用时(即,它们不被用作独立类型)。
在 0.14 版本中,任何派生了 `Reflect` 的类型都会自动注册其所有类型依赖项。因此,当我们注册 `Data<Blob>` 时,`Blob` 也会被注册(这会注册 `Vec<u8>`),从而将我们的注册简化为一行代码
app.register_type::<Data<Blob>>()
请注意,现在删除 `Data<Blob>` 的注册也意味着 `Blob` 和 `Vec<u8>` 可能不会被注册,除非它们通过其他方式注册。如果这些类型需要用作独立类型,则应单独注册它们。
`Rot2` 2D 旋转类型 #
- 作者: @Jondolf, @IQuick143, @tguichaoua
- PR #11658
您是否曾经想要在 2D 中使用旋转,却因不得不选择四元数或原始 `f32` 而感到沮丧?我们也是!
我们为您添加了一个方便的 `Rot2` 类型,并附带了许多辅助方法。您可以随意替换您编写的辅助类型,并提交针对我们遗漏的任何有用功能的小型 PR。
`Rot2` 是 `Dir2` 类型(以前称为 `Direction2d`)的绝佳补充。前者表示一个角度,而后者是一个单位向量。这些类型相似但不可互换,表示形式的选择很大程度上取决于手头的任务。您可以使用 `direction = rotation * Dir2::X` 旋转方向。要恢复旋转,请使用 `Dir2::X::rotation_to(direction)`,在本例中,可以使用辅助方法 `Dir2::rotation_from_x(direction)`。
虽然这些类型尚未在引擎中得到广泛使用,但我们 *确实* 了解您的痛苦,并且正在评估 提案,了解如何使在 2D 中使用变换变得更加直接和愉快。
变换的对齐 API #
- 作者: @mweatherley
- PR #12187
**Bevy 0.14** 添加了一个新的 `Transform::align` 函数,它是 `Transform::look_to` 的更通用形式,它允许您指定要用于主轴和副轴的任何局部轴。
这使您能够执行诸如将飞船的前部指向您正在前进的行星,同时保持右翼指向另一艘飞船的方向,或者将飞船的顶部指向正在拉动它的牵引光束的方向,同时前部旋转以匹配较大飞船的方向等操作。
让我们考虑一艘飞船,我们将使用飞船的前部和右翼作为局部轴
// point the local negative-z axis in the global Y axis direction
// point the local x-axis in the global Z axis direction
transform.align(Vec3::NEG_Z, Vec3::Y, Vec3::X, Vec3::Z)
`align` 将移动它以尽可能地匹配所需的位置
请注意,并非所有旋转都可以构造,并且 文档 解释了在这种情况下会发生什么。
形状和方向的随机采样 #
- 作者: @13ros27, @mweatherley, @lynn-lumen
- PR #12484
在游戏开发的背景下,访问随机值通常很有用,无论是为了驱动 NPC 的行为、创建效果,还是仅仅为了创造多样性。为了支持这一点,我们在 `bevy_math` 中添加了一些随机采样功能,这些功能受 `rand` 特性控制。这些功能主要是几何性质的,它们有两种形式。
首先,可以从各种数学原语的边界和内部采样随机点:
在代码中,可以通过几种不同的方式执行此操作,使用 `sample_interior`/`sample_boundary` 或 `interior_dist`/`boundary_dist` API
use bevy::math::prelude::*;
use rand::{Rng, SeedableRng};
use rand_chacha::ChaCha8Rng;
let sphere = Sphere::new(1.5);
// Instantiate an Rng:
let rng = &mut ChaCha8Rng::seed_from_u64(7355608);
// Using these, sample a random point from the interior of this sphere:
let interior_pt: Vec3 = sphere.sample_interior(rng);
// or from the boundary:
let boundary_pt: Vec3 = sphere.sample_boundary(rng);
// Or, if we want a lot of points, we can use a Distribution instead...
// to sample 100000 random points from the interior:
let interior_pts: Vec<Vec3> = sphere.interior_dist().sample_iter(rng).take(100000).collect();
// or 100000 random points from the boundary:
let boundary_pts: Vec<Vec3> = sphere.boundary_dist().sample_iter(rng).take(100000).collect();
请注意,这些方法显式地需要一个 `Rng` 对象,让您控制随机化策略和种子。
当前支持的形状如下
2D: `Circle`、`Rectangle`、`Triangle2d`、`Annulus`、`Capsule2d`。
3D: `Sphere`、`Cuboid`、`Triangle3d`、`Tetrahedron`、`Cylinder`、`Capsule3d` 以及可采样 2D 形状的挤压(`Extrusion`)。
类似地,方向类型(`Dir2`、`Dir3`、`Dir3A`)和四元数(`Quat`)现在可以使用 `from_rng` 随机构造
use bevy::math::prelude::*;
use rand::{random, Rng, SeedableRng};
use rand_chacha::ChaCha8Rng;
// Instantiate an Rng:
let rng = &mut ChaCha8Rng::seed_from_u64(7355608);
// Get a random direction:
let direction = Dir3::from_rng(rng);
// Similar, but requires left-hand type annotations or inference:
let another_direction: Dir3 = rng.gen();
// Using `random` to grab a value using implicit thread-local rng:
let yet_another_direction: Dir3 = random();
用于分析 GPU 性能的工具 #
- 作者: @LeshaInc
- PR #9135
虽然 Tracy 已经允许我们测量每个系统的 CPU 时间,但我们的 GPU 诊断要弱得多。在 Bevy 0.14 中,我们通过 `RenderDiagnosticsPlugin` 添加了对两类渲染相关统计数据的支持
- **时间戳查询:**GPU 上特定工作部分的运行时间有多长?
- **管道统计数据:**有关发送到 GPU 的工作量的信息。
虽然时间戳查询听起来像是终极诊断工具,但它们也有一些注意事项。首先,由于 GPU 会根据工作负载(GPU 工作的空闲间隔,例如,大量连续的屏障或大型分派的尾部)或 GPU 的物理温度动态地提高和降低时钟速度,因此它们的帧间变化很大。要获得准确的测量结果,您需要查看汇总统计数据:平均值、中位数、第 75 个百分位数等。
其次,虽然时间戳查询会告诉您某项操作的运行时间,但它不会告诉您为什么速度慢。要查找瓶颈,您需要使用来自 GPU 供应商的 GPU 分析器(英伟达的 NSight、AMD 的 RGP、英特尔的 GPA 或苹果的 XCode)。这些工具会提供有关缓存命中率、线程组占用率等的更详细的统计数据。另一方面,它们会将 GPU 的时钟锁定到基本速度以获得稳定的结果,因此它们不会为您提供对实际性能的良好指示。
`RenderDiagnosticsPlugin` 跟踪以下管道统计数据,这些数据记录在 Bevy 的 `DiagnosticsStore` 中:已用 CPU 时间、已用 GPU 时间、顶点着色器 调用、片段着色器 调用、计算着色器 调用、裁剪器调用 以及 裁剪器图元。
您还可以跟踪各个渲染/计算通道、通道组(例如,所有阴影通道)以及通道中的各个命令(例如,绘制调用)。为此,请使用 `RecordDiagnostics` 特征中的方法对其进行检测。
新的几何原语 #
- 作者: @vitorfhc, @Chubercik, @andristarr, @spectria-limina, @salvadorcarvalhinho, @aristaeus, @mweatherley
- PR #12508
几何形状在游戏开发中有着广泛的应用,从渲染简单的项目到屏幕上显示/调试,再到用于碰撞器、物理、射线投射等。
为此,几何形状原语在 Bevy 0.13 中引入,并且该领域的工作一直在继续,Bevy 0.14 带来了 `Triangle3d` 和 `Tetrahedron` 3D 原语的添加,以及 `Rhombus`、`Annulus`、`Arc2d`、`CircularSegment` 以及 `CircularSector` 2D 原语。与往常一样,这些原语都有用于查询几何信息(如周长、面积和体积)的方法,并且它们都支持网格化(如果适用)以及小工具显示。
改进 `Point` 并将其重命名为 `VectorSpace` #
- 作者: @mweatherley, @bushrat011899, @JohnTheCoolingFan, @NthTensor, @IQuick143, @alice-i-cecile
- PR #12747
线性代数在游戏中无处不在,我们希望确保它易于理解。这就是我们添加新的 `VectorSpace` 特征的原因,这是我们让 `bevy_math` 更加通用、表达性强和数学上合理的一部分工作。任何实现了 `VectorSpace` 的东西都表现得像一个向量。更正式地说,该特征要求实现满足向量加法和标量乘法的向量空间公理。我们还添加了 `NormedVectorSpace` 特征,其中包含用于距离和大小的 API。
这些特性是新的曲线和形状采样 API 的基础。VectorSpace
已针对 f32
、glam
向量类型和几种新的颜色空间类型实现。它完全取代了 bevy_math::Point
。
Bevy 中的样条模块长期以来一直缺乏一些功能。样条在游戏开发中非常有用,因此改进它们将改善所有使用它们的组件。
最大的添加是 NURBS 支持!它是 B 样条的变体,具有更多可调整的参数,可以创建特定的曲线形状。我们还添加了一个 LinearSpline
,它可以用于在曲线中放置直线段。CubicCurve
现在充当曲线段的序列,你可以向其中添加新的片段,这样你就可以将各种样条类型混合在一起形成一条路径。
二维网格线框 #
- 作者:@msvbg,@IceSentry
- PR #12135
线框材质用于渲染网格的单个边和面。它们通常用作可视化几何体的调试工具,但也可以用于各种风格化效果。Bevy 支持将 3D 网格显示为线框,但直到现在才缺乏对 2D 网格执行此操作的能力。
要将你的 2D 网格渲染为线框,请将 Wireframe2dPlugin
添加到你的应用程序中,并将 Wireframe2d
组件添加到你的精灵中。可以通过添加 Wireframe2dColor
组件对每个对象配置线框的颜色,或者通过插入 Wireframe2dConfig
资源来全局配置。
有关如何使用该功能的示例,请查看新的 wireframe_2d 示例
自定义反射字段属性 #
- 作者:@MrGVSV
- PR #11659
Bevy 的反射系统的一项功能是能够将任意“类型数据”附加到类型。这最常用于允许动态调用特征方法。但是,一些用户将其视为进行其他很棒事情的机会。
惊人的 bevy-inspector-egui 有效地使用类型数据来允许用户为每个字段配置其检查器 UI
use bevy_inspector_egui::prelude::*;
use bevy_reflect::Reflect;
#[derive(Reflect, Default, InspectorOptions)]
#[reflect(InspectorOptions)]
struct Slider {
#[inspector(min = 0.0, max = 1.0)]
value: f32,
}
从这一点得到启发,Bevy 0.14 在派生 Reflect
时添加了对自定义属性的适当支持,因此用户和第三方板条箱不再需要为此目的专门创建自定义类型数据。这些属性可以使用 #[reflect(@...)]
语法附加到结构体、枚举、字段和变体,其中 ...
可以是解析为实现 Reflect
的类型的任何表达式。
例如,我们可以使用 Rust 的内置 RangeInclusive
类型为字段指定我们自己的范围
use std::ops::RangeInclusive;
use bevy_reflect::Reflect;
#[derive(Reflect, Default)]
struct Slider {
#[reflect(@RangeInclusive<f32>::new(0.0, 1.0))]
// Since this accepts any expression,
// we could have also used Rust's shorthand syntax:
// #[reflect(@0.0..=1.0_f32)]
value: f32,
}
然后可以使用 TypeInfo
动态访问属性
let TypeInfo::Struct(type_info) = Slider::type_info() else {
panic!("expected struct");
};
let field = type_info.field("value").unwrap();
let range = field.get_attribute::<RangeInclusive<f32>>().unwrap();
assert_eq!(*range, 0.0..=1.0);
此功能为构建在 Bevy 的反射系统之上的事物打开了大量可能性。通过使其独立于任何特定用法,它允许各种用例,包括将来帮助编辑器工作。
事实上,此功能已被 bevy_reactor
用于为其自定义检查器 UI 提供支持
#[derive(Resource, Debug, Reflect, Clone, Default)]
pub struct TestStruct {
pub selected: bool,
#[reflect(@ValueRange::<f32>(0.0..1.0))]
pub scale: f32,
pub color: Srgba,
pub position: Vec3,
pub unlit: Option<bool>,
#[reflect(@ValueRange::<f32>(0.0..10.0))]
pub roughness: Option<f32>,
#[reflect(@Precision(2))]
pub metalness: Option<f32>,
#[reflect(@ValueRange::<f32>(0.0..1000.0))]
pub factors: Vec<f32>,
}
查询迭代排序 #
- 作者:@Victoronz
- PR #13417
Bevy 不对项目的顺序做任何保证。因此,如果我们希望按照特定顺序处理查询项目,则需要对其进行排序!我们可能希望按顺序显示玩家的得分,或者为了网络稳定性确保一致的迭代顺序。在 0.13 中,排序可能如下所示
#[derive(Component, Copy, Clone, Deref)]
pub struct Attack(pub usize)
fn handle_enemies(enemies: Query<(&Health, &Attack, &Defense)>) {
// An allocation!
let mut enemies: Vec<_> = enemies.iter().collect();
enemies.sort_by_key(|(_, atk, ..)| *atk)
for enemy in enemies {
work_with(enemy)
}
}
当在多个系统中进行排序时,这会变得特别繁琐且重复。即使我们始终希望相同的排序,不同的 Query
类型也会使抽象成为用户不合理地困难!为了解决这个问题,我们在 QueryIter
类型上实现了新的排序方法,将示例变为
// To be used as a sort key, `Attack` now implements Ord.
#[derive(Component, Copy, Clone, Deref, PartialEq, Eq, PartialOrd, Ord)]
pub struct Attack(pub usize)
fn handle_enemies(enemies: Query<(&Health, &Attack, &Defense)>) {
// Still an allocation, but undercover.
for enemy in enemies.iter().sort::<&Attack>() {
work_with(enemy)
}
}
要使用 Attack
组件对我们的查询进行排序,我们将它指定为 sort
的泛型参数。要按多个 Component
进行排序,我们可以这样做,与原始 Query
类型中 Component
的顺序无关:enemies.iter().sort::<(&Defense, &Attack)>()
泛型参数可以被认为是原始查询的 透镜 或“子集”,实际执行底层排序。然后,结果在内部用于返回对原始查询项目进行排序的新查询迭代器。使用默认的 sort
,透镜必须完全 Ord
,就像 slice::sort
一样。如果这还不够,我们还有来自 slice
的其余 6 种排序方法的对应方法!
泛型透镜参数的工作方式与 Query::transmute_lens
相同。我们不使用过滤器,它们继承自原始查询。 transmute_lens
基础设施有一些不错的附加功能,这使得这一点成为可能
fn handle_enemies(enemies: Query<(&Health, &Attack, &Defense, &Rarity)>) {
for enemy in enemies.iter().sort_unstable::<Entity>() {
work_with(enemy)
}
}
因为我们可以将 Entity
添加到任何透镜,所以我们可以在不将其包含在原始查询中的情况下按它进行排序!
这些排序方法适用于 Query::iter
和 Query::iter_mut
!目前,Query
上的其余迭代器方法不支持排序。排序返回 QuerySortedIter
,它本身是一个迭代器,可以对它使用更进一步的迭代器适配器。
请记住,透镜会增加一些开销,因此这些查询迭代器排序的执行效率不如手动排序。但是,这强烈依赖于工作负载,因此如果相关,请自行测试!
SystemBuilder #
- 作者:@james-j-obrien
- PR #13123
Bevy 用户喜欢系统,因此我们为他们的系统创建了一个构建器,这样他们就可以从系统内部构建系统。在运行时,使用动态定义的组件和资源类型!
虽然你可以使用 SystemBuilder
作为 SystemState
API 的一个符合人体工程学的选择,将 World
分割成不相交的借用,但它的真正价值在于其动态使用。
你可以选择根据运行时分支创建不同的系统,或者更有趣的是,查询等可以使用运行时定义的组件 ID。这是朝着创建用于处理 动态查询 的符合人体工程学和安全的 API 迈出的又一步,为想要集成脚本语言或为其游戏烘焙复杂修改支持的开发人员奠定了基础。
// Start by creating builder from the world
let system = SystemBuilder::<()>::new(&mut world)
// Various helper methods exist to add `SystemParam`.
.resource::<R>()
.query::<&A>()
// Alternatively use `.param::<T>()` for any other `SystemParam` types.
.param::<MyParam>()
// Finish it all up with a call `.build`
.build(my_system);
// The parameters the builder is initialized with will appear first in the arguments.
let system = SystemBuilder::<(Res<R>, Query<&A>)>::new(&mut world)
.param::<MyParam>()
.build(my_system);
// Parameters like `Query` that implement `BuildableSystemParam` can use
// `.builder::<T>()` to build in place.
let system = SystemBuilder::<()>::new(&mut world)
.resource::<R>()
// This turns our query into a `Query<&A, With<B>>`
.builder::<Query<&A>>(|builder| { builder.with::<B>(); })
.param::<MyParam>()
.build(my_system);
world.run_system_once(system);
限制渲染资产 #
- 作者:@robtfm,@IceSentry,@mockersf
- PR #12622
使用大量资产?在短时间内将大量字节上传到 GPU 可能会导致卡顿,因为渲染世界正在等待上传完成。
通常,如果应用程序运行流畅,而不是卡顿,体验会更令人愉快,并且在看到资产出现之前延迟几帧通常甚至不会被察觉。
这种体验现在已成为可能
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.insert_resource(RenderAssetBytesPerFrame::new(1_000_000_000)) // Tune to your situation by experimenting!
.run();
}
就是这样!提供的数字应通过找出无卡顿和可接受延迟之间良好的权衡来选择。
此功能依赖于资产知道在发送到 GPU 时将占用多少字节。目前,图像和网格知道这一点,预计将来会有更多资产类型能够报告这一点。
StandardMaterial UV 通道选择 #
- 作者:@geckoxx
- PR #13200
以前,StandardMaterial 始终默认为对除光照贴图之外的每个纹理使用 ATTRIBUTE_UV_0,这对于许多 gltf 文件来说不够灵活。在Bevy 0.14 中,添加了一个新的 UvChannel 枚举,允许你选择在 StandardMaterial 中用于每个纹理的通道。
以下是展示对所有纹理跨越 ATTRIBUTE_UV_1 的支持的之前和之后的示例
删除对 RenderLayers 的限制 #
- 作者:@tychedelia,@robtfm,@UkoeHB
- PR #13317
渲染层用于快速切换对象集的可见性,并控制哪些对象可以被哪些摄像机看到。这对于调试视图、装备预览屏幕、可切换的叙事 UI 等非常有用。
在 Bevy 0.14 之前,成员身份由一个位掩码定义,该位掩码的可用插槽有限。现在,你定义的层数不再有任何实际限制,这对于像 nannou 这样的创意编码应用程序特别有用!我们确保将常见情况保持快速,但现在使用可增长的掩码,该掩码将在需要时为其他层分配空间。请记住,每层检查可见性仍然会产生成本,但这允许更动态的用途,其中可以根据需要创建层,而不必担心超出限制。
on_unimplemented
诊断 #
- 作者:@bushrat011899,@alice-i-cecile,@Themayu
- PR #13347
Bevy 充分利用了 Rust 提供的强大类型系统,但这种强大的功能通常会带来困惑,即使是微小的错误也会导致混乱。
use bevy::prelude::*;
struct MyResource;
fn main() {
App::new()
.insert_resource(MyResource)
.run();
}
运行以上代码将产生编译器错误,让我们看看为什么...
单击以展开...
error[E0277]: the trait bound `MyResource: Resource` is not satisfied
--> example.rs:6:32
|
6 | App::new().insert_resource(MyResource).run();
| --------------- ^^^^^^^^^^ the trait `Resource` is not implemented for `MyResource`
| |
| required by a bound introduced by this call
|
= help: the following other types implement trait `Resource`:
AccessibilityRequested
ManageAccessibilityUpdates
bevy::a11y::Focus
DiagnosticsStore
FrameCount
bevy::prelude::Axis<T>
WinitActionHandlers
ButtonInput<T>
and 127 others
note: required by a bound in `bevy::prelude::App::insert_resource`
--> /bevy/crates/bevy_app/src/app.rs:537:31
|
537 | pub fn insert_resource<R: Resource>(&mut self, resource: R) -> &mut Self {
| ^^^^^^^^ required by this bound in `App::insert_resource`
编译器建议我们使用实现 Resource
的不同类型,或者在 MyResource
上实现该特征。前者对我们毫无帮助,而后者没有提及可用的派生宏。
随着 Rust 1.78 的发布,Bevy 现在可以使用 诊断属性 为编译期间的某些类型的错误提供更直接的消息。
error[E0277]: `MyResource` is not a `Resource`
--> example.rs:6:32
|
6 | App::new().insert_resource(MyResource).run();
| --------------- ^^^^^^^^^^ invalid `Resource`
| |
| required by a bound introduced by this call
|
= help: the trait `Resource` is not implemented for `MyResource`
= note: consider annotating `MyResource` with `#[derive(Resource)]`
= help: the following other types implement trait `Resource`:
AccessibilityRequested
...
现在,错误消息有一个更易于理解的入口点,以及一个新的 note
部分,指向资源的派生宏。如果 Bevy 的建议不是你问题的解决方案,则其余的编译器错误仍将包含在内,以防万一。
这些诊断已在 Bevy 的各个特征中实现,我们希望随着 Rust 中添加新功能来改善这种体验。例如,我们真的很想改善使用 Component
元组的体验,但我们还没有做到。你可以在 pull request 和相关的 issue 中了解更多关于此更改的信息。
动画网格的运动向量和 TAA #
- 作者:@pcwalton
- PR #13572
早在**Bevy 0.11**中,我们添加了时间抗锯齿 (TAA),它使用运动向量来判断物体移动的速度。然而,在**Bevy 0.11**中,我们只添加了对“静态”网格的运动向量支持,这意味着 TAA 无法用于使用骨骼动画或变形目标的动画网格。
在**Bevy 0.14**中,我们实现了逐物体运动模糊,它也使用运动向量,因此也存在同样的限制。
幸运的是,在**Bevy 0.14**中,我们为带骨骼蒙皮的网格和带变形目标的网格实现了运动向量,弥补了这一差距,并使 TAA、逐物体运动模糊以及未来基于运动向量的功能能够应用于动画网格。
改进矩阵命名 #
- 作者:@ricky26
- PR #13489
游戏引擎通常提供一组矩阵来执行游戏世界中的空间变换。通常,使用以下空间
- 标准化设备坐标:由图形 API 直接使用
- 裁剪空间:投影后但在透视除法之前进行的坐标
- 视点空间:相机视点中的坐标
- 世界空间:全局坐标(这是我们最常谈论的!)
- 模型空间:(或局部空间)相对于实体的坐标
一个常见的例子是“模型视图投影矩阵”,它是从模型空间到 NDC 空间的变换(奇怪的是,在这个简写中,视图矩阵通常是从世界到视点空间的变换,但模型矩阵是从模型(或局部)空间到世界空间的变换)。通常,矩阵被称为该简写的一部分,例如,投影矩阵将视图坐标转换为 NDC 坐标。
Bevy 在一些地方有一个视图矩阵,它是从视点到世界空间的变换(而不是从世界到视点空间的变换,如上所示)。此外,即使在一致使用的情况下,单个单词简写也是模棱两可的,可能会造成混淆。我们认为需要一个更清晰的约定。
从现在开始,Bevy 中的矩阵命名为 y_from_x
,例如 world_from_local
,它表示从局部空间到世界空间坐标的变换。这样做的一个好处是,逆矩阵命名为 x_from_y
,当在空间之间进行乘法时,很容易看出它是正确的。
例如,您不再写
let model_view_projection = projection * view * model;
您现在应该写
let clip_from_local = clip_from_view * view_from_world * world_from_local;
类型化的 glTF 标签 #
- 作者:@mockersf、@rparrett、@alice-i-cecile
- PR #13586
如果您一直在使用glTF
文件作为您的场景,或者查看过使用 glTF
文件的示例,您可能会在资产路径的末尾看到标签
let model_pine = asset_server.load("models/trees/pine.gltf#Scene0");
let model_hen = asset_server.load("models/animals/hen.gltf#Scene0");
let animation_hen = asset_server.load("models/animals/hen.gltf#Aniamtion1"); // Oh no!
请注意末尾的 #Scene0
语法。glTF 格式能够在一个文件中包含许多东西,包括多个场景、动画、灯光等等。
这些标签是告诉 Bevy 我们要加载文件的哪个部分的方法。
然而,这很容易导致用户错误,并且看起来确实出现了错误!母鸡动画的标签为 Aniamtion1
而不是 Animation1
。
现在不用担心了!上面代码可以改写如下
let hen = "models/animals/hen.gltf"; // Can re-use this more easily too
let model_pine = asset_server.load(GltfAssetLabel::Scene(0).from_asset("models/trees/pine.gltf"));
let model_hen = asset_server.load(GltfAssetLabel::Scene(0).from_asset(hen));
let animation_hen = asset_server.load(GltfAssetLabel::Animation(0).from_asset(hen)); // No typo!
查看glTF 标签文档
,了解您可以查询哪些部分。
winit v0.30 #
- 作者:@pietrosophya、@mockersf
- PR #13366
Winit v0.30 改变了它的 API,以支持基于特性的架构,而不是简单的基于事件的架构。Bevy 0.14 现在实现了这个新的架构,使事件循环处理更容易理解。
现在可以定义一个自定义 winit
用户事件,该事件可以用于触发 App 更新,并且可以在系统内部读取以触发特定行为。这对于从 winit
事件循环之外发送事件并在 Bevy 系统内部管理它们特别有用(请参阅window/custom_user_event.rs
示例)。
UpdateMode
枚举现在只接受两个值:Continuous
和 Reactive
。后者公开了 3 个新属性,以支持对设备、用户或窗口事件的响应。之前的 UpdateMode::Reactive
现在等效于 UpdateMode::reactive()
,而 UpdateMode::ReactiveLowPower
映射到 UpdateMode::reactive_low_power()
。
Idle
:循环尚未开始Running
(以前称为Started
):循环正在运行WillSuspend
:循环即将暂停Suspended
:循环已暂停WillResume
:循环即将恢复
注意:Resumed
状态已被删除,因为恢复的应用程序只是 Running
。
场景、网格和材质 glTF 扩展 #
- 作者:@kaosat-dev
- PR #13453
glTF 3D 模型文件格式允许在extras 属性中传递其他用户定义的元数据,除了基元/节点级别的 glTF 扩展外,Bevy 现在还为以下内容提供了特定的 GltfExtras:
- 场景:SceneGltfExtras,如果存在,则在场景级别注入
- 网格:MeshGltfExtras,如果存在,则在网格级别注入
- 材质:MaterialGltfExtras,如果存在,则在网格级别注入:即如果网格有一个具有 glTF 扩展的材质,则该组件将被注入到那里。
您现在可以轻松地查询这些特定的扩展
fn check_for_gltf_extras(
gltf_extras_per_entity: Query<(
Entity,
Option<&Name>,
Option<&GltfSceneExtras>,
Option<&GltfExtras>,
Option<&GltfMeshExtras>,
Option<&GltfMaterialExtras>,
)>,
) {
// use the extras' data
for (id, name, scene_extras, extras, mesh_extras, material_extras) in
gltf_extras_per_entity.iter()
{
}
}
这使得通过 glTF 文件从 Blender 等程序传递信息到 Bevy 更加符合规范,也更加实用!
场景中的资源实体映射 #
- 作者:@brandon-reinhart
- PR #13650
Bevy 的 DynamicScene
是一个资源和实体的集合,可以序列化以创建预制件或存档游戏数据之类的集合。当一个 DynamicScene 被反序列化并写入一个 World 中时(例如,当加载存档游戏时),场景内的动态实体标识符必须映射到它们新生成的对应物。
以前,这种映射只对存储在组件上的实体标识符可用。在 Bevy 0.14 中,资源可以反映 MapEntitiesResource
并实现 MapEntities
特性以访问 EntityMapper
。
// This resource reflects MapEntitiesResource and implements the MapEntities trait.
#[derive(Resource, Reflect, Debug)]
#[reflect(Resource, MapEntitiesResource)]
struct TestResource {
entity_a: Entity,
entity_b: Entity,
}
// A simple and common use is a straight mapping of the old entity to the new.
impl MapEntities for TestResource {
fn map_entities<M: EntityMapper>(&mut self, entity_mapper: &mut M) {
self.entity_a = entity_mapper.map_entity(self.entity_a);
self.entity_b = entity_mapper.map_entity(self.entity_b);
}
}
指南针象限和指南针八分圆 #
- 作者:@BobG1983、@alice-i-cecile
- PR #13653
在游戏开发中,有很多情况下需要知道给定方向的指南针方位。这在使用四方向或八方向精灵的 2D 游戏中尤其重要,或者想要将模拟输入映射到离散的移动方向。
为了使这更容易,枚举 CompassQuadrant
(用于四方向划分)和 CompassOctant
(用于八方向划分)已被添加,并实现了 From<Dir2>
,方便使用。
加载资产时支持 AsyncSeek
#
- 作者:@BeastLe9enD
- PR #12547
资产可能很大,而且您并不总是需要单个文件中包含的所有数据。
Bevy 允许您添加您自己的资产加载器。从 Bevy 0.14 开始,您现在可以寻址到您选择的偏移量,读取文件的一部分。
也许您有 .celestial
文件格式,它对宇宙进行编码,但您只想查看始终出现在某个偏移量的微型小行星
#[derive(Default)]
struct UniverseLoader;
#[derive(Asset, TypePath, Debug)]
struct JustALilAsteroid([u8; 128]); // Each lil' asteroid uses this much data
impl AssetLoader for UniverseLoader {
type Asset = JustALilAsteroid;
type Settings = ();
type Error = std::io::Error;
async fn load<'a>(
&'a self,
reader: &'a mut Reader<'_>,
_settings: &'a (),
_load_context: &'a mut LoadContext<'_>,
) -> Result<JustALilAsteroid, Self::Error> {
// The universe is big, and our lil' asteroids don't appear until this offset
// in the celestial file format!
let offset_of_lil_asteroids = 5_000_000_000_000;
// Skip vast parts of the universe with the new async seek trait!
reader
.seek(SeekFrom::Start(offset_of_lil_asteroids))
.await?;
let mut asteroid_buf = [0; 128];
reader.read_exact(&mut asteroid_buf).await?;
Ok(JustALilAsteroid(asteroid_buf))
}
fn extensions(&self) -> &[&str] {
&["celestial"]
}
}
这是可行的,因为 Bevy 的reader
类型(传递给资产加载器的 load
函数)现在实现了AsyncSeek
。
现实世界中的用例可能是:
- 您在一个档案中打包了多个资产,并且您希望跳到其中一个资产并读取它
- 您正在处理大型数据集,例如地图数据,并且您知道在哪里提取某些感兴趣的位置
LoadState::Failed 现在包含错误信息 #
- 作者:@bugsweeper
- PR #12709
Rust 以其错误处理而自豪,Bevy 也一直在稳步赶上。以前,当使用AssetServer::get_load_state
检查资产是否已加载时,如果出现错误,您只会得到一个无数据的LoadState::Failed
。这对于调试来说并不十分有用!
现在,将包含一个完整的AssetLoadError
,它具有 14 个不同的变体,可以准确地告诉您哪里出错了。这对于故障排除非常有用,它为更复杂的应用程序中进行适当的错误处理打开了大门。
AppExit
错误 #
- 作者:@Brezak、@alice-i-cecile
- PR #13022
在运行应用程序时,可能会有许多原因触发退出。可能是用户按下了退出按钮,或者渲染线程遇到了错误并崩溃了。您可能希望区分这两种情况,并从您的应用程序返回一个适当的退出代码。
在**Bevy 0.14**中,您可以这样做。AppExit
事件现在是一个具有两个变体的枚举:Success
和 Error
。错误变体还包含一个非零代码,您可以随意使用它。由于 AppExit
事件现在包含有用的信息,因此应用程序运行器和 App::run
现在将返回导致应用程序退出的事件。
对于插件开发人员,App
已经获得了一个新方法 App::should_exit
,它将检查在最近两次更新中是否发送了任何 AppExit
事件。为了确保 AppExit::Success
事件不会掩盖有用的错误信息,即使 AppExit::Success
之后发送了 AppExit::Error
事件,该方法也会返回任何 AppExit::Error
事件。
最后,AppExit
也实现了Termination
特性,因此它可以从 main 返回。
use bevy::prelude::*;
fn exit_with_a_error_code(mut events: EventWriter<AppExit>) {
events.send(AppExit::from_code(42));
}
fn main() -> AppExit {
App::new()
.add_plugins(MinimalPlugins)
.add_systems(Update, exit_with_a_error_code)
.run() // There's no semicolon here, `run()` returns `AppExit`.
}
将动态链接在 WASM 目标上设为无操作 #
- 作者:@james7132
- PR #12672
WASM 不支持在运行时链接的动态库。以前,如果您启用了 dynamic_linking
功能,Bevy 将无法编译。
$ cargo build --target wasm32-unknown-unknown --features bevy/dynamic_linking
error: cannot produce dylib for `bevy_dylib v0.13.2` as the target `wasm32-unknown-unknown` does not support these crate types
现在,Bevy 将为所有 WASM 目标回退到静态链接。如果您为开发启用了 dynamic_linking
,则不再需要为 WASM 禁用它。
弃用动态插件 #
- 作者:@BD103
- PR #13080
bevy_dynamic_plugin
是 Bevy 最初的 0.1 版本中添加的一个工具:旨在作为一种工具,用于动态加载/链接 Rust 代码,用于诸如 modding 之类的事情。不幸的是,这个功能没有得到社区的广泛采用,因此多年来几乎没有贡献来改进和记录它。
再加上一个具有挑战性且本质上不安全的 API,导致用户遇到了令人担忧的故障,因此我们决定弃用 bevy_dynamic_plugin
,并将在 Bevy 0.15 中将其完全移除。如果您是这个功能的忠实用户,只需将这个相当小的板条箱复制到您自己的项目中,然后像以前一样继续使用。
我们仍然认为 modding 和热重载代码以加快开发时间是 Bevy 应该支持的宝贵用例。我们希望通过将其作为一级板条箱移除,我们可以刺激第三方尝试,并避免用户浪费时间来调查一个复杂的潜在解决方案,然后得出它还无法满足他们的需求的结论。
Bevy 工作组 #
- 作者:@alice-i-cecile
- PR #13162
Bevy 有很多才华横溢的贡献者,因此跟踪正在发生的事情并做出明智的决定可能是一个真正的挑战。我们正在尝试工作组:临时小组通过创建设计文档、获得专家的认可,然后进行实现来解决更难的问题。如果您想帮助对 Bevy 进行复杂、高影响力的更改:加入或组建一个工作组!
下一步是什么? #
以上功能可能很棒,但 Bevy 还有哪些正在进行中的功能呢?深入时间迷雾(当你的团队几乎都是志愿者时,预测非常困难!),我们可以看到一些激动人心的工作正在形成
- 更好的场景:场景是 Bevy 的核心构建块之一:旨在成为创建关卡和创建可重用游戏对象的强大工具,无论它们是单选按钮小部件还是怪物。我们正在开发一个新的场景系统,它使用新的语法,这将使在资产中和在代码中定义场景更强大、更令人愉悦。你可以查看(现在有点旧的)项目启动讨论以了解更多信息。我们也即将发布一份设计文档,概述我们的计划和当前实施状态。
- ECS 关系:关系(将实体链接在一起的一流功能)是人们强烈需要的,但它却非常复杂,推动了我们 ECS 内部机制的功能和重构。该工作组一直在耐心规划我们需要做的事情以及原因,如该RFC中所述。
- 更好的音频:Bevy 的内置音频解决方案从未真正达到预期效果。该更好的音频工作组正在规划前进的道路。
- 贡献手册:我们关于如何贡献的文档散布在我们的存储库的各个角落。通过将这些文档收集在一起,该贡献手册工作组希望让发现和维护变得更容易。
- 曲线抽象:曲线在游戏开发中经常出现,组成该曲线组的数学大师正在设计一个特质来统一和增强它们。
- 更好的文本:我们现有的文本解决方案无法满足现代 UI 的需求。“Lorem Ipsum”工作组正在研究用更好的解决方案替换它。
- 关于开发工具的统一视图:在 0.14 中,我们添加了一个存根
bevy_dev_tools
crate:一个用于工具和叠加层的地方,可以加速游戏开发,例如性能监控器、飞行相机或用于生成游戏对象的 ingame 命令。我们正在努力添加更多工具,并创建一个开发工具抽象。这将为我们提供一种统一的方式来启用/禁用、自定义和将这组工具分组到工具箱中,从而创建类似于 Quake 控制台或 VSCode 命令面板的东西,其中包含来自生态系统各处的工具。 - Bevy 远程协议:与正在运行的 Bevy 游戏通信对于构建编辑器、调试器和其他工具来说是一个非常强大的工具。我们正在开发一个基于反射的协议来创建一个能够为整个生态系统提供动力的解决方案。
- 一个模块化、可维护的渲染图:Bevy 的现有渲染架构在提供可重用渲染器功能方面已经相当不错,例如
RenderPhases
、批处理和绘制命令。但是,渲染图接口本身仍然是一个痛点。由于它分布在许多文件中,因此控制流很难理解,而且它大量使用 ECS 资源来传递渲染数据,这实际上不利于模块化。虽然确切的设计尚未最终确定(并且非常欢迎反馈!),但我们一直在积极努力重新设计渲染图,以便朝着模块化和易用性对渲染器进行更大规模的重构。
支持 Bevy #
Bevy 将永远是免费的开源软件,但它的制作并非免费!由于 Bevy 是免费的,我们依赖 Bevy 社区的慷慨捐助来资助我们的工作。如果您是 Bevy 的快乐用户,或者您相信我们的使命,请考虑向 Bevy 基金会捐款... 每一点帮助都至关重要!
贡献者 #
衷心感谢 256 位贡献者,他们使这次发布(以及相关的文档)成为可能!以随机顺序
- @miroim
- @vitorfhc
- @13ros27
- @andristarr
- @mrtolkien
- @atlv24
- @MrGVSV
- @SludgePhD
- @Wuketuke
- @AndrewDanial
- @thebluefish
- @waywardmonkeys
- @VictorBulba
- @Earthmark
- @GitGhillie
- @andriyDev
- @shanecelis
- @mintlu8
- @bushrat011899
- @TheCarton
- @RobWalt
- @NoahShomette
- @jake8655
- @sam-kirby
- @Olle-Lukowski
- @R081n
- @adithramachandran
- @msvbg
- @freiksenet
- @IQuick143
- @AldanTanneo
- @ricky26
- @torsteingrindvik
- @Chubercik
- @Themayu
- @umut-sahin
- @hut
- @JMS55
- @hi-names-nat
- @BobG1983
- @gagnus
- Fpgu
- @dependabot[bot]
- @Hexorg
- @A-Walrus
- @killercup
- @rparrett
- @Zeenobit
- @Bluefinger
- @Brezak
- @nicoburns
- @lee-orr
- ebola
- @JoshuaSchlichting
- @mrchantey
- @Aceeri
- @ramirezmike
- @mgi388
- @LuisFigueiredo73
- @benpinno
- @james-j-obrien
- @oli-obk
- @tguichaoua
- @SolarLiner
- @s-puig
- @dmlary
- @brandon-reinhart
- @ekropotin
- @Victoronz
- @janhohenheim
- @Xzihnago
- @infmagic2047
- @spooky-th-ghost
- @greytdepression
- @philpax
- @pablo-lua
- @rmsthebest
- @mockersf
- @UkoeHB
- @eira-fransham
- @chompaa
- @ghost
- @pkupper
- @porkbrain
- @tychedelia
- @Kanabenki
- @MScottMcBee
- @gabrielkryss
- @EmiOnGit
- @kristoff3r
- @imrn99
- @moonlightaria
- @geekvest
- @sampettersson
- @JoJoJet
- @JeanMertz
- @arcashka
- @Testare
- @Davier
- @SkiFire13
- @ArthurBrussee
- @IceSentry
- @zuiyu1998
- @snendev
- @MiniaczQ
- @soqb
- Alice Cecile
- @Gingeh
- @Weibye
- @viridia
- @MarcoMeijer
- @lambertsbennett
- @doonv
- @DGriffin91
- @BD103
- @forgemo
- @StephenTurley
- @kaosat-dev
- @mnmaita
- @Maximetinu
- @eidloi
- @yrns
- @daxpedda
- @Kurble
- @findmyhappy
- @inodentry
- @TimJentzsch
- @alice-i-cecile
- @eero-lehtinen
- @OneFourth
- @pcwalton
- @MonaMayrhofer
- @jgayfer
- @blukai
- @vertesians
- @geckoxx
- @james7132
- @theredfish
- @nzhao95
- @StrikeForceZero
- @spectria-limina
- @ChristopherBiscardi
- @gavlig
- @Multirious
- @mweatherley
- @TheNullicorn
- @lukaschod
- @salvadorcarvalhinho
- @ua-kxie
- @stinkytoe
- @Aztro-dev
- @bcolloran
- @awwsmm
- @TheRawMeatball
- @tomara-x
- @orzogc
- @matiqo15
- @TimLeach635
- @uwuPyxl
- @Soulghost
- @benfrankel
- @kornelski
- @paolobarbolini
- @notmd
- @mamekoro
- Franklin
- @simbleau
- @NixyJuppie
- @coolreader18
- @feyokorenhof
- @eerii
- @AmionSky
- @jkb0o
- @Shatur
- @stowmyy
- @chescock
- @hymm
- @ShadowMitia
- @pietrosophya
- @jnhyatt
- @Jondolf
- @jdm
- @TrialDragon
- @Remi-Godin
- @Friz64
- @dmyyy
- @rib
- @juliohq
- @stepancheg
- @nbielans
- @komadori
- @djeedai
- @ManevilleF
- @mghildiy
- @BeastLe9enD
- @JohnTheCoolingFan
- @kettle11
- @emilyselwood
- @cBournhonesque
- @aristaeus
- @chrisjuchem
- @allsey87
- @nicopap
- @tjamaan
- @gibletfeets
- @floppyhammer
- @honungsburk
- @CatThingy
- @jakobhellermann
- @aevyrie
- @jirisvd
- @CptPotato
- @NiklasEi
- @lynn-lumen
- @AxiomaticSemantics
- @Azorlogh
- @zeux
- @agiletelescope
- @Elabajaba
- @RobinKellnerVector
- @iiYese
- @ycysdf
- @Waridley
- @coreh
- @yyogo
- @targrub
- @marcelchampagne
- @tygyh
- @unknownue
- @TheNeikos
- @Vrixyz
- @MTFT-Games
- @SpecificProtagonist
- @Zoomulator
- @afonsolage
- @NthTensor
- @cart
- @maboesanman
- @IWonderWhatThisAPIDoes
- @re0312
- @66OJ66
- @theon
- @robtfm
- @NiseVoid
- Lukas Chodosevicius
- @superdump
- @oyasumi731
- @ameknite
- @franklinblanco
- @bugsweeper
- @Zeophlite
- @xStrom
- @ItsDoot
- @LeshaInc
- @maniwani
- @ickshonpe
完整变更日志 #
上面提到的更改只是我们在这个周期中所做的最吸引人、影响最大的更改。无数的错误修复、文档更改和 API 易用性调整也已加入。有关更改的完整列表,请查看下面列出的 PR。
辅助功能 + 渲染 #
辅助功能 + 窗口 #
动画 #
重新设计动画,以便在两个阶段完成。
修复四元数插值的文档
实现
AnimationGraph
,允许将多个动画混合在一起。修复 find_current_keyframe 崩溃
公开可变的动画剪辑
新示例:响应事件的精灵动画
使新动画播放器的组件类型可克隆。
为
AnimationTransitions
添加了get_main_animation
动画 + 资产 #
动画 + 颜色 + 数学 + 渲染 #
动画 + 颜色 + 渲染 #
动画 + 渲染 #
App #
重构 App 和 SubApp 内部机制以实现更好的分离
向 PluginGroupBuilder 添加了 add_group
将 PanicHandlerPlugin 移动到 bevy_app
使
AppExit
更具体地说明退出原因。简化运行器应用程序退出代码。
更新
App:is_plugin_added
以在Plugin::finish
和Plugin::clean
中起作用修复
custom_loop
示例以包含插件最终化弃用动态插件
修复 bevy_app 在没有默认功能的情况下无法编译
在默认应用程序运行器中转发退出代码
让 init_non_send_resource 需要 FromWorld 而不是 Default
将缺失的插件添加到 DefaultPlugins 的文档中
修复 is_plugin_added::<Self>() 在构建期间为真
App + ECS #
将状态安装方法从
bevy_app
移动到bevy_state
确保即使使用最基本的 Bevy App 也会更新事件(#13808)
将
StateTransitionSteps
注册移动到状态插件
资产 #
用 $crate: 限定 embedded_asset 扩展:
修复 embedded_asset 宏的示例文档
解析缺失的 MIME 类型
使用完整路径创建 imported_assets 目录
改进文件监视器错误消息
添加一种从 AssetId 获取强句柄的方法
在文件监视器中规范化根路径
删除 UpdateAssets 和 AssetEvents 调度程序
向
AssetIndex
添加 to_bits 和 from_bits 函数添加从 World 直接加载资产的方法
添加关于在 WASM 中从 RAM 中卸载资产的说明
添加 extra_asset_source 示例
在 extra_asset_source 示例中使用
.register_asset_source()
将 AssetEvents 移动到最后
修复 AssetActionMinimal 的文档注释
当资产实际未被使用时,发送 Unused 事件
在 traits 中使用 async-fn 而不是 BoxedFuture
使
AssetAction::Ignore
不将资产复制到imported_assets
向 ProcessContext 添加路径函数
删除 Handle<T> 的 Into<AssedId<T>>,如 #12600 中所述
修复 get_asset_paths 没有正确删除空文件夹(& 递归异步函数)
修复 Web Workers 中获取资产
允许将可变句柄借用转换为 AssetId。
向
Reader
添加AsyncSeek
trait 以便能够在资产加载器中进行查找在确定扩展名时忽略 AssetPaths 中的查询参数
错误信息已添加到 LoadState::Failed
添加使用 .meta 文件的示例
修复文档中的复制粘贴错误
修复无扩展名图像加载 panic
修复 asset_settings 示例中注释中的未完成句子
将
AssetMetaCheck
设为资产插件上的一个字段bevy_asset: 添加缺失的 web-sys 功能并清理未使用的功能
其他资产代码质量和文档
使用
load_with_settings
而不是在示例中手动覆盖 srgbness添加更多 load_direct 实现
使 LoadContext 使用构建器模式来加载依赖资产
允许
AssetServer::load
获取一个 guard 项目。添加关于加载 Gltf 资产部分的 bevy_gltf 文档
glTF 标签:添加枚举以避免拼写错误并保持最新列表的文档
改进 AssetServer::load 文档以帮助找到从带有哈希的文件名中加载文件的方法
避免加载带标签的资产时出现 panic
向 Gltf Node 和 Mesh 资产添加标签
允许加载具有自定义异步行为的资产
当遇到文件监视器故障时提供更多信息。
改进
AssetServer::add_async
的错误处理
Assets + Diagnostics #
Assets + ECS #
Assets + Reflection #
Assets + Rendering #
将 PointLightBundle 恢复为 DirectionalLightBundle,该更改是在 0.12.1 和 0.13.0 之间对 asset_loading 示例进行的
Gltf 加载器现在显示哪个文件缺少预烘焙切线
修复
ImageLoader
未使用webp
或pnm
功能初始化允许在加载期间为 gLTF 网格和材质设置 RenderAssetUsages
修复了一个错误,该错误会导致 wgpu 从 skybox ddsfile 中崩溃
创建加载屏幕示例
将 Render(Ui)Materials(2d) 合并到 RenderAssets 中
为 Mesh2dHandle 添加了 deref trait
修复 gltf 的法线计算
向图像加载器添加 ImageFormatSetting::Guess
卸载 RenderAssetUsages::RENDER_WORLD 的未使用的图像
添加所有缺失的 gltf 额外内容的处理:场景、网格和材质
提高 MeshletMesh::from_mesh 性能
进一步提高 MeshletMesh::from_mesh 的性能
音频 #
不要直接依赖 oboe
bevy_audio
的贡献指南修复音频实体销毁时对子项的剩余引用
更新了 audio_source.rs 的文档
编程配乐示例
添加了关于向示例加载额外音频格式的说明
更新到
rodio
0.18
构建系统 #
为缺少它的工作空间成员添加
[lints]
条目修复 taplo CI - toml fmt
在 CI 期间检查
cfg
并修复功能拼写错误添加
typos
- 源代码拼写检查器CI:在新 macOS 运行器上运行长时间任务
向自动化的 CI 检查添加取消进行中的支持
更新 cargo deny
在 ci 中显式运行
+nightly
用于-Zcheck-cfg
传递。修复 typos 和 check-cfg 的失败
本地运行 CI 的质量生活更新
修复对 raw-window-handle 的重复依赖
修复 ci 中的最小插件
CI 测试:如果屏幕截图管理器资源不可用,则不要崩溃
修复 CI 桌面模式补丁
更改灯光展示补丁的文件位置
使用带种子的随机数使对齐确定性
使用带种子的随机数使 alien_cake_addict 确定性
检查补丁是否未损坏
使用带种子的随机数使示例 font_atlas_debug 确定性
修复 Ci 由于测试中的死代码而失败
删除冗余的 doc_auto_config
向 bevy_utils_proc_macros 添加 repository 字段
修复每周 ci 中的错误依赖
修复每周 ci 运行中字符串未插值
小型 CI 工具改进
工具:重构 CI 以使用
argh
为安装 Linux 依赖项创建自定义操作
当示例未设置 doc-scrape-examples 时失败
删除未使用的 nightly 工具链环境变量
将 crate-ci/typos 从 1.20.8 提升到 1.20.9
改进示例展示补丁 CI 工作流程的输出
小型 CI 改进
安装 arm ios 模拟器的 rust 目标
在 wasm 目标上使 dynamic_linking 为无操作
重构
ci
模块将 crate-ci/typos 从 1.20.9 提升到 1.20.10
对
ci
工具的少量更改工具的示例设置
ci 配置文件的格式
更新编译测试以使用 ui_test 0.23
将 crate-ci/typos 从 1.20.10 提升到 1.21.0
在分叉上工作时不要部署文档
修复
asset-source-website.patch
行号更新发布工作流程 pr 正文
添加
cargo ci
别名为ci
工具重构
ci_testing
并将其与DevToolsPlugin
分开重新生成光集群补丁文件
着色器代码路径
示例展示:保持导入的着色器的顺序
构建系统 + 交叉切面 #
构建系统 + 开发工具 #
构建系统 + ECS + 反射 #
构建系统 + 元数据 #
构建系统 + 渲染 #
颜色 #
对 oklab/oklch 文档进行一些小的修改
解决一些 oklaba 不一致问题
为
Srgba
实现数学运算和Animatable
将 wgsl 颜色运算从 bevy_pbr 移动到 bevy_render
添加颜色转换 #13224
删除
ClampColor
为
Color
实现颜色运算添加了 Grey trait 以及烘焙颜色上的实现。修复 #13206
将转换颜色为 u8 数组的方式添加回来,在两种 RGB 颜色类型上实现,并将 Color::linear 重命名为 Color::to_linear。
颜色 + Gizmos #
颜色 + Gizmos + 渲染 + 文本 + UI #
颜色 + 渲染 #
bevy_color: 添加 'palettes' 模块。
bevy_color
: 创建了一个私有 traitStandardColor
bevy_color
: 添加了Xyza
颜色空间简化了
bevy_color
Srgba
十六进制字符串解析使
bevy_color
成为bevy_render
的依赖项将
bevy_core_pipeline
移植到LinearRgba
bevy_color
: 添加了Hsva
和Hwba
模型bevy_color
: 添加Laba
以支持 Lab 颜色模型bevy_color
: 添加了颜色转换美人鱼图为 bevy_color 定义一个 prelude,并将其添加到 bevy_internal
bevy_color::Color
方便方法bevy_color
: 添加 Oklch 颜色空间通过
css
颜色调色板重新导出basic
颜色调色板bevy_color
: 向Hsla
、Lcha
、Oklcha
添加sequence_dispersed
在
bevy_color
中反映颜色空间中的默认值bevy_color: 添加 Tailwind 调色板
修复
Oklab
和Oklch
颜色空间的不一致问题添加色调特征
Emissive 现在是 StandardMaterial 上的 LinearRgba
修复切换到 LinearRgba 后 StandardMaterial 中的发射值
颜色 + 渲染 + UI #
核心 #
交叉切面 #
为 Bevy 的所有发布的板条箱设置徽标和网站图标
从 Rust 源文件中删除不必要的可执行标志
禁止引擎中大多数板条箱使用 unsafe
删除冗余导入
清理一些底层依赖项
修复一些 nightly Clippy lint
修复一些文档警告
修复 beta lint
修复 "it's" 与 "its" 的用法。
修复 WASM 上的 Clippy lint
将整体 lib 切换到模块重新导出
chore: 修复一些注释
删除非发布板条箱的
version
字段并更新描述改进
config_fast_builds.toml
向所有板条箱添加
README.md
确定每个独立的 bevy_* 板条箱的 msrv。
恢复 "向大多数公共特征添加
on_unimplemented
Diagnostics"
交叉切面 + 开发工具 + Gizmos #
交叉切面 + ECS #
开发工具 #
FPS 叠加
始终在所有内容之上生成 fps_overlay
在 bevy_dev_tools 中将
debug_overlay
重命名为ui_debug_overlay
删除 close_on_esc
对示例展示报告使用文件夹并添加显示日志标志
开发工具 + Diagnostics #
开发工具 + Diagnostics + 渲染 #
开发工具 + ECS + 网络 #
开发工具 + Gizmos + UI #
开发工具 + 反射 #
开发者工具 + 窗口 #
诊断 #
从
LogPlugin
中删除不必要的通配符,并将警告转换为错误。使 sysinfo 诊断插件可选
用
bevy_utils
替换bevy_log
的 tracing 重新导出在
LogPlugin::update_subscriber
中添加对App
的访问权限删除 "features" 特性
简化回溯
修复来自 toml_edit 的弃用
在诊断中处理 NaN
修复 Android 日志中未处理的空字符
删除 bevy 日志对非发送资源的使用
改进 tracing 层定制
诊断 + ECS #
诊断 + 渲染 #
ECS #
更新 WorldQuery 和过滤器的文档
禁用步进的性能修复
修复
SystemTypeSet::system_type
与System::type_id
不一致的问题bevy_ecs
解决unsafe_op_in_unsafe_fn
的简单情况放宽单线程
Scope::spawn
的生命周期要求,以匹配多线程版本。修复 SimpleExecutor 崩溃
在 System::run 中立即应用延迟系统参数
更新一些命令的文档字符串,使用正确的类型
添加 Archetype::component_count
实现从
SystemId
到Entity
的转换从
bevy_ecs
中删除downcast-rs
作为依赖项组件生命周期钩子和延迟世界
用 register_component_hooks 替换 init_component_info
记录 Entity 内部表示的不稳定性
将 commands 模块移至
bevy::ecs::world
对非组件 SparseSets 使用 NonMaxUsize
改进组件钩子文档
bevy_ecs
: 为World::run_system
和World::run_system_with_input
修复文档重写部分 Commands rustdoc
删除 ComponentStorage 和相关类型
删除 initialize_resource<T> 及其朋友
清理 BundleSpawner/BundleInserter 中的指针使用
实现 MutUntyped::from(mut_typed)
在文档中提到查询迭代顺序和结果唯一性。
查询联接
SystemId 应该手动实现
Eq
注意 Query::is_empty 的性能
修复 Entity 的调试和序列化表示之间的不一致性
拆分 ScheduleGraph::process_configs 函数(已采用)
从 QueryState 中删除 archetype_component_access
为 EntityMut 和 EntityWorldMut 添加 into_ 方法,这些方法消耗 self。
删除 WorldCell
更新 ecs 查询文档
允许命令注册系统
添加一些有关原型内部结构的文档
更新有关捆绑删除的安全注释
向
World
添加了一个init_bundle
方法向 Has Query 类型添加 Debug
为 &Archetype 和 EntityLocation 实现 QueryData
为 ManualEventReader 实现 Clone
添加 QueryState::contains,记录复杂性,并将 as_nop 设置为 pub(crate)
仅存储查询迭代所需的 ID
修复拼写错误
修复 insert_or_spawn_batch/spawn_batch 方法中的拼写错误
添加
RemovedComponentEvents::iter
删除查询迭代中不必要的分支
添加
EntityWorldMut::remove_by_id
从默认特性中删除步进
将小型表格/原型集群到并行迭代中的单个任务中
为
EntityMut<'w>
实现From<&'w mut EntityMut>
向 Access Debug 实现添加原型
优化事件更新
更新
set_if_neq
和replace_if_neq
的文档清理多线程执行器
fix: 在
bevy_ui
中使用try_insert
而不是insert
,以防止在取消生成 UI 节点时出现恐慌使 SystemParam::new_archetype 和 QueryState::new_archetype 成为不安全的函数
修复状态丢失时的文档
并行事件读取器
改进
par_iter
和Parallel
在宏中使用
ptr::from_ref
和ptr::addr_eq
向
Query
方法添加#[track_caller]
更好的 SystemId 到 Entity 转换
添加调度文档
计算状态和子状态
调度资源变异
使一次性示例更适合新手
将计算/子状态示例中不相关的代码分离到子模块中
分离状态箱
状态示例
将 WorldQuery::get_state 约束为仅使用 &Components
在
Mut
上实现WorldQuery
和QueryData
。在 QueryIter 上实现完整的排序方法集
修复 Added、Changed 的文档
为构建 SystemParams 实现 SystemBuilder
进一步改进组件钩子文档
查询迭代器的简单 Debug 实现
重构命令应用以获得更多一致性
修复
FilteredEntity{Ref,Mut}
的各种get
方法中的不安全问题将 WorldQuery::init_state 参数约束为 ComponentInitializer
更新 NextState 的文档
将过渡名称统一为
exited
和entered
添加通过 EntityWorldMut 清除实体上所有组件的功能
简化状态过渡
合并
Substates
的过渡系统稍微清理一下子状态代码
向大多数公共特征添加
on_unimplemented
诊断向大多数公共特征添加
on_unimplemented
诊断 (#13347)将实用程序从示例移动到
bevy_state
,并添加状态范围实体的概念将
StateTransitionEvent<S>
泛化以允许身份过渡添加基于动态切片的 get_many_entities 方法变体
更新 bevy 状态的箱子元数据
清除 AppExitStates 实现上的错误特征标志
修复 EntityCommands::despawn 文档
为状态过渡调度顺序添加更细粒度的系统集
修复
StateTransition
周围的文档,并删除对apply_sta…
的引用更新
bevy_ecs
的序列化标志删除对
clear_trackers
的额外调用还原 "将 WorldQuery::init_state 参数约束为 ComponentInitial…"
修复查询联接文档中的轻微拼写错误
恢复
insert_state
的覆盖功能使用观察者泛化 ECS 反应性 (#10839)
从
in_state
中删除不准确的警告在安装状态时警告缺少
StatesPlugin
观察者示例不符合标准
为稀疏组件更新观察者原型标志
feat(bevy_app): 公开一个 API 用于执行特定子应用程序的更新。
不要在
Entity
的Display
实现中显示.to_bits
修复
par_read
目标为 0.14 分支AnyOf 完整性修复
如果
EntityCommand::with_entity
的结果未被使用,则发出警告向 QueryIter 添加缺少的
sort_unstable_by_key
添加缺少的
StaticSystemParam::queue
实现。修复 AnyOf 中的错误
修复
push_children
即使没有提供子节点,也会插入Children
组件的问题在 QuerySortedIter 文档中添加对
sort_unstable_by_key
的遗漏说明将 #14083(注销事件)移植到 0.14 分支
ECS + 网络 #
ECS + 网络 + 场景 #
ECS + 指针 #
ECS + 反射 #
替换
ReflectResource
上的FromWorld
要求,并为State<S>
反射Resource
使一些
ReflectComponent
/ReflectBundle
方法也能与EntityMut
一起使用使
from_reflect_or_world
也尝试ReflectDefault
,并改进一些注释和恐慌消息向事件及其包含的类型添加 Reflect 派生
将组件反射泛化为在
FilteredEntityRef
和FilteredEntityMut
上运行,而不是在EntityRef
和EntityMut
上运行。feat: Identifier 上的反射实现
ECS + 渲染 #
ECS + 任务 #
ECS + 实用程序 #
编辑器 #
编辑器 + 小部件 #
编辑器 + 反射 #
小部件 #
将小部件示例移至单独的文件夹中
使小部件组在渲染时排序稳定
添加网格小部件
添加基本灯光小部件
轴小部件示例
修复小部件在收到来自
GlobalTransform::to_scale_rotation_translation
的错误输出时出现恐慌的问题改进小部件轴示例
小部件线接头
小部件: 用 Vec3 替换 PositionItem
小部件 3d 网格
在轴示例中排序系统
小部件线样式
支持 2D 网格的线框
更改了 Arc 小部件文档中参数的顺序
添加四面体小部件
向小部件添加双端箭头
上下文清除小部件
小部件: 在旋转之前获取平面 3d 上法线的法线
添加圆角框小部件
清理
2d_gizmos
示例段/分辨率命名不一致
使小部件按引用获取基元
更多小部件构建器
添加 axes_2d 小部件。
小部件 + 数学 #
从 bounding_2d 示例中挑出毛病
添加
Annulus
小部件新的圆形基元:
Arc2d
、CircularSector
、CircularSegment
向
render_primitives
示例添加Triangle3d
/Tetrahedron
实现菱形 2D 基元。
为
Arc2d
、CircularSegment
、CircularSector
实现 GizmoPrimitive2d,并使 arc_2d 使用逆时针角度。
小部件 + 反射 #
小部件 + 渲染 #
层次结构 #
层次结构 + 场景 #
输入 #
也在
just_pressed
触摸中查找位置添加表格显示输入方法的复杂性
防止在
text_input
示例中收到多个 Enter 输入时出现恐慌仅在需要时更新
Touches
资源修复 Input -> ButtonInput 的遗漏重命名
使 Gilrs 在非 Wasm 目标上成为普通资源
添加 WinitEvent 聚合事件,用于同步窗口事件读取
在键盘输入文档中的几个地方将
Input
更新为ButtonInput
为启动时连接的游戏手柄发送 GamepadEvent
澄清有关
just_released
和just_pressed
输入的文档从
text_input
示例中删除未使用的ImePreedit
组件修复
previous_position
/previous_force
过早被丢弃的问题ButtonInput 文档 - 性能成本调整
添加了
ButtonInput
文档使用示例将触控板重命名为手势,并添加新的手势
修复 winit 上焦点更改时的虚假按键按下 (#13299)
输入 + 数学 #
输入 + 窗口 #
数学 #
为几个(非常少)的基元添加单 f32 构造函数
添加
Direction3dA
并将方向类型从primitives
中移出三次样条曲线大修
将
Direction2d/3d
重命名为Dir2/3
在
f32
和方向类型之间实现Mul
改进非规格化方向的错误消息
支持变换包围盒
为
Aabb3d
添加关于旋转的注释添加
Rotation2d
为
BoundingVolume
特性添加scale_around_center
方法更改
SphereKind::Ico
的文档以反映三角形是等…某些基本形状的均匀点采样方法。
添加返回方向类型内部值的方法
为 Vec2 添加一个来自 Dir2 的实现
使基点样条曲线包含端点
将
Triangle3d
基元添加到bevy_math::primitives
数学测试修复
为
AspectRatio
实现From<Vec2>
将
Point
从三次样条曲线模块中移出并扩展它修复
Triangle2d
/Triangle3d
内部采样以正确遵循三角形删除 Quat 上的 VectorSpace 实现
将
Tetrahedron
基元添加到bevy_math::primitives
修复 2d_shapes.rs 示例中的行注释
将
Tetrahedron
的默认原点更改为(0, 0, 0)
方向和四元数的随机采样
为
Triangle3d
基元生成网格数学基元清理
为
bevy_math
中的WindingOrder
添加其他文档别名为 3D 包围盒和射线投射使用 Vec3A
将 glam 版本要求从 0.25 更新到 0.27
椭圆函数
用 f32::EPSILON 替换 std::f32::EPSILON
为
Dir
类型添加AXES
迭代器为三次样条曲线结构添加 copy、clone 和 debug 派生
允许使用零值构建形状
四面体采样
为 Dir2、Dir3、Dir3A 添加 slerp 函数
为
ShapeSample
特性添加Distribution
访问方法环形采样
添加 triangle_math 测试并修复 Triangle3d::bounding_sphere 错误
提到了 Dir::new 的 Vec 规范化
随机采样的示例
创建基本形状采样展示示例
阐明圆锥位置
为
Extrusion<T>
实现ShapeSample
为 2D 和 3D 形状示例添加线框切换
为
Dir2
添加罗盘方向常量Dir2
->Rotation2d
转换挤压边界
可网格化挤压
可网格化挤压 - 第 2 部分
允许创建随机
Rotation2d
允许自定义基元实现
Bounded3d
将
Rotation2d
重命名为Rot2
挤压
为
ExtrusionBuilder
添加段自定义基元示例
数学 + 反射 #
数学 + 渲染 #
将
Annulus
基元添加到bevy_math::primitives
为
Annulus
基元生成网格分离有限和无限 3D 平面
为
Cone
添加网格生成通用
MeshBuilder
特性修复网格缩放期间的法线
四面体网格
为
ConicalFrustum
添加网格生成为网格化基元提供更多选项
为 PlaneMeshBuilder 添加细分
数学 + 变换 #
数学 + 工具 #
数学 + 窗口 #
元数据 #
将对旧书籍的引用替换为快速入门指南
在发布后提升版本
添加发布步骤,添加指向 github 发布说明的链接
更新资金链接
记录如何发布补丁
添加关于部分审核的注释
添加关于请求审核的段落
在 PR 模板中添加测试部分
添加关于关闭 PR 的指南
重新组织问题标签
为工作组添加流程
记录候选发布流程
修改 #
指针 #
反射 #
bevy_reflect: 递归注册
添加用于查询给定短类型路径是否模糊的方法
reflect: 在序列化时正确处理代理类型
添加了对 std::HashSet、BTreeSet 和 BTreeMap 的 reflect 支持。
删除不必要的
impl_reflect_for_btree_map
宏清理类型注册
bevy_reflect: 删除
U32Visitor
为类型 ID 添加 reflect
为 BinaryHeap 添加 reflect
reflect: 删除可以通过宏处理的手动 Reflect 实现
bevy_reflect: 将
UntypedReflectDeserializer
重命名为ReflectDeserializer
为 Result<T, E> 作为枚举实现 Reflect
示例:添加
Dynamic Types
反射示例将
bevy_reflect_derive
文件夹重命名为derive
完成对
try_apply
的工作bevy_reflect: 删除
ContainerAttributes::merge
在发布模式下避免 bevy_reflect::List::iter 包装
bevy_reflect:
enum_utility
清理添加一些缺少的体积雾类型 reflect
bevy_reflect 中的哈希错误现在包含类型(bevyengine#13646)
反射 + 渲染 #
反射 + 场景 #
反射 + 时间 #
反射 + 工具 #
渲染 #
逐物体运动模糊
Meshlet 渲染(初始功能)
修复 bevy_core_pipeline 中的 dds 特性依赖项
为 bevy_render 添加 bitflags 的 serde 特性。
将 Camera3dBundle 的 'dither' 字段重命名为 'deband_dither' 以与 Camera2dBundle 对齐
为 SpriteBundle 和 SpriteSheetBundle 实现 Debug
允许与网格相关的队列阶段系统并行化
在统一/存储缓冲区中为每个 MeshUniform 节省 16 字节
修复 3 个或更多相机具有相同目标时的 MSAA 回写。
添加对 KHR_texture_transform 的支持
将 AlphaMode 移到 bevy_render 中
使全局变量在顶点着色器中可见
修复 UI 图像切片
修复:由于缺少 CUBE_ARRAY_TEXTURES,iOS 模拟器未渲染
使渲染器中的更多内容变为 pub
当着色器尚未可用时将管道设置为已排队
修复拼写错误:converstion -> conversion
使反射探针示例帧速率独立
为 WASM 将 SkyUniforms 填充到 16 字节
添加修改颜色通道的“流畅”方法。
在处理纹理尺寸时优先使用
UVec2
清理:在 extract_meshes 中使用 Parallel
提高 3D 照明示例的灯光强度
如果
intensity == 0.0
,则提前退出 bloom 节点修复 WebGL 未渲染
StandardMaterial
按管道和网格而不是按距离对 alpha 遮罩管道进行排序
修复
CameraProjectionPlugin
在某些情况下未实现Plugin
添加随机着色器工具,修复 cluster_debug_visualization
在
many_lights
示例中使用spawn_batch
改进更多示例中的照明
为 LinearRgba 实现 ShaderType
计算着色器生命游戏示例:使用 R32Float 而不是 Rgba8Unorm
注册
fxaa::Sensitivity
并派生Debug
bloom: 为发射使用发射色而不是基础色
内部化网格顶点缓冲区布局,以便我们不必反复比较它们。
将
wgpu
更新到 v0.19.3 并取消固定web-sys
。批处理:用 u32 替换 GpuArrayBufferIndex::index
PBR:为衰减使用衰减而不是基础色
修复颜色迁移后的示例光照贴图
为纹理图集添加切片支持
更新
StandardMaterial
结构的emissive
字段的注释,以提及较大的颜色通道值在基本调色板中使用从 8 位值计算出的浮点数
修复方向光阴影视锥体剔除靠近裁剪平面的无穷大
改进 Bloom 3D 照明
尝试插入 NoAutomaticBatching
从 light.rs 中提取环境光,并创建 light 目录
停止重试已删除的资产
为裁剪颜色添加特性
在 as_bind_group 中快速失败
为 MaterialPlugin 添加设置以启用/禁用阴影
为
Hsva
和Hwba
实现Mix
插值色调应该使用 rem_euclid。
删除对
SpritePipeline
的不必要颜色专门化将 PointLight、SpotLight 和 DirectionalLight 结构从 light/mod.rs 中移出
修复:使 WebGPU 着色器再次工作
在 synchronous_pipeline_compilation 文档中添加 iOS
修复 wasm 原子的 CI
将 image 要求从 0.24 更新到 0.25
使 PersistentGpuBufferable 成为安全的特性
将
StandardMaterialKey
打包成单个标量而不是结构。圆环基准测试
通过将不透明项 bin 到一起而不是对它们进行排序来提高性能。
矢量化 reset_view_visibility
在 post_processing 示例中添加了一个小注释,其中包含有关如何使其对 2D 工作的说明
修复 Linux Nvidia 550 驱动程序上的崩溃
删除
DeterministicRenderingConfig
使用 Nvidia 驱动程序规范化警告消息
修复
generate_custom_mesh
示例中的 UV 坐标微优化
queue_material_meshes
,主要用于删除位操作。many_cubes:添加无自动批处理和不同网格的生成
将环形形状添加到
2d_shapes
示例中默认情况下禁用 RAY_QUERY 和 RAY_TRACING_ACCELERATION_STRUCTURE
放松 BufferVec 的类型约束
添加方法以从管道缓存获取等待的管道 ID。
修复网格管道键中使用辐射体积的 msaa 偏移
修复网格文档中的损坏链接
修复天空盒错误的 alpha
更强大的 gpu 图像使用
添加 previous_view_uniforms.inverse_view
修复 pbr_functions.wgsl 中的潜在越界访问
添加 gpu 回读示例
修复生命游戏示例
在可用的情况下,通过计算着色器在 GPU 上生成
MeshUniform
。在 StandardMaterial 中添加了翻转纹理坐标方法
为点光源实现百分比更近过滤 (PCF)。
为性能起见,将单个
VisibleEntities
列表分成 2D 网格、3D 网格、灯光和 UI 元素的单独列表。修复 #12582 之后精灵、文本和 meshlet 的渲染。
在提取
SpriteSource
时不要检查每个实体。修复转码单通道或双通道 KTX2 纹理时的崩溃
修复 2D BatchedInstanceBuffer 清理
实现 alpha 到覆盖 (A2C) 支持。
精灵切片的规范化锚点位于该切片的尺寸中
修复:当精灵有矩形且没有自定义尺寸时,aabb 的精灵大小不正确。
为 ExtendedMaterial 添加缺失的 Default 实现。
记录相机坐标空间
在所有其他可见性系统集完成设置后,运行 `CheckVisibility`。
通过窗口创建公开 `desired_maximum_frame_latency`。
使用 WireframeColor 覆盖全局颜色。
使用 u64 作为 MeshPipelineKey。
澄清有关相机坐标系的注释。
删除未使用的推入常量。
Meshlet 连续 LOD
修复 mesh2d_manual 渲染其他网格时,自定义管线错误。
限制渲染资产。
清理 extract_meshes。
修复 `CameraProjection` 崩溃并改进 `CameraProjectionPlugin`。
资产限制:如果没有限制,不要耗尽。
与 Meshlet LOD 兼容的两遍遮挡剔除。
恢复龙的权力宝座。
实现 GPU 视锥剔除。
修复 `bevy_render/src/batching/gpu_preprocessing.rs` 中的错别字。
不要忽略不可批处理的排序项。
实现电影色彩分级。
在 texture_binding_array 示例中使用 BindGroupLayoutEntryBuilder。
实现可见性范围,也称为分层细节级别 (HLOD)。
添加 BufferVec,它是 StorageBuffer 的更高性能替代方案,并使 GpuArrayBuffer 使用它。
实现自动曝光插件。
将 IntoDynamicImageError 重新导出为公共。
Meshlet 删除每个集群数据上传。
文档自定义 CameraProjection 需要使用插件。
重复纹理示例。
仅在缓冲区已存在时创建已更改的缓冲区。
根据 Filament 和 `KHR_materials_clearcoat` 规范实现清漆涂层。
再次使用发射颜色对发射纹理进行调制。
提取网格视图布局逻辑。
通过为 `visibility_ranges` 数组提供固定长度来修复 WebGL 2 后端。
清理 2D 渲染阶段。
已添加无头渲染器示例。
修复 wasm 上的运动模糊。
删除发布版本中未使用的警告。
修复自动曝光中的错误 workgroupBarrier 和 OOB 数组访问。
为 StandardMaterial 添加 UV 通道选择。
实现快速景深作为后期处理效果。
添加 `PointLight` 文档。
在预处理阶段应用 uv 变换。
跳过顶点预处理着色器中冗余的 mesh_position_local_to_world 调用。
修复 2D 管线中的 ClearColor。
在 webgpu 上启用景深。
为 `ScreenSpaceAmbientOcclusionSettings` 结构添加 `Debug` 派生。
通过设置 transmissive_lighting_input.F_ab 的正确值来修复透射。
支持计算索引网格的法线。
恢复“支持计算索引网格的法线 (#12716)”并添加对计算平滑法线的支持。
#12502 删除 RenderLayers 的限制。
实现体积雾和体积光照,也称为光柱或神光。
删除不必要的 .view_layouts。
示例 render_to_texture:删除额外的灯光。
在 StandardMaterial 中添加 emissive_exposure_weight。
使预处理着色器在存在光照贴图时进行编译。
删除另一个 .view_layouts。
修复 headless_renderer 根据图像尺寸表现出错误的行为。
修复 beta Rust 上的 lint。
使渲染阶段渲染世界资源而不是组件。
修复景深示例中熔岩发射强度。
修复 2D 在奇数窗口大小下看起来模糊的问题。
修复照明示例,遵循 #13350 中的发射材质更改。
更新渲染图文档。
为 bevy_pbr 添加 glsl 功能。
为延迟渲染器实现可选的锐利屏幕空间反射,并改进射线行进代码。
恢复反射 PR 对 meshlet 示例的更改。
在体积雾绑定组中使用 ssr 动态偏移。
为精灵和 mesh2d 管线添加色调映射 LUT 绑定。
将默认目标曝光设置为最小值,而不是 0。
在 TAA 之前运行运动模糊以减少伪影。
修复:运动模糊应该对没有深度的屏幕片段进行采样。
在具有 Adreno 6xx GPU 的 Android 上禁用 GPU 预处理。
color_grading:相机设置更改时更新 UI。
修复 `RenderLayers` 文档。
为带蒙皮的网格和带变形目标的网格实现运动矢量和 TAA。
使用 meshopt 的正确最小版本。
添加天空盒运动矢量。
Meshlet 单遍深度降采样 (SPD)。
更惯用的纹理图集构建器。
关于图像调试断言的额外信息。
将与集群相关的类型和函数移到它们自己的模块中。
规范化矩阵命名。
将 ruzstd 要求从 0.6.0 更新到 0.7.0。
根据 `KHR_materials_anisotropy` 实现 PBR 各向异性。
记录在 Mesh::(with_)insert_attribute 中更新 Aabb 的必要性。
在集群上下文中将“点光源”重命名为“可集群对象”。
为 `BufferVec` 添加 `binding()` 辅助函数。
实现亚像素形态抗锯齿,或 SMAA。
为 `gpu_readback` 示例使用 `BufferVec`。
如果色调映射为无,则跳过色调映射。
使 `Mesh::merge` 接受 `Mesh` 的引用。
杂项 meshlet 更改。
在 pbr_prepass 中的 apply_normal_mapping 中使用 TBN。
允许 hdr 和非 hdr 相机混合到同一个渲染目标。
2D 自上而下的相机示例。
从 apply_normal_mapping 中删除未使用的 mip_bias 参数。
Meshlet 杂项。
澄清由于缺少着色器文件导致的错误消息。
修复 meshlet 顶点属性插值。
向 `StandardMaterial` 和 `ColorMaterial` 添加 `from_color`。
使 FOG_ENABLED 成为 shader_def 而不是材料标志。
恢复“使 FOG_ENABLED 成为 shader_def 而不是材料标志 (#13783)”。
在后期处理示例中使用动态统一缓冲区。
Wgpu 0.20
使 meshlet 处理确定性。
修复 meshlet 与常规着色通道的交互。
修复 MeshletMesh 材质系统排序。
如果没有功能 `bevy_pbr`、`ktx2`、`zstd`,不要崩溃。
使用 llvmpipe 时打印警告。
错别字
修复 CPU 适配器警告中的错别字。
修复集群遮挡查找的 mip 计算错误。
允许与网格无关的阶段项被分箱。
修复 WASM 在没有 `wgpu` 后端的情况下编译失败。
支持渲染层的操作并修复相等性比较。
阐明默认渲染层和 `none` 渲染层之间的区别。
添加功能开关以将默认 StandardMaterial 的新各向异性纹理设置为关闭。
渲染 + 变换 #
渲染 + UI #
弃用 `SpriteSheetBundle` 和 `AtlasImageBundle`。
将 `BackgroundColor` 与 `UiImage` 解耦。
修复模糊文本。
修复由于错误混合导致的 UI 边框伪影。
修复 #13277 后,UI 元素随机不出现的问题。
降低抗锯齿强度。
修复崩溃:使用了无效的 SlotMap 键。
使 `BackgroundColor` 和 `BorderColor` 的默认行为更直观。
渲染 + 工具 #
渲染 + 窗口 #
使用 4 个相机更新 `split_screen` 示例。
configure_surface 需要在 iOS 上的主线程上进行。
引入 `WindowWrapper`,在使用流水线渲染时扩展窗口的生存期。
场景 #
任务 #
在 bevy_tasks 中的并行迭代帮助程序中添加索引参数。
使 Bevy 为 WebAssembly 构建,并支持多线程。
升级 async-task。
删除 async-task 作为依赖项。
async_compute 示例:不要在任务中阻塞。
任务 + 窗口 #
文本 #
时间 #
变换 #
变换的对齐 API
在 `Transform` API 中使用 `Dir3`。
重构 align 示例以使用 `Dir3` 随机采样。
bevy_transform 拆分以允许功能门模块化。
允许 bevy_transform 用作基本依赖项。
修复 `Transform` 和 `GlobalTransform` 文档中指向 `Transform` 的链接。
在 Transform::align 示例中使用飞船。
变换 + UI #
UI #
添加文档注释,解释对齐和锚点与 text_2d 的不同行为。
简化和改进 `overflow_debug` 示例。
从 `flex_layout` 示例中删除自定义窗口大小。
在 `ui_texture_slice` 示例中为边框添加着色。
UI 材质尊重目标相机。
避免对非 UI 节点出现恐慌。
修复 #12255 在多相机场景中更新 TargetCamera 不允许计算布局。
从 UI 示例图像中删除背景颜色。
修复 `with_scale_factor_override` 不正确地设置 `scale_factor_override`。
修复 UiMaterial 文档中的错误链接。
为大多数板条箱的 docs.rs 元数据添加“all-features = true”。
不要尝试为零大小的节点设置光标相对位置。
在移动示例中正确设置背景颜色。
减少 ui_stack_system 中的稳定状态分配。
向 `UiRect` 添加 `with_left`、`with_right`、`with_top`、`with_bottom`。
在布局后计算纹理切片。
feat:在某些 UI 类型上派生一些通用特征。
为 UI 节点添加边框半径 (已采用)。
UI:允许边框半径对图像和背景可选。
UI:不要将颜色通道乘以 alpha。
UI:圆角边框应该使用相机而不是窗口。
更新 `borders` 示例以匹配 `rounded_borders` 示例。
圆角边框:删除着色器中的死代码。
恢复 0.13.1 之前的根节点布局行为。
在 `ui` 示例中为新文本添加填充。
[bevy_ui/layout] 将 UiSurface 提取到单独的文件中。
语法修正
正确处理没有相机的 UI 层次结构。
在 gridtrack 实现、repeatedgridtrack 实现中添加了 vmin 和 vmax。
UI:将未变换的节点大小传递给着色器。
升级到 Taffy 0.4。
将 `Rect` 的 `inset()` 方法重命名为 `inflate()`。
优化 `EMPTY` 矩形的值。
修复 UI 圆角边框的各种错误。
修复按钮上的圆角边框。
修复 WebGPU 中的 UI:从 if 外部调用 `textureSample`。
修复图像度量函数以将固有纵横比应用于样式大小。
将默认文本字体大小更新为 24px。
使 UI 文本渲染受相机驱动。
bug:修复具有不对称边框的 9 切片纹理。
向 Outline 添加 PartialEq。
修复示例中背景颜色的剩余问题。
修复 `ui_texture_slice` 和 `ui_texture_atlas_slice` 示例中的边框颜色。
工具 #
重构:提取并行队列抽象。
bevy_utils:向 `bevy_utils::Entry` 类型别名添加 `BuildHasher` 参数。
分离 bevy_utils/bevy_core 的重新导出的依赖项。
窗口 #
将
size
和physical_size
添加到window
修复fit_canvas_to_parent
添加从外部来源请求重绘的功能
修复重新聚焦游戏时的winit控制流
将
CreateWindowParams
类型和create_windows
系统设为公共在窗口创建时公开Winit的
with_skip_taskbar
清理WinitWindows::remove_window
在WinitSettings中添加克隆
修复#12000:当视口设置为相机并切换到SizedFul…时
移除不必要的lint
#[allow(...)]
修复:重写winit循环
简化winit运行器退出代码报告
确保干净退出
修复:升级到winit v0.30
确保窗口在主线程上被丢弃
13743 应用程序退出挂起
在更新winit时正确检查物理尺寸
在创建窗口时将窗口缩放比例应用于窗口大小
让WindowPosition::Centered考虑scale_factor_override
每帧绘制只运行一次更新
没有区域标签#
在
App::is_plugin_added
中使用is
方法代替downcast_ref::<T>().is_some()
更新到toml_edit 0.22
在示例中使用滚轮控制相机速度
修复一些拼写错误
在ui_texture_slice示例中的查询中删除不必要的mut
修复了iOS文档中关于xcrun命令的拼写错误
examples/ecs/iter_combinations:使用固定时间步长初始化速度
将tracing-log的要求从0.1.2更新到0.2.0
在错误消息中包含链接
在错误消息链接中添加冒号
对
contributors
示例进行各种改进像docs.rs一样构建开发文档
在config.toml中添加夜间提示
使用Bevy引擎错误代码时,更新engine_style_guide以添加指向错误代码的链接指南
移除重复代码
将crate-ci/typos从1.18.2更新到1.19.0
移除typos.toml中的注释
修复了有关atlas + 切片支持的文档
修复了各种示例中绿色变暗的问题
修复了各种示例中“深灰色”变亮的问题
修复了iOS模拟器支持
我们必须有谷歌眼睛(新的游戏示例)
修复了
lighting
示例中昏暗的发光值将ruzstd的要求从0.5.0更新到0.6.0
low_power示例:挑刺
修复了breakout示例中
z
缩放比例为0.0
的问题Breakout重构
修复了bevy_internal/Cargo.toml中的拼写错误
更新到fixedbitset 0.5
移除指向不存在示例的链接
美化示例展示网站的URL
将base64的要求从0.21.5更新到0.22.0
修复了示例中的粉色
重构:分离出
PanicHandlerPlugin
拼写错误:“plateform” -> “platform”
在示例中切换到可移植的RNG
使
feature(doc_auto_cfg)
工作在示例中使用种子RNG添加解释
修复了wasm/webgl2中的example mesh2d_manual
修复了导致崩溃的歧义
修复了示例展示wasm窗口设置补丁
将crate-ci/typos从1.19.0更新到1.20.4
启用
clippy::ref_as_ptr
将crate-ci/typos从1.20.4更新到1.20.8
将
Cascades
添加到类型注册表中,修复了glTF中的灯光。更新并澄清维护者合并规则
为Bevy徽标添加替代文字
headless_renderer注释拼写错误修复
将itertools的要求从0.12更新到0.13
对color_grading示例进行一些小的改进
在volumetric_fog示例中将ambient_intensity设置为0.0,并更正文档注释
在示例中将From<Color>用于StandardMaterial
在各种示例中使用标准指令文本/位置
在生命游戏示例中处理wgsl错误
修复了一些拼写错误
将crate bevy_state_macros_official重命名为其原始名称
使Observer::with_event(和其他变体)不安全
修复了BackgroundColor更改后的示例color_grading和mobile