21个版本

0.3.3 2024年7月19日
0.3.1 2024年4月25日
0.3.0 2024年2月29日
0.2.2 2023年8月17日
0.1.1 2022年10月22日

#56 in 图形API

Download history 124/week @ 2024-04-25 3/week @ 2024-05-02 2/week @ 2024-05-16 1/week @ 2024-05-23 150/week @ 2024-06-06 10/week @ 2024-06-13 103/week @ 2024-07-18 146/week @ 2024-07-25 20/week @ 2024-08-01

每月269次下载

MIT许可证

210KB
6.5K SLoC

Dunge

简单且可移植的基于WGPU的3D渲染库。

特性

  • 简单灵活的API
  • 可自定义顶点、组和实例
  • 将着色器代码描述为单个Rust函数
  • 高度类型安全,运行时检查最小化
  • 支持桌面、WASM和(稍后)Android
  • 可选内置窗口和事件循环

应用领域

目前该库仅限个人使用。不过,随着时间的推移,我计划稳定API,以便某人可以用它来完成他们的任务。

入门指南

要开始使用该库,将其添加到您的项目中

cargo add dunge -F winit

如果需要创建窗口应用程序,请指定winit功能。尽管这不是必需的,例如,您可以直接将场景绘制到RAM中的图像中。

那么,如果您想在屏幕上绘制一些东西呢?假设您想绘制一个简单的彩色三角形。那么首先创建一个顶点类型。为此,为您的结构体派生Vertex特质

use dunge::prelude::*;

// Create a vertex type
#[repr(C)]
#[derive(Vertex)]
struct Vert {
    pos: [f32; 2],
    col: [f32; 3],
}

要在GPU上渲染某些内容,您需要编写一个着色器。在dunge中,您可以通过正常的(几乎)Rust函数来完成此操作

// Create a shader program
let triangle = |vert: sl::InVertex<Vert>| {
    // Describe the vertex position:
    // Take the vertex data as vec2 and expand it to vec4
    let place = sl::vec4_concat(vert.pos, sl::vec2(0., 1.));

    // Then describe the vertex color:
    // First you need to pass the color from
    // vertex shader stage to fragment shader stage
    let fragment_col = sl::fragment(vert.col);

    // Now create the final color by adding an alpha value
    let color = sl::vec4_with(fragment_col, 1.);

    // As a result, return a program that describes how to
    // compute the vertex position and the fragment color
    sl::Out { place, color }
};

从代码片段中可以看出,着色器要求您提供两个东西:顶点在屏幕上的位置以及每个片段/像素的颜色。结果是triangle函数,但如果您在IDE中请求其类型,您可能会注意到它比通常更复杂

impl Fn(InVertex<Vert>) -> Out<Ret<Compose<Ret<ReadVertex, Vec2<f32>>, Ret<NewVec<(f32, f32), Vs>, Vec2<f32>>>, Vec4<f32>>, Ret<Compose<Ret<Fragment<Ret<ReadVertex, Vec3<f32>>>, Vec3<f32>>, f32>, Vec4<f32>>>

这是因为这个函数实际上并没有进行任何计算。它只用于描述在GPU上计算所需内容的步骤。在着色器实例化过程中,此函数用于编译实际的着色器。然而,这使我们免于编写wgsl着色器,并允许在编译时进行类型检查。例如,dunge会检查着色器中的顶点类型是否与渲染期间使用的网格相匹配。它还会检查着色器内部的类型。

现在我们来创建dunge上下文和其他必需的内容

// Create the dunge context
let cx = dunge::context().await?;

// You can use the context to manage dunge objects.
// Create a shader instance
let shader = cx.make_shader(triangle);

您可能会注意到上下文创建需要异步操作。这是WGPU特有的,所以您需要在项目中添加您喜欢的异步运行时。

同时创建一个我们将要绘制的三角形网格

// Create a mesh from vertices
let mesh = {
    let data = const {
        MeshData::from_verts(&[
            Vert { pos: [-0.5, -0.5], col: [1., 0., 0.] },
            Vert { pos: [ 0.5, -0.5], col: [0., 1., 0.] },
            Vert { pos: [ 0. ,  0.5], col: [0., 0., 1.] },
        ])
    };

    cx.make_mesh(&data)
};

现在要运行应用程序,我们需要最后两件事:处理程序。一个在每次渲染之前被调用的Update处理程序,用于控制渲染对象和管理主事件循环

// Describe the `Update` handler
let upd = |ctrl: &Control| {
    for key in ctrl.pressed_keys() {
        // Exit by pressing escape key
        if key.code == KeyCode::Escape {
            return Then::Close;
        }
    }

    // Otherwise continue running
    Then::Run
};

在这里我们没有做任何特别的事情,我们只是检查是否按下了Esc键并在必要时结束主循环。请注意,此处理程序仅用于使用具有winit功能的窗口。

第二个Draw处理程序直接用于在最终帧中绘制内容

// Create a layer for drawing a mesh on it
let layer = cx.make_layer(&shader, view.format());

// Describe the `Draw` handler
let draw = move |mut frame: Frame| {
    use dunge::color::Rgba;

    // Create a black RGBA background
    let bg = Rgba::from_bytes([0, 0, 0, !0]);

    frame
        // Select a layer to draw on it
        .layer(&layer, bg)
        // The shader has no bindings, so call empty bind
        .bind_empty()
        // And finally draw the mesh
        .draw(&mesh);
};

注意:要创建一个图层,我们需要知道窗口的格式。猜测它是可能的,但最好直接从视图对象中获取它。您可以从特殊的make辅助函数中获取视图,该辅助函数在处理程序初始化时调用闭包,并将必要的数据传递给它。

现在您可以将两个步骤合并到一个处理程序中,运行应用程序并查看窗口

let make_handler = |cx: &Context, view: &View| {
    let upd = |ctrl: &Control| {/***/};
    let draw = move |mut frame: Frame| {/***/};
    dunge::update(upd, draw)
};

// Run the window with handlers
dunge::window().run_local(cx, dunge::make(make_handler))?;

您可以从这里找到此示例的完整代码这里,并使用以下方法运行它

cargo run -p window

示例

有关使用窗口的更多示例,请参阅示例目录。要构建和运行示例,请

cargo run -p <example_name>

构建和运行wasm示例

cargo x build <example_name>
cargo x serve <example_name>

如果系统上已经安装了wasm-pack,构建脚本将找到它并使用它来编译wasm工件。否则,将在本地安装wasm-pack。要防止此行为,请添加no-install标志

cargo x --no-install build <example_name>

最终,它将启动本地服务器,您可以在浏览器中打开https://127.0.0.1:3000来查看正在运行的应用程序。仅支持WebGPU后端,因此请确保您的浏览器支持它。

还可以查看测试目录中的创建单个图像的小示例。

依赖关系

~11–51MB
~836K SLoC