1 个不稳定版本
0.14.0 | 2024年7月14日 |
---|
#3 在 #compute-shader
每月 129 次下载
66KB
1K SLoC
Bevy Easy Compute
在Bevy应用程序中运行wgpu计算着色器的一种简单方法。
这是Kjolnyr/bevy_app_compute的分支,该分支已不再维护。本项目目标是保持其整体架构并添加改进,同时继续维护bevy_app_compute
。欢迎提交问题和PR。
入门
将以下行添加到您的Cargo.toml
[dependencies]
bevy_easy_compute = "0.14.0"
用法
设置
在实现ComputeShader
的struct中声明您的着色器。函数shader()
应指向您的着色器源代码。您还需要派生TypePath
#[derive(TypePath)]
struct SimpleShader;
impl ComputeShader for SimpleShader {
fn shader() -> ShaderRef {
"shaders/simple.wgsl".into()
}
}
接下来,声明一个实现ComputeWorker
的struct,以声明绑定和worker的逻辑
#[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
的struct一个AppComputeWorkerPlugin
App::new()
// ... other plugins ...
.add_plugins(bevy_easy_compute::AppComputeWorkerPlugin::<SimpleComputeWorker>::default());
您的计算worker现在将在每帧的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]
一次性计算
您可以配置worker仅在请求时执行
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();
然后,当您准备好执行它时,可以调用worker上的execute()
// Execute it only when the left mouse button is pressed.
fn on_click_compute(
buttons: Res<ButtonInput<MouseButton>>,
mut compute_worker: ResMut<AppComputeWorker<SimpleComputeWorker>>
) {
if !buttons.just_pressed(MouseButton::Left) { return; }
compute_worker.execute();
}
它将在当前帧结束时运行,您将在下一帧中能够读取数据。
(见one_shot.rs)
示例
Bevy版本映射
Bevy | bevy_easy_compute |
---|---|
0.14 | 0.14.0 |
依赖项
~24–58MB
~1M SLoC