Skip to content

Commit

Permalink
修订前九章文档
Browse files Browse the repository at this point in the history
  • Loading branch information
jinleili committed Nov 17, 2024
1 parent b1ac962 commit 388c435
Show file tree
Hide file tree
Showing 11 changed files with 126 additions and 582 deletions.
478 changes: 18 additions & 460 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ edition = "2021"
rust-version = "1.79"

[workspace.dependencies.image]
version = "0.24"
version = "0.25"
default-features = false

[workspace.dependencies]
Expand Down
7 changes: 2 additions & 5 deletions code/beginner/tutorial5-textures/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,13 @@ const INDICES: &[u16] = &[0, 1, 4, 1, 2, 4, 2, 3, 4];

struct WgpuApp {
app: AppSurface,
size: PhysicalSize<u32>,
size_changed: bool,
render_pipeline: wgpu::RenderPipeline,
vertex_buffer: wgpu::Buffer,
index_buffer: wgpu::Buffer,
num_indices: u32,
size: PhysicalSize<u32>,
size_changed: bool,
// NEW!
#[allow(dead_code)]
diffuse_texture: texture::Texture,
diffuse_bind_group: wgpu::BindGroup,
}

Expand Down Expand Up @@ -226,7 +224,6 @@ impl WgpuAppAction for WgpuApp {
num_indices,
size,
size_changed: false,
diffuse_texture,
diffuse_bind_group,
}
}
Expand Down
2 changes: 1 addition & 1 deletion code/utils/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ winit.workspace = true
wgpu.workspace = true
glam.workspace = true
png = "0.17"
image = { version = "*" }
image.workspace = true

[target.'cfg(target_arch = "wasm32")'.dependencies]
console_error_panic_hook.workspace = true
Expand Down
20 changes: 8 additions & 12 deletions docs/beginner/tutorial3-pipeline/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,16 +118,14 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4f {

## 使用着色器

终于要用到本章节标题提到的概念 **管线**(Pipeline)了。首先,我们来修改 `State` 以包括以下代码。
终于要用到本章节标题提到的概念 **管线**(Pipeline)了。首先,我们来修改 `WgpuApp` 以包括以下代码。

```rust
// lib.rs
struct State {
surface: wgpu::Surface,
device: wgpu::Device,
queue: wgpu::Queue,
config: wgpu::SurfaceConfiguration,
size: winit::dpi::PhysicalSize<u32>,
struct WgpuApp {
app: AppSurface,
size: PhysicalSize<u32>,
size_changed: bool,
// 新添加!
render_pipeline: wgpu::RenderPipeline,
}
Expand Down Expand Up @@ -239,16 +237,14 @@ primitive: wgpu::PrimitiveState {

<!-- https://gamedev.stackexchange.com/questions/22507/what-is-the-alphatocoverage-blend-state-useful-for -->

现在我们要做的就是把 `render_pipeline` 添加到 `State`,然后就可以使用它了!
现在我们要做的就是把 `render_pipeline` 添加到 `WgpuApp`,然后就可以使用它了!

```rust
// new()
Self {
surface,
device,
queue,
config,
app,
size,
size_changed: false,
// 新添加!
render_pipeline,
}
Expand Down
58 changes: 25 additions & 33 deletions docs/beginner/tutorial4-buffer/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,15 @@ const VERTICES: &[Vertex] = &[

按逆时针顺序排列顶点:上、左下、右下。这样做的部分理由是出于惯例,但主要是因为我们在 `render_pipeline``primitive` 中指定了三角形的 `front_face``Ccw`(counter-clockwise),这样就可以做背面剔除。这意味着任何面向我们的三角形的顶点都应该是按逆时针顺序排列。

现在有了顶点数据,需要将其存储在一个缓冲区中。让我们给 `State` 添加再一个 `vertex_buffer` 字段:
现在有了顶点数据,需要将其存储在一个缓冲区中。让我们给 `WgpuApp` 添加再一个 `vertex_buffer` 字段:

```rust
// lib.rs
struct State {
struct WgpuApp {
// ...
render_pipeline: wgpu::RenderPipeline,

// 新添加!
vertex_buffer: wgpu::Buffer,

// ...
}
```
Expand Down Expand Up @@ -78,7 +76,7 @@ use wgpu::util::DeviceExt;
你应该注意到我们使用了 [bytemuck](https://docs.rs/bytemuck/1.2.0/bytemuck/) 来将 `VERTICES` 转换为 `&[u8]``create_buffer_init()` 函数的参数类型是 `&[u8]`,而 `bytemuck::cast_slice` 为我们实现了此类型转换。为此需在 `Cargo.toml` 中添加以下依赖项:

```toml
bytemuck = { version = "1.14", features = [ "derive" ] }
bytemuck = { version = "1.19", features = [ "derive" ] }
```

我们还需要实现两个 trait 来使 `bytemuck` 工作。它们是 [bytemuck::Pod](https://docs.rs/bytemuck/1.3.0/bytemuck/trait.Pod.html)[bytemuck::Zeroable](https://docs.rs/bytemuck/1.3.0/bytemuck/trait.Zeroable.html)`Pod` 表示 `Vertex`["Plain Old Data"](<https://zh.wikipedia.org/wiki/POD_(程序设计)>) 数据类型,因此可以被解释为 `&[u8]` 类型。`Zeroable` 表示可以对其使用 `std::mem::zeroed()`。下面修改 `Vertex` 结构体来派生这些 trait:
Expand All @@ -103,15 +101,11 @@ unsafe impl bytemuck::Zeroable for Vertex {}

</div>

最终,我们可以把 `vertex_buffer` 添加到 `State` 结构体中了:
最终,我们可以把 `vertex_buffer` 添加到 `WgpuApp` 结构体中了:

```rust
Self {
surface,
device,
queue,
config,
size,
// ...
render_pipeline,
vertex_buffer,
}
Expand Down Expand Up @@ -243,31 +237,32 @@ render_pass.draw(0..3, 0..1);

第二个参数是要使用的缓冲区的数据片断。你可以在硬件允许的情况下在一个缓冲区中存储尽可能多的对象,所以 `slice` 允许我们指定使用缓冲区的哪一部分。我们用 `..` 来指定整个缓冲区。

在继续之前,我们需要修改 `render_pass.draw()` 的调用来使用 `VERTICES` 所指定的顶点数量。在 `State` 中添加一个`num_vertices`,令其值等于 `VERTICES.len()`
在继续之前,我们需要修改 `render_pass.draw()` 的调用来使用 `VERTICES` 所指定的顶点数量。在 `WgpuApp` 中添加一个`num_vertices`,令其值等于 `VERTICES.len()`

```rust
// lib.rs

struct State {
struct WgpuApp {
// ...
num_vertices: u32,
}

impl State {
// ...
fn new(...) -> Self {
impl WgpuApp {
async fn new(
window: Arc<winit::window::Window>,
) -> Self {
// 创建 wgpu 应用
let app = AppSurface::new(window).await;
// ...
let num_vertices = VERTICES.len() as u32;

Self {
surface,
device,
queue,
config,
app,
size,
size_changed: false,
render_pipeline,
vertex_buffer,
num_vertices,
size,
}
}
}
Expand Down Expand Up @@ -366,7 +361,7 @@ const INDICES: &[u16] = &[

现在这种设置下,`VERTICES` 占用了 120 个字节,而 `INDICES` 只有 18 个字节,因为 `u16` 类型是 2 个字节长。在这种情况下,wgpu 会自动增加 2 个字节的填充,以确保缓冲区被对齐到 4 个字节,但它仍然只有 20 个字节。五边形总共是 140 字节,这意味着我们节省了 76 个字节! 这可能看起来不多,但当处理数十万的三角形时,索引可以节省大量的内存。

为了使用索引,有几处我们需要修改。首先需要创建一个缓冲区来存储索引。在 `State``new()` 函数中,创建了 `vertex_buffer` 之后创建 `index_buffer`。同时将 `num_vertices` 改为`num_indices`,令其值等于 `INDICES.len()`
为了使用索引,有几处我们需要修改。首先需要创建一个缓冲区来存储索引。在 `WgpuApp``new()` 函数中,创建了 `vertex_buffer` 之后创建 `index_buffer`。同时将 `num_vertices` 改为`num_indices`,令其值等于 `INDICES.len()`

```rust
let vertex_buffer = device.create_buffer_init(
Expand All @@ -387,15 +382,14 @@ let index_buffer = device.create_buffer_init(
let num_indices = INDICES.len() as u32;
```

我们不需要为索引实现 `Pod``Zeroable`,因为 `bytemuck` 已经为 `u16` 等基本类型实现了它们。只需将 `index_buffer``num_indices` 添加到 `State` 结构体中。
我们不需要为索引实现 `Pod``Zeroable`,因为 `bytemuck` 已经为 `u16` 等基本类型实现了它们。只需将 `index_buffer``num_indices` 添加到 `WgpuApp` 结构体中。

```rust
struct State {
surface: wgpu::Surface,
device: wgpu::Device,
queue: wgpu::Queue,
config: wgpu::SurfaceConfiguration,
size: winit::dpi::PhysicalSize<u32>,
struct WgpuApp {
app: AppSurface,
render_pipeline: wgpu::RenderPipeline,
size: PhysicalSize<u32>,
size_changed: bool,
render_pipeline: wgpu::RenderPipeline,
vertex_buffer: wgpu::Buffer,
// 新添加!
Expand All @@ -408,11 +402,9 @@ struct State {

```rust
Self {
surface,
device,
queue,
config,
app,
size,
size_changed: false,
render_pipeline,
vertex_buffer,
// 新添加!
Expand Down
78 changes: 38 additions & 40 deletions docs/beginner/tutorial5-textures/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ features = ["png", "jpeg"]

</div>

`State``new()` 函数中,于 `surface.configure()` 之后添加以下代码:
`WgpuApp``new()` 函数中,于 `AppSurface::new(window).await` 之后添加以下代码:

```rust
surface.configure(&device, &config);
// 新添加!
let app = AppSurface::new(window).await;

// 新添加!
let diffuse_bytes = include_bytes!("happy-tree.png");
let diffuse_image = image::load_from_memory(diffuse_bytes).unwrap();
let diffuse_rgba = diffuse_image.to_rgba8();
Expand Down Expand Up @@ -183,29 +183,29 @@ Mipmaps 是一个复杂的话题,需要在未来单独写一个章节。现在

```rust
let texture_bind_group_layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Texture {
multisampled: false,
view_dimension: wgpu::TextureViewDimension::D2,
sample_type: wgpu::TextureSampleType::Float { filterable: true },
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStages::FRAGMENT,
// This should match the filterable field of the
// corresponding Texture entry above.
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
count: None,
},
],
label: Some("texture_bind_group_layout"),
});
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Texture {
multisampled: false,
view_dimension: wgpu::TextureViewDimension::D2,
sample_type: wgpu::TextureSampleType::Float { filterable: true },
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStages::FRAGMENT,
// This should match the filterable field of the
// corresponding Texture entry above.
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
count: None,
},
],
label: Some("texture_bind_group_layout"),
});
```

`texture_bind_group_layout` 有两个条目:一个是绑定到 0 资源槽的**纹理**,另一个是绑定到 1 资源槽的**采样器**。这两个绑定只对由 `visibility` 字段指定的片元着色器可见。这个字段的可选值是 `NONE``VERTEX``FRAGMENT``COMPUTE` 的任意按位或(`|`)组合。
Expand Down Expand Up @@ -233,15 +233,13 @@ let diffuse_bind_group = device.create_bind_group(

看着这个,你可能会有一点似曾相识的感觉! 这是因为**绑定组****绑定组布局**的一个更具体的声明。它们分开的原因是,只要是共享同一个绑定组布局的绑定组,就能在运行时实时切换。创建的每个纹理和采样器都需要添加到一个绑定组中。为了达成目的,我们将为每个纹理创建一个新的绑定组。

让我们把 `diffuse_bind_group` 添加到 `State` 结构体中:
让我们把 `diffuse_bind_group` 添加到 `WgpuApp` 结构体中:

```rust
struct State {
surface: wgpu::Surface,
device: wgpu::Device,
queue: wgpu::Queue,
config: wgpu::SurfaceConfiguration,
size: winit::dpi::PhysicalSize<u32>,
struct WgpuApp {
app: AppSurface,
size: PhysicalSize<u32>,
size_changed: bool,
render_pipeline: wgpu::RenderPipeline,
vertex_buffer: wgpu::Buffer,
index_buffer: wgpu::Buffer,
Expand All @@ -253,7 +251,7 @@ struct State {
确保我们在 `new()` 函数中返回这个字段:

```rust
impl State {
impl WgpuApp {
async fn new() -> Self {
// ...
Self {
Expand Down Expand Up @@ -431,14 +429,14 @@ const VERTICES: &[Vertex] = &[

```toml
[dependencies]
image = "0.24"
image = "0.25"
glam = "0.29"
winit = "0.30"
env_logger = "0.11"
log = "0.4"
pollster = "0.3"
wgpu = "23"
bytemuck = { version = "1.14", features = [ "derive" ] }
bytemuck = { version = "1.19", features = [ "derive" ] }
anyhow = "1.0" # NEW!
```

Expand Down Expand Up @@ -569,19 +567,19 @@ let diffuse_bind_group = device.create_bind_group(
);
```

最后,需要更新 `State` 中的字段以使用全新 `Texture` 结构体,在未来的教程中还会用到它:
最后,需要更新 `WgpuApp` 中的字段以使用全新 `Texture` 结构体,在未来的教程中还会用到它:

```rust
struct State {
struct WgpuApp {
// ...
diffuse_bind_group: wgpu::BindGroup,
diffuse_texture: texture::Texture, // NEW
}
```

```rust
impl State {
async fn new() -> Self {
impl WgpuApp {
async fn new(window: Arc<winit::window::Window>) -> Self {
// ...
Self {
// ...
Expand Down
Loading

0 comments on commit 388c435

Please sign in to comment.