3个版本

0.10.3 2023年4月19日
0.10.2 2023年4月17日
0.10.1 2023年4月16日
0.10.0 2023年4月14日

#866游戏开发

Download history 46/week @ 2024-03-31

52 每月下载量

MIT/Apache

59KB
1K SLoC

Bevy App Compute

MIT/Apache 2.0 Doc Crate

从App World调度和运行计算着色器。

入门指南

将以下行添加到您的 Cargo.toml

[dependencies]
bevy_app_compute = "0.10.3"

用法

设置

在实现 ComputeShader 的结构体中声明您的着色器。函数 shader() 应指向您的着色器源代码。您还需要派生 TypeUuid 并分配一个唯一的 Uuid

#[derive(TypeUuid)]
#[uuid = "2545ae14-a9bc-4f03-9ea4-4eb43d1075a7"]
struct SimpleShader;

impl ComputeShader for SimpleShader {
    fn shader() -> ShaderRef {
        "shaders/simple.wgsl".into()
    }
}

接下来,声明一个实现 ComputeWorker 的结构体,以声明工作者的绑定和逻辑

#[derive(Resource)]
struct SimpleComputeWorker;

impl ComputeWorker for SimpleComputeWorker {
    fn build(world: &mut World) -> AppComputeWorker<Self> {
        let worker = AppComputeWorkerBuilder::new(world)
            // Add a uniform variable
            .add_uniform("uni", &5.)

            // Add a staging buffer, it will be available from
            // both CPU and GPU land.
            .add_staging("values", &[1., 2., 3., 4.])

            // Create a compute pass from your compute shader
            // and define used variables
            .add_pass::<SimpleShader>([4, 1, 1], &["uni", "values"])
            .build();

        worker
    }
}

别忘了将着色器文件添加到您的 assets/ 文件夹


@group(0) @binding(0)
var<uniform> uni: f32;

@group(0) @binding(1)
var<storage, read_write> my_storage: array<f32>;

@compute @workgroup_size(1)
fn main(@builtin(global_invocation_id) invocation_id: vec3<u32>) {
    my_storage[invocation_id.x] = my_storage[invocation_id.x] + uni;
}

AppComputePlugin 插件添加到您的应用程序中,以及每个实现 ComputeWorker 的结构体一个 AppComputeWorkerPlugin

use bevy::prelude::*;
use bevy_app_compute::AppComputePlugin;

fn main() {
    App::new()
        .add_plugin(AppComputePlugin)
        .add_plugin(AppComputeWorkerPlugin::<SimpleComputeWorker>::default());
}

您的计算工作者现在将在每帧的 PostUpdate 阶段运行。要从中读取/写入,请使用 AppComputeWorker<T> 资源!

fn my_system(
    mut compute_worker: ResMut<AppComputeWorker<SimpleComputeWorker>>
) {
    if !compute_worker.available() {
        return;
    };

    let result: Vec<f32> = compute_worker.read_vec("values");

    compute_worker.write_slice("values", [2., 3., 4., 5.]);

    println!("got {:?}", result)
}

(见 simple.rs)

多遍

您可以在不将数据在之间复制回CPU的情况下进行多遍

let worker = AppComputeWorkerBuilder::new(world)
    .add_uniform("value", &3.)
    .add_storage("input", &[1., 2., 3., 4.])
    .add_staging("output", &[0f32; 4])
    // add each item + `value` from `input` to `output`
    .add_pass::<FirstPassShader>([4, 1, 1], &["value", "input", "output"]) 
    // multiply each element of `output` by itself
    .add_pass::<SecondPassShader>([4, 1, 1], &["output"]) 
    .build();

    // the `output` buffer will contain [16.0, 25.0, 36.0, 49.0]

(见 multi_pass.rs)

一次性计算

您可以根据请求配置工作者仅当请求时执行

let worker = AppComputeWorkerBuilder::new(world)
    .add_uniform("uni", &5.)
    .add_staging("values", &[1., 2., 3., 4.])
    .add_pass::<SimpleShader>([4, 1, 1], &["uni", "values"])

    // This `one_shot()` function will configure your worker accordingly
    .one_shot()
    .build();

然后,您可以在准备执行它时在您的工作者上调用 execute()

// Execute it only when the left mouse button is pressed.
fn on_click_compute(
    buttons: Res<Input<MouseButton>>,
    mut compute_worker: ResMut<AppComputeWorker<SimpleComputeWorker>>
) {
    if !buttons.just_pressed(MouseButton::Left) { return; }

    compute_worker.execute();
} 

它将在当前帧的末尾运行,您将在下一帧中能够读取数据。

(见 one_shot.rs)

示例

examples

正在开发的功能

  • 在计算遍之间读取/写入的能力。
  • 向API添加更多选项,例如决定 BufferUsages 或缓冲区的大小。
  • 优化。目前代码一团糟。
  • 测试。这迫切需要测试。

Bevy版本映射

Bevy bevy_app_compute
0.10 0.10.3

依赖关系

~21–57MB
~1M SLoC