tutorials 6-9 migrated

pull/177/head
Ben Hansen 3 years ago
parent f1c7536668
commit b160f28d48

@ -224,31 +224,42 @@ render_pass.draw_indexed(0..self.num_indices, 0, 0..1);
## Using the uniforms in the vertex shader
Modify `shader.vert` to include the following.
Modify the vertex shader to include the following.
```glsl
#version 450
```wgsl
// Vertex shader
layout(location=0) in vec3 a_position;
layout(location=1) in vec2 a_tex_coords;
[[block]] // 1.
struct Uniforms {
view_proj: mat4x4<f32>;
};
[[group(1), binding(0)]] // 2.
var<uniform> uniforms: Uniforms;
layout(location=0) out vec2 v_tex_coords;
struct VertexInput {
[[location(0)]] position: vec3<f32>;
[[location(1)]] tex_coords: vec2<f32>;
};
// NEW!
layout(set=1, binding=0) // 1.
uniform Uniforms {
mat4 u_view_proj; // 2.
struct VertexOutput {
[[builtin(position)]] clip_position: vec4<f32>;
[[location(0)]] tex_coords: vec2<f32>;
};
void main() {
v_tex_coords = a_tex_coords;
gl_Position = u_view_proj * vec4(a_position, 1.0); // 3.
[[stage(vertex)]]
fn main(
model: VertexInput,
) -> VertexOutput {
var out: VertexOutput;
out.tex_coords = model.tex_coords;
out.clip_position = uniforms.view_proj * vec4<f32>(model.position, 1.0); // 3.
return out;
}
```
1. Because we've created a new bind group, we need to specify which one we're using in the shader. The number is determined by our `render_pipeline_layout`. The `texture_bind_group_layout` is listed first, thus it's `set=0`, and `uniform_bind_group` is second, so it's `set=1`.
2. The `uniform` block requires us to specify global identifiers for all the fields we intend to use. It's important to only specify fields that are actually in our uniform buffer, as trying to access data that isn't there may lead to undefined behavior.
3. Multiplication order is important when it comes to matrices. The vector always goes on the right, and the matrices gone on the left in order of importance.
1. The according to the [WGSL Spec](https://gpuweb.github.io/gpuweb/wgsl/), The block decorator indicates this structure type represents the contents of a buffer resource occupying a single binding slot in the shaders resource interface. Any structure used as a `uniform` must be annotated with `[[block]]`
2. Because we've created a new bind group, we need to specify which one we're using in the shader. The number is determined by our `render_pipeline_layout`. The `texture_bind_group_layout` is listed first, thus it's `group(0)`, and `uniform_bind_group` is second, so it's `group(1)`.
3. Multiplication order is important when it comes to matrices. The vector goes on the right, and the matrices gone on the left in order of importance.
## A controller for our camera

@ -44,7 +44,7 @@ A `Quaternion` is a mathematical structure often used to represent rotation. The
</div>
Using these values directly in the shader would be a pain as quaternions don't have a GLSL analog. I don't feel like writing the math in the shader, so we'll convert the `Instance` data into a matrix and store it into a struct called `InstanceRaw`.
Using these values directly in the shader would be a pain as quaternions don't have a WGSL analog. I don't feel like writing the math in the shader, so we'll convert the `Instance` data into a matrix and store it into a struct called `InstanceRaw`.
```rust
// NEW!
@ -218,37 +218,48 @@ Make sure if you add new instances to the `Vec`, that you recreate the `instance
</div>
We need to reference the parts of our new matrix in `shader.vert` so that we can use it for our instances. Add the following to the top of `shader.vert`.
We need to reference the parts of our new matrix in `shader.wgsl` so that we can use it for our instances. Add the following to the top of `shader.wgsl`.
```glsl
layout(location=5) in vec4 model_matrix_0;
layout(location=6) in vec4 model_matrix_1;
layout(location=7) in vec4 model_matrix_2;
layout(location=8) in vec4 model_matrix_3;
```wgsl
struct InstanceInput {
[[location(5)]] model_matrix_0: vec4<f32>;
[[location(6)]] model_matrix_1: vec4<f32>;
[[location(7)]] model_matrix_2: vec4<f32>;
[[location(8)]] model_matrix_3: vec4<f32>;
};
```
We need to reassemble the matrix before we can use it.
```glsl
void main() {
mat4 model_matrix = mat4(
model_matrix_0,
model_matrix_1,
model_matrix_2,
model_matrix_3
```wgsl
[[stage(vertex)]]
fn main(
model: VertexInput,
instance: InstanceInput,
) -> VertexOutput {
let model_matrix = mat4x4<f32>(
instance.model_matrix_0,
instance.model_matrix_1,
instance.model_matrix_2,
instance.model_matrix_3,
);
// Continued...
}
```
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.
We'll apply the `model_matrix` before we apply `uniforms.view_proj`. We do this because the `uniforms.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.
```glsl
void main() {
```wgsl
[[stage(vertex)]]
fn main(
model: VertexInput,
instance: InstanceInput,
) -> VertexOutput {
// ...
v_tex_coords = a_tex_coords;
// UPDATED!
gl_Position = u_view_proj * model_matrix * vec4(a_position, 1.0);
var out: VertexOutput;
out.tex_coords = model.tex_coords;
out.clip_position = uniforms.view_proj * model_matrix * vec4<f32>(model.position, 1.0);
return out;
}
```

@ -79,26 +79,50 @@ With all that in place we need a model to render. If you have one already that's
When cargo builds and runs our program it sets what's known as the current working directory. This directory is usually the folder containing your projects root `Cargo.toml`. The path to our res folder may differ depending on the structure of the project. In the `res` folder for the example code for this section tutorial is at `code/beginner/tutorial9-models/res/`. When loading our model we could use this path, and just append `cube.obj`. This is fine, but if we change our projects structure, our code will break.
We're going to fix that by modifying our build script to copy our `res` folder to where cargo creates our executable, and we'll reference it from there. Add the following lines to `build.rs` after you compile the shaders.
We're going to fix that by modifying our build script to copy our `res` folder to where cargo creates our executable, and we'll reference it from there. Create a file called `build.rs` and add the following:
```rust
// This tells cargo to rerun this script if something in /res/ changes.
println!("cargo:rerun-if-changed=res/*");
let out_dir = env::var("OUT_DIR")?;
let mut copy_options = CopyOptions::new();
copy_options.overwrite = true;
let mut paths_to_copy = Vec::new();
paths_to_copy.push("res/");
copy_items(&paths_to_copy, out_dir, &copy_options)?;
use anyhow::*;
use fs_extra::copy_items;
use fs_extra::dir::CopyOptions;
use std::env;
fn main() -> Result<()> {
// This tells cargo to rerun this script if something in /res/ changes.
println!("cargo:rerun-if-changed=res/*");
let out_dir = env::var("OUT_DIR")?;
let mut copy_options = CopyOptions::new();
copy_options.overwrite = true;
let mut paths_to_copy = Vec::new();
paths_to_copy.push("res/");
copy_items(&paths_to_copy, out_dir, &copy_options)?;
Ok(())
}
```
<div class="note">
Make sure to put `build.rs` in the same folder as the `Cargo.toml`. If you don't, cargo won't run it when your crate builds.
</div>
<div class="note">
The `OUT_DIR` is an environment variable that cargo uses to specify where our application will be built.
</div>
You'll need to modify your `Cargo.toml` for this to work properly. Add the following below your `[dependencies]` block.
```toml
[build-dependencies]
anyhow = "1.0"
fs_extra = "1.2"
glob = "0.3"
```
## Loading models with TOBJ

Loading…
Cancel
Save