@ -60,33 +60,31 @@ let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescrip
});
```
With all that in place we need a model to render. If you have one already that's great, but I've supplied a [zip file](https://github.com/sotrh/learn-wgpu/blob/master/code/beginner/tutorial9-models/src/res/cube.zip) with the model and all of it's textures. We're going to put this model in a new `res` folder.
With all that in place we need a model to render. If you have one already that's great, but I've supplied a [zip file](https://github.com/sotrh/learn-wgpu/blob/master/code/beginner/tutorial9-models/src/res/cube.zip) with the model and all of it's textures. We're going to put this model in a new `res` folder next to the existing `src` folder.
Speaking of textures, let's add a `load()` method to `Texture` in `texture.rs`.
## Accessing files in the res folder
```rust
use std::path::Path;
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`, but our program will break if we try to run the executable generated by cargo directly. This is because the running executable is in charge of setting the current working directory.
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.
```rust
// This tells cargo to rerun this script if something in /res/ changes.
The `load` method will be useful when we load the textures for our models, as `include_bytes!` requires that we know the name of the file at compile time which we can't really guarantee with model textures.
<divclass="note">
While we're at it let's import `texture.rs` in `model.rs`.
The `OUT_DIR` is an environment variable that cargo uses to specify where our application will be built.
```rust
use crate::texture;
```
</div>
## Loading models with TOBJ
@ -120,6 +118,39 @@ pub struct Mesh {
The `Material` is pretty simple, it's just the name and one texture. Our cube obj actually has 2 textures, but one is a normal map, and we'll get to those [later](../../intermediate/normal-mapping). The name is more for debugging purposes.
Speaking of textures, we'll need to add a `load()` method to `Texture` in `texture.rs`.
The `load` method will be useful when we load the textures for our models, as `include_bytes!` requires that we know the name of the file at compile time which we can't really guarantee with model textures.
While we're at it let's import `texture.rs` in `model.rs`.
```rust
use crate::texture;
```
We also need to make a subtle change on `from_image()` method in `texture.rs`. PNGs work fine with `as_rgba8()`, as they have an alpha channel. But, JPEGs don't have an alpha channel, and the code would panic if we try to call `as_rgba8()` on the JPEG texture image we are going to use. Instead, we can use `to_rgba()` to handle such an image.
```rust
let rgba = img.to_rgba();
```
`Mesh` holds a vertex buffer, an index buffer, and the number of indices in the mesh. We're using an `usize` for the material. This `usize` will be used to index the `materials` list when it comes time to draw.
With all that out of the way, we can get to loading our model.
@ -128,31 +159,29 @@ With all that out of the way, we can get to loading our model.
@ -378,12 +417,6 @@ let material = &self.obj_model.materials[mesh.material];
render_pass.draw_mesh_instanced(mesh, material, 0..self.instances.len() as u32, &self.uniform_bind_group);
```
We also need to make a subtle change on `from_image()` method in `texture.rs`. PNGs work fine with `as_rgba8()`, as they have an alpha channel. But, JPEGs don't have an alpha channel, and the code would panic if we try to call `as_rgba8()` on the JPEG texture image we are going to use. Instead, we can use `to_rgba()` to handle such an image.
```rust
let rgba = img.to_rgba();
```
With all that in place we should get the following.