migrated docs for tutorial7

pull/126/head
Ben Hansen 4 years ago
parent c770e1860f
commit e462670b72

@ -491,6 +491,7 @@ impl State {
depth_stencil_state: None, depth_stencil_state: None,
vertex_state: wgpu::VertexStateDescriptor { vertex_state: wgpu::VertexStateDescriptor {
index_format: wgpu::IndexFormat::Uint16, index_format: wgpu::IndexFormat::Uint16,
// UPDATED!
vertex_buffers: &[Vertex::desc(), InstanceRaw::desc()], vertex_buffers: &[Vertex::desc(), InstanceRaw::desc()],
}, },
sample_count: 1, sample_count: 1,
@ -584,11 +585,11 @@ impl State {
depth_stencil_attachment: None, depth_stencil_attachment: None,
}); });
render_pass.set_vertex_buffer(1, self.instance_buffer.slice(..));
render_pass.set_pipeline(&self.render_pipeline); render_pass.set_pipeline(&self.render_pipeline);
render_pass.set_bind_group(0, &self.diffuse_bind_group, &[]); render_pass.set_bind_group(0, &self.diffuse_bind_group, &[]);
render_pass.set_bind_group(1, &self.uniform_bind_group, &[]); render_pass.set_bind_group(1, &self.uniform_bind_group, &[]);
render_pass.set_vertex_buffer(0, self.vertex_buffer.slice(..)); render_pass.set_vertex_buffer(0, self.vertex_buffer.slice(..));
render_pass.set_vertex_buffer(1, self.instance_buffer.slice(..));
render_pass.set_index_buffer(self.index_buffer.slice(..)); render_pass.set_index_buffer(self.index_buffer.slice(..));
// UPDATED! // UPDATED!
render_pass.draw_indexed(0..self.num_indices, 0, 0..self.instances.len() as _); render_pass.draw_indexed(0..self.num_indices, 0, 0..self.instances.len() as _);

@ -64,7 +64,7 @@ Let's create a method on `Instance` to convert to `InstanceRaw`.
impl Instance { impl Instance {
fn to_raw(&self) -> InstanceRaw { fn to_raw(&self) -> InstanceRaw {
InstanceRaw { InstanceRaw {
model: cgmath::Matrix4::from_translation(self.position) * cgmath::Matrix4::from(self.rotation), model: (cgmath::Matrix4::from_translation(self.position) * cgmath::Matrix4::from(self.rotation)).into(),
} }
} }
} }
@ -75,7 +75,6 @@ Now we need to add 2 fields to `State`: `instances`, and `instance_buffer`.
```rust ```rust
struct State { struct State {
instances: Vec<Instance>, instances: Vec<Instance>,
#[allow(dead_code)]
instance_buffer: wgpu::Buffer, instance_buffer: wgpu::Buffer,
} }
``` ```
@ -124,45 +123,65 @@ let instance_buffer = device.create_buffer_init(
&wgpu::util::BufferInitDescriptor { &wgpu::util::BufferInitDescriptor {
label: Some("Instance Buffer"), label: Some("Instance Buffer"),
contents: bytemuck::cast_slice(&instance_data), contents: bytemuck::cast_slice(&instance_data),
usage: wgpu::BufferUsage::STORAGE, usage: wgpu::BufferUsage::VERTEX,
} }
); );
``` ```
We need a way to bind our new instance buffer so we can use it in the vertex shader. We could create a new bind group (and we probably should), but for simplicity, I'm going to add a binding to the `uniform_bind_group` that references our `instance_buffer`. We're going to need to create a new `VertexBufferDescriptor` for `InstanceRaw`.
```rust ```rust
let uniform_bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { impl InstanceRaw {
entries: &[ fn desc<'a>() -> wgpu::VertexBufferDescriptor<'a> {
// ... use std::mem;
// NEW! wgpu::VertexBufferDescriptor {
wgpu::BindGroupLayoutEntry { stride: mem::size_of::<InstanceRaw>() as wgpu::BufferAddress,
binding: 1, // We need to switch from using a step mode of Vertex to Instance
visibility: wgpu::ShaderStage::VERTEX, // This means that our shaders will only change to use the next
ty: wgpu::BindingType::StorageBuffer { // instance when the shader starts processing a new instance
// We don't plan on changing the size of this buffer step_mode: wgpu::InputStepMode::Instance,
dynamic: false, attributes: &[
// The shader is not allowed to modify it's contents wgpu::VertexAttributeDescriptor {
readonly: true, offset: 0,
min_binding_size: None, // While our vertex shader only uses locations 0, and 1 now, in later tutorials we'll
}, // be using 2, 3, and 4, for Vertex. We'll start at slot 5 not conflict with them later
count: None, shader_location: 5,
}, format: wgpu::VertexFormat::Float4,
], },
label: Some("uniform_bind_group_layout"), // A mat4 takes up 4 vertex slots as it is technically 4 vec4s. We need to define a slot
}); // for each vec4. We don't have to do this in code though.
wgpu::VertexAttributeDescriptor {
offset: mem::size_of::<[f32; 4]>() as wgpu::BufferAddress,
shader_location: 6,
format: wgpu::VertexFormat::Float4,
},
wgpu::VertexAttributeDescriptor {
offset: mem::size_of::<[f32; 8]>() as wgpu::BufferAddress,
shader_location: 7,
format: wgpu::VertexFormat::Float4,
},
wgpu::VertexAttributeDescriptor {
offset: mem::size_of::<[f32; 12]>() as wgpu::BufferAddress,
shader_location: 8,
format: wgpu::VertexFormat::Float4,
},
],
}
}
}
```
let uniform_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { We need to add this descriptor to the render pipeline so that we can use it when we render.
layout: &uniform_bind_group_layout,
entries: &[ ```rust
// ... let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
// NEW! // ...
wgpu::BindGroupEntry { vertex_state: wgpu::VertexStateDescriptor {
binding: 1, index_format: wgpu::IndexFormat::Uint16,
resource: wgpu::BindingResource::Buffer(instance_buffer.slice(..)) // UPDATED!
}, vertex_buffers: &[Vertex::desc(), InstanceRaw::desc()],
], },
label: Some("uniform_bind_group"), // ...
}); });
``` ```
@ -177,13 +196,15 @@ Self {
} }
``` ```
The last change we need to make is in the `render()` method. We need to change the range we're using in `draw_indexed()` to include the number of instances. The last change we need to make is in the `render()` method. We need to bind our `instance_buffer` and we need to change the range we're using in `draw_indexed()` to include the number of instances.
```rust ```rust
render_pass.set_pipeline(&self.render_pipeline); render_pass.set_pipeline(&self.render_pipeline);
render_pass.set_bind_group(0, &self.diffuse_bind_group, &[]); render_pass.set_bind_group(0, &self.diffuse_bind_group, &[]);
render_pass.set_bind_group(1, &self.uniform_bind_group, &[]); render_pass.set_bind_group(1, &self.uniform_bind_group, &[]);
render_pass.set_vertex_buffer(0, &self.vertex_buffer.slice(..)); render_pass.set_vertex_buffer(0, &self.vertex_buffer.slice(..));
// NEW!
render_pass.set_vertex_buffer(1, self.instance_buffer.slice(..));
render_pass.set_index_buffer(&self.index_buffer.slice(..)); render_pass.set_index_buffer(&self.index_buffer.slice(..));
// UPDATED! // UPDATED!
render_pass.draw_indexed(0..self.num_indices, 0, 0..self.instances.len() as _); render_pass.draw_indexed(0..self.num_indices, 0, 0..self.instances.len() as _);
@ -191,37 +212,26 @@ render_pass.draw_indexed(0..self.num_indices, 0, 0..self.instances.len() as _);
<div class="warning"> <div class="warning">
Make sure if you add new instances to the `Vec` that you recreate the `instance_buffer` and as well as `uniform_bind_group`, otherwise your new instances won't show up correctly. Make sure if you add new instances to the `Vec`, that you recreate the `instance_buffer` and as well as `uniform_bind_group`, otherwise your new instances won't show up correctly.
</div> </div>
## Storage Buffers We need to reference our new matrix in `shader.vert` so that we can use it for our instances. Add the following to the top of `shader.vert`.
When we modified `uniform_bind_group_layout`, we specified that our `instance_buffer` would be of type `wgpu::BindingType::StorageBuffer`. A storage buffer functions like an array that persists between shader invocations. Let's take a look at what it looks like in `shader.vert`.
```glsl ```glsl
layout(location=5) in mat4 model_matrix; layout(location=5) in mat4 model_matrix;
``` ```
We declare a storage buffer in a very similar way to how we declare a uniform block. The only real difference is that we use the `buffer` keyword. We can then use `model_matrix` to position our models in the scene. But how do we know what instance to use? We'll apply the `model_matrix` before we apply `u_view_proj`. We do this because the `u_view_proj` changes the coordinate system from `world space` to `camera space`. Our `model_matrix` is a `world space` transformation, so we don't want to be in `camera space` when using it.
## gl_InstanceIndex
This GLSL variable lets us specify what instance we want to use. We can use the `gl_InstanceIndex` to index our `model_matrix` buffer to get the matrix for the current model.
```glsl ```glsl
void main() { void main() {
v_tex_coords = a_tex_coords; // UPDATED! v_tex_coords = a_tex_coords;
// UPDATED!
gl_Position = u_view_proj * model_matrix * vec4(a_position, 1.0); gl_Position = u_view_proj * model_matrix * vec4(a_position, 1.0);
} }
``` ```
<div class="note">
The value of `gl_InstanceIndex` is based on the range passed to the `instances` parameter of `draw_indexed`. Using `3..instances.len() as _` would mean that the 1st-3rd instances would be skipped.
</div>
With all that done, we should have a forest of trees! With all that done, we should have a forest of trees!
![./forest.png](./forest.png) ![./forest.png](./forest.png)

@ -31,7 +31,7 @@ To make *uniform buffers* portable they have to be std140 and not std430.
*Uniform structs* have to be std140. *Uniform structs* have to be std140.
*Storage structs* have to be std430. *Storage structs* have to be std430.
*Storage buffers* for compute shaders can be std140 oder std430. *Storage buffers* for compute shaders can be std140 or std430.
## std140 (since GLSL 1.4, OpenGL 3.1) ## std140 (since GLSL 1.4, OpenGL 3.1)
@ -45,7 +45,7 @@ Struct:
- determine the member with the largest alignment and lets name it `max_member_align` - determine the member with the largest alignment and lets name it `max_member_align`
- the alignment of the array is maximum(`max_member_align`, 16) - the alignment of the array is maximum(`max_member_align`, 16)
### crates to make yuor struct compatible with std140 ### crates to make your struct compatible with std140
[glsl_layout](https://github.com/rustgd/glsl-layout) [glsl_layout](https://github.com/rustgd/glsl-layout)
[crevice](https://github.com/LPGhatguy/crevice) [crevice](https://github.com/LPGhatguy/crevice)
@ -69,6 +69,6 @@ Struct
---- ----
## memory qualifiers <!-- ## memory qualifiers
TODO readonly, writeonly, restrict TODO readonly, writeonly, restrict -->

Loading…
Cancel
Save