11 个版本

0.3.3 2024 年 7 月 19 日
0.3.2 2024 年 6 月 9 日
0.3.1 2024 年 4 月 25 日
0.3.0 2024 年 2 月 29 日
0.2.2 2023 年 8 月 17 日

#509图形 API

Download history 127/week @ 2024-04-22 8/week @ 2024-04-29 7/week @ 2024-05-20 135/week @ 2024-06-03 36/week @ 2024-06-10 109/week @ 2024-07-15 9/week @ 2024-07-22 95/week @ 2024-07-29

213 每月下载次数
用于 dunge

MIT 许可证

92KB
3K 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后端,因此请确保您的浏览器支持它。

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

依赖关系

~8–16MB
~240K SLoC