You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
learn-wgpu/beginner/tutorial9-models/index.html

426 lines
121 KiB
HTML

<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Model Loading | Learn Wgpu</title>
<meta name="generator" content="VuePress 1.9.10">
<meta name="description" content="">
<link rel="preload" href="/learn-wgpu/assets/css/0.styles.81cb5453.css" as="style"><link rel="preload" href="/learn-wgpu/assets/js/app.8ee4646c.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/2.2ef7287a.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/1.eaeeb819.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/36.2e1d433e.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/33.945dce62.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/37.5ecf7ce2.js" as="script"><link rel="prefetch" href="/learn-wgpu/assets/js/10.baf5d1fe.js"><link rel="prefetch" href="/learn-wgpu/assets/js/11.b8633c49.js"><link rel="prefetch" href="/learn-wgpu/assets/js/12.0b8835f1.js"><link rel="prefetch" href="/learn-wgpu/assets/js/13.af1bbe85.js"><link rel="prefetch" href="/learn-wgpu/assets/js/14.626c7cb3.js"><link rel="prefetch" href="/learn-wgpu/assets/js/15.5a8ea302.js"><link rel="prefetch" href="/learn-wgpu/assets/js/16.f4e8226b.js"><link rel="prefetch" href="/learn-wgpu/assets/js/17.ea2d3b52.js"><link rel="prefetch" href="/learn-wgpu/assets/js/18.4eb59bb5.js"><link rel="prefetch" href="/learn-wgpu/assets/js/19.48960e96.js"><link rel="prefetch" href="/learn-wgpu/assets/js/20.a01dc53f.js"><link rel="prefetch" href="/learn-wgpu/assets/js/21.5e81f33c.js"><link rel="prefetch" href="/learn-wgpu/assets/js/22.caf73498.js"><link rel="prefetch" href="/learn-wgpu/assets/js/23.ddff5db2.js"><link rel="prefetch" href="/learn-wgpu/assets/js/24.9ed2104b.js"><link rel="prefetch" href="/learn-wgpu/assets/js/25.1676676b.js"><link rel="prefetch" href="/learn-wgpu/assets/js/26.01a5696a.js"><link rel="prefetch" href="/learn-wgpu/assets/js/27.3b14c055.js"><link rel="prefetch" href="/learn-wgpu/assets/js/28.d1a4ff6c.js"><link rel="prefetch" href="/learn-wgpu/assets/js/29.ea2d6bbf.js"><link rel="prefetch" href="/learn-wgpu/assets/js/3.80d94795.js"><link rel="prefetch" href="/learn-wgpu/assets/js/30.f08bd92d.js"><link rel="prefetch" href="/learn-wgpu/assets/js/31.fbafea68.js"><link rel="prefetch" href="/learn-wgpu/assets/js/32.3d0e544d.js"><link rel="prefetch" href="/learn-wgpu/assets/js/34.0fe8e5e4.js"><link rel="prefetch" href="/learn-wgpu/assets/js/35.7c607f94.js"><link rel="prefetch" href="/learn-wgpu/assets/js/38.b0253733.js"><link rel="prefetch" href="/learn-wgpu/assets/js/39.73123b03.js"><link rel="prefetch" href="/learn-wgpu/assets/js/4.ff267fdb.js"><link rel="prefetch" href="/learn-wgpu/assets/js/40.30864a0f.js"><link rel="prefetch" href="/learn-wgpu/assets/js/41.0b7d478f.js"><link rel="prefetch" href="/learn-wgpu/assets/js/42.4caac867.js"><link rel="prefetch" href="/learn-wgpu/assets/js/43.991fa7d2.js"><link rel="prefetch" href="/learn-wgpu/assets/js/44.27513d85.js"><link rel="prefetch" href="/learn-wgpu/assets/js/45.2ea5b108.js"><link rel="prefetch" href="/learn-wgpu/assets/js/46.61045c81.js"><link rel="prefetch" href="/learn-wgpu/assets/js/47.ea92b080.js"><link rel="prefetch" href="/learn-wgpu/assets/js/48.cc620f49.js"><link rel="prefetch" href="/learn-wgpu/assets/js/49.6426e080.js"><link rel="prefetch" href="/learn-wgpu/assets/js/5.250d79d3.js"><link rel="prefetch" href="/learn-wgpu/assets/js/50.05fd19ce.js"><link rel="prefetch" href="/learn-wgpu/assets/js/51.47410096.js"><link rel="prefetch" href="/learn-wgpu/assets/js/52.ecbe158e.js"><link rel="prefetch" href="/learn-wgpu/assets/js/53.8c976652.js"><link rel="prefetch" href="/learn-wgpu/assets/js/54.daee63ce.js"><link rel="prefetch" href="/learn-wgpu/assets/js/55.3799ddaa.js"><link rel="prefetch" href="/learn-wgpu/assets/js/56.74e5dcef.js"><link rel="prefetch" href="/learn-wgpu/assets/js/57.9cdfcb79.js"><link rel="prefetch" href="/learn-wgpu/assets/js/58.35b75a7b.js"><link rel="prefetch" href="/learn-wgpu/assets/js/59.5dd82339.js"><link rel="prefetch" href="/learn-wgpu/assets/js/60.1ced8124.js"><link rel="prefetch" href="/learn-wgpu/assets/js/61.f10516d3.js"><link rel="prefetch" href="/learn-wgpu/assets/js/62.fc721fd9.js"><link rel="prefetch" href="/learn-wgpu/assets/js/63.68526f40.js"><link rel="prefetch" href="/learn-wgpu/assets/js/64.b9a310af.js"><link rel="prefetch" href="/learn-wgpu/assets/js/65.e23a076d.js"><link rel="prefetch" href="/learn-wgpu/assets/js/66.19a033d1.js"><link rel="prefetch" href="/learn-wgpu/assets/js/67.ab338058.js"><link rel="prefetch" href="/learn-wgpu/assets/js/68.d785413d.js"><link rel="prefetch" href="/learn-wgpu/assets/js/8.2c0d831a.js"><link rel="prefetch" href="/learn-wgpu/assets/js/9.985bc61a.js"><link rel="prefetch" href="/learn-wgpu/assets/js/vendors~docsearch.efa6f8ef.js">
<link rel="stylesheet" href="/learn-wgpu/assets/css/0.styles.81cb5453.css">
</head>
<body>
<div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="inner"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/learn-wgpu/" class="home-link router-link-active"><!----> <span class="site-name">Learn Wgpu</span></a> <div class="links"><!----> <div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div></div></div></header> <div class="sidebar-mask"></div> <div class="docs-layout"><aside class="sidebar"><!----> <ul class="sidebar-links"><li><a href="/learn-wgpu/" aria-current="page" class="sidebar-link">Introduction</a></li><li><section class="sidebar-group depth-0"><p class="sidebar-heading open"><span>Beginner</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/learn-wgpu/beginner/tutorial1-window/" class="sidebar-link">Dependencies and the window</a></li><li><a href="/learn-wgpu/beginner/tutorial2-surface/" class="sidebar-link">The Surface</a></li><li><a href="/learn-wgpu/beginner/tutorial3-pipeline/" class="sidebar-link">The Pipeline</a></li><li><a href="/learn-wgpu/beginner/tutorial4-buffer/" class="sidebar-link">Buffers and Indices</a></li><li><a href="/learn-wgpu/beginner/tutorial5-textures/" class="sidebar-link">Textures and bind groups</a></li><li><a href="/learn-wgpu/beginner/tutorial6-uniforms/" class="sidebar-link">Uniform buffers and a 3d camera</a></li><li><a href="/learn-wgpu/beginner/tutorial7-instancing/" class="sidebar-link">Instancing</a></li><li><a href="/learn-wgpu/beginner/tutorial8-depth/" class="sidebar-link">The Depth Buffer</a></li><li><a href="/learn-wgpu/beginner/tutorial9-models/" aria-current="page" class="active sidebar-link">Model Loading</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/learn-wgpu/beginner/tutorial9-models/#accessing-files-in-the-res-folder" class="sidebar-link">Accessing files in the res folder</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/beginner/tutorial9-models/#accessing-files-from-wasm" class="sidebar-link">Accessing files from WASM</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/beginner/tutorial9-models/#loading-models-with-tobj" class="sidebar-link">Loading models with TOBJ</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/beginner/tutorial9-models/#rendering-a-mesh" class="sidebar-link">Rendering a mesh</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/beginner/tutorial9-models/#using-the-correct-textures" class="sidebar-link">Using the correct textures</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/beginner/tutorial9-models/#rendering-the-entire-model" class="sidebar-link">Rendering the entire model</a></li></ul></li></ul></section></li><li><section class="sidebar-group depth-0"><p class="sidebar-heading"><span>Intermediate</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/learn-wgpu/intermediate/tutorial10-lighting/" class="sidebar-link">Working with Lights</a></li><li><a href="/learn-wgpu/intermediate/tutorial11-normals/" class="sidebar-link">Normal Mapping</a></li><li><a href="/learn-wgpu/intermediate/tutorial12-camera/" class="sidebar-link">A Better Camera</a></li><li><a href="/learn-wgpu/intermediate/tutorial13-hdr/" class="sidebar-link">High Dynamic Range Rendering</a></li></ul></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>Showcase</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>News</span> <span class="arrow right"></span></p> <!----></section></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><h1 id="model-loading"><a href="#model-loading" class="header-anchor">#</a> Model Loading</h1> <p>Up to this point we've been creating our models manually. While this is an acceptable way to do this, it's really slow if we want to include complex models with lots of polygons. Because of this, we're going to modify our code to leverage the <code>.obj</code> model format so that we can create a model in software such as blender and display it in our code.</p> <p>Our <code>lib.rs</code> file is getting pretty cluttered, let's create a <code>model.rs</code> file that we can put our model loading code into.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token comment">// model.rs</span>
<span class="token keyword">pub</span> <span class="token keyword">trait</span> <span class="token type-definition class-name">Vertex</span> <span class="token punctuation">{</span>
<span class="token keyword">fn</span> <span class="token function-definition function">desc</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">VertexBufferLayout</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">'static</span><span class="token operator">&gt;</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token attribute attr-name">#[repr(C)]</span>
<span class="token attribute attr-name">#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]</span>
<span class="token keyword">pub</span> <span class="token keyword">struct</span> <span class="token type-definition class-name">ModelVertex</span> <span class="token punctuation">{</span>
<span class="token keyword">pub</span> position<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token keyword">f32</span><span class="token punctuation">;</span> <span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token keyword">pub</span> tex_coords<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token keyword">f32</span><span class="token punctuation">;</span> <span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token keyword">pub</span> normal<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token keyword">f32</span><span class="token punctuation">;</span> <span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token keyword">impl</span> <span class="token class-name">Vertex</span> <span class="token keyword">for</span> <span class="token class-name">ModelVertex</span> <span class="token punctuation">{</span>
<span class="token keyword">fn</span> <span class="token function-definition function">desc</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">VertexBufferLayout</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">'static</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
<span class="token macro property">todo!</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>You'll notice a couple of things here. In <code>lib.rs</code> we had <code>Vertex</code> as a struct, here we're using a trait. We could have multiple vertex types (model, UI, instance data, etc.). Making <code>Vertex</code> a trait will allow us to abstract out the <code>VertexBufferLayout</code> creation code to make creating <code>RenderPipeline</code>s simpler.</p> <p>Another thing to mention is the <code>normal</code> field in <code>ModelVertex</code>. We won't use this until we talk about lighting, but will add it to the struct for now.</p> <p>Let's define our <code>VertexBufferLayout</code>.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">impl</span> <span class="token class-name">Vertex</span> <span class="token keyword">for</span> <span class="token class-name">ModelVertex</span> <span class="token punctuation">{</span>
<span class="token keyword">fn</span> <span class="token function-definition function">desc</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">VertexBufferLayout</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">'static</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span></span>mem<span class="token punctuation">;</span>
<span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">VertexBufferLayout</span> <span class="token punctuation">{</span>
array_stride<span class="token punctuation">:</span> <span class="token namespace">mem<span class="token punctuation">::</span></span><span class="token function">size_of</span><span class="token punctuation">::</span><span class="token operator">&lt;</span><span class="token class-name">ModelVertex</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">as</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BufferAddress</span><span class="token punctuation">,</span>
step_mode<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">VertexStepMode</span><span class="token punctuation">::</span><span class="token class-name">Vertex</span><span class="token punctuation">,</span>
attributes<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token punctuation">[</span>
<span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">VertexAttribute</span> <span class="token punctuation">{</span>
offset<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
shader_location<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
format<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">VertexFormat</span><span class="token punctuation">::</span><span class="token class-name">Float32x3</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">VertexAttribute</span> <span class="token punctuation">{</span>
offset<span class="token punctuation">:</span> <span class="token namespace">mem<span class="token punctuation">::</span></span><span class="token function">size_of</span><span class="token punctuation">::</span><span class="token operator">&lt;</span><span class="token punctuation">[</span><span class="token keyword">f32</span><span class="token punctuation">;</span> <span class="token number">3</span><span class="token punctuation">]</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">as</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BufferAddress</span><span class="token punctuation">,</span>
shader_location<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span>
format<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">VertexFormat</span><span class="token punctuation">::</span><span class="token class-name">Float32x2</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">VertexAttribute</span> <span class="token punctuation">{</span>
offset<span class="token punctuation">:</span> <span class="token namespace">mem<span class="token punctuation">::</span></span><span class="token function">size_of</span><span class="token punctuation">::</span><span class="token operator">&lt;</span><span class="token punctuation">[</span><span class="token keyword">f32</span><span class="token punctuation">;</span> <span class="token number">5</span><span class="token punctuation">]</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">as</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BufferAddress</span><span class="token punctuation">,</span>
shader_location<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">,</span>
format<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">VertexFormat</span><span class="token punctuation">::</span><span class="token class-name">Float32x3</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>This is basically the same as the original <code>VertexBufferLayout</code>, but we added a <code>VertexAttribute</code> for the <code>normal</code>. Remove the <code>Vertex</code> struct in <code>lib.rs</code> as we won't need it anymore, and use our new <code>Vertex</code> from <code>model</code> for the <code>RenderPipeline</code>.</p> <p>We will also remove our homemade <code>vertex_buffer</code>, <code>index_buffer</code> and <code>num_indices</code>.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">let</span> render_pipeline <span class="token operator">=</span> device<span class="token punctuation">.</span><span class="token function">create_render_pipeline</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">RenderPipelineDescriptor</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
vertex<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">VertexState</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
buffers<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token punctuation">[</span><span class="token namespace">model<span class="token punctuation">::</span></span><span class="token class-name">ModelVertex</span><span class="token punctuation">::</span><span class="token function">desc</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token class-name">InstanceRaw</span><span class="token punctuation">::</span><span class="token function">desc</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token comment">// ...</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>Since the <code>desc</code> method is implemented on the <code>Vertex</code> trait, the trait needs to be imported before the method will be accessible. Put the import towards the top of the file with the others.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">use</span> <span class="token namespace">model<span class="token punctuation">::</span></span><span class="token class-name">Vertex</span><span class="token punctuation">;</span>
</code></pre></div><p>With all that in place, we need a model to render. If you have one already that's great, but I've supplied a <a href="https://github.com/sotrh/learn-wgpu/blob/master/code/beginner/tutorial9-models/res/cube.zip" target="_blank" rel="noopener noreferrer">zip file<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> with the model and all of its textures. We're going to put this model in a new <code>res</code> folder next to the existing <code>src</code> folder.</p> <h2 id="accessing-files-in-the-res-folder"><a href="#accessing-files-in-the-res-folder" class="header-anchor">#</a> Accessing files in the res folder</h2> <p>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 project's root <code>Cargo.toml</code>. The path to our res folder may differ depending on the structure of the project. In the <code>res</code> folder for the example code for this section tutorial is at <code>code/beginner/tutorial9-models/res/</code>. When loading our model we could use this path, and just append <code>cube.obj</code>. This is fine, but if we change our project's structure, our code will break.</p> <p>We're going to fix that by modifying our build script to copy our <code>res</code> folder to where cargo creates our executable, and we'll reference it from there. Create a file called <code>build.rs</code> and add the following:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">use</span> <span class="token namespace">anyhow<span class="token punctuation">::</span></span><span class="token operator">*</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token namespace">fs_extra<span class="token punctuation">::</span></span>copy_items<span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token namespace">fs_extra<span class="token punctuation">::</span>dir<span class="token punctuation">::</span></span><span class="token class-name">CopyOptions</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span></span>env<span class="token punctuation">;</span>
<span class="token keyword">fn</span> <span class="token function-definition function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">Result</span><span class="token operator">&lt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
<span class="token comment">// This tells cargo to rerun this script if something in /res/ changes.</span>
<span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">&quot;cargo:rerun-if-changed=res/*&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> out_dir <span class="token operator">=</span> <span class="token namespace">env<span class="token punctuation">::</span></span><span class="token function">var</span><span class="token punctuation">(</span><span class="token string">&quot;OUT_DIR&quot;</span><span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> <span class="token keyword">mut</span> copy_options <span class="token operator">=</span> <span class="token class-name">CopyOptions</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
copy_options<span class="token punctuation">.</span>overwrite <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> <span class="token keyword">mut</span> paths_to_copy <span class="token operator">=</span> <span class="token class-name">Vec</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
paths_to_copy<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token string">&quot;res/&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">copy_items</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>paths_to_copy<span class="token punctuation">,</span> out_dir<span class="token punctuation">,</span> <span class="token operator">&amp;</span>copy_options<span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">;</span>
<span class="token class-name">Ok</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre></div><div class="note"><p>Make sure to put <code>build.rs</code> in the same folder as the <code>Cargo.toml</code>. If you don't, cargo won't run it when your crate builds.</p></div> <div class="note"><p>The <code>OUT_DIR</code> is an environment variable that cargo uses to specify where our application will be built.</p></div> <p>You'll need to modify your <code>Cargo.toml</code> for this to work properly. Add the following below your <code>[dependencies]</code> block.</p> <div class="language-toml extra-class"><pre class="language-toml"><code><span class="token punctuation">[</span><span class="token table class-name">build-dependencies</span><span class="token punctuation">]</span>
<span class="token key property">anyhow</span> <span class="token punctuation">=</span> <span class="token string">&quot;1.0&quot;</span>
<span class="token key property">fs_extra</span> <span class="token punctuation">=</span> <span class="token string">&quot;1.2&quot;</span>
<span class="token key property">glob</span> <span class="token punctuation">=</span> <span class="token string">&quot;0.3&quot;</span>
</code></pre></div><h2 id="accessing-files-from-wasm"><a href="#accessing-files-from-wasm" class="header-anchor">#</a> Accessing files from WASM</h2> <p>By design, you can't access files on a user's filesystem in Web Assembly. Instead, we'll serve those files up using a web serve, and then load those files into our code using an http request. In order to simplify this, let's create a file called <code>resources.rs</code> to handle this for us. We'll create two functions that will load text files and binary files respectively.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span>io<span class="token punctuation">::</span></span><span class="token punctuation">{</span><span class="token class-name">BufReader</span><span class="token punctuation">,</span> <span class="token class-name">Cursor</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token namespace">cfg_if<span class="token punctuation">::</span></span>cfg_if<span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token namespace">wgpu<span class="token punctuation">::</span>util<span class="token punctuation">::</span></span><span class="token class-name">DeviceExt</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token keyword">crate</span><span class="token punctuation">::</span><span class="token punctuation">{</span>model<span class="token punctuation">,</span> texture<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token attribute attr-name">#[cfg(target_arch = <span class="token string">&quot;wasm32&quot;</span>)]</span>
<span class="token keyword">fn</span> <span class="token function-definition function">format_url</span><span class="token punctuation">(</span>file_name<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">str</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token namespace">reqwest<span class="token punctuation">::</span></span><span class="token class-name">Url</span> <span class="token punctuation">{</span>
<span class="token keyword">let</span> window <span class="token operator">=</span> <span class="token namespace">web_sys<span class="token punctuation">::</span></span><span class="token function">window</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> location <span class="token operator">=</span> window<span class="token punctuation">.</span><span class="token function">location</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> <span class="token keyword">mut</span> origin <span class="token operator">=</span> location<span class="token punctuation">.</span><span class="token function">origin</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token operator">!</span>origin<span class="token punctuation">.</span><span class="token function">ends_with</span><span class="token punctuation">(</span><span class="token string">&quot;learn-wgpu&quot;</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
origin <span class="token operator">=</span> <span class="token macro property">format!</span><span class="token punctuation">(</span><span class="token string">&quot;{}/learn-wgpu&quot;</span><span class="token punctuation">,</span> origin<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">let</span> base <span class="token operator">=</span> <span class="token namespace">reqwest<span class="token punctuation">::</span></span><span class="token class-name">Url</span><span class="token punctuation">::</span><span class="token function">parse</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token macro property">format!</span><span class="token punctuation">(</span><span class="token string">&quot;{}/&quot;</span><span class="token punctuation">,</span> origin<span class="token punctuation">,</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
base<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>file_name<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token keyword">pub</span> <span class="token keyword">async</span> <span class="token keyword">fn</span> <span class="token function-definition function">load_string</span><span class="token punctuation">(</span>file_name<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">str</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token namespace">anyhow<span class="token punctuation">::</span></span><span class="token class-name">Result</span><span class="token operator">&lt;</span><span class="token class-name">String</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
<span class="token macro property">cfg_if!</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token attribute attr-name">#[cfg(target_arch = <span class="token string">&quot;wasm32&quot;</span>)]</span> <span class="token punctuation">{</span>
<span class="token keyword">let</span> url <span class="token operator">=</span> <span class="token function">format_url</span><span class="token punctuation">(</span>file_name<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> txt <span class="token operator">=</span> <span class="token namespace">reqwest<span class="token punctuation">::</span></span><span class="token function">get</span><span class="token punctuation">(</span>url<span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token keyword">await</span><span class="token operator">?</span>
<span class="token punctuation">.</span><span class="token function">text</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token keyword">await</span><span class="token operator">?</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
<span class="token keyword">let</span> path <span class="token operator">=</span> <span class="token namespace">std<span class="token punctuation">::</span>path<span class="token punctuation">::</span></span><span class="token class-name">Path</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token macro property">env!</span><span class="token punctuation">(</span><span class="token string">&quot;OUT_DIR&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">&quot;res&quot;</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>file_name<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> txt <span class="token operator">=</span> <span class="token namespace">std<span class="token punctuation">::</span>fs<span class="token punctuation">::</span></span><span class="token function">read_to_string</span><span class="token punctuation">(</span>path<span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token class-name">Ok</span><span class="token punctuation">(</span>txt<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token keyword">pub</span> <span class="token keyword">async</span> <span class="token keyword">fn</span> <span class="token function-definition function">load_binary</span><span class="token punctuation">(</span>file_name<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">str</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token namespace">anyhow<span class="token punctuation">::</span></span><span class="token class-name">Result</span><span class="token operator">&lt;</span><span class="token class-name">Vec</span><span class="token operator">&lt;</span><span class="token keyword">u8</span><span class="token operator">&gt;&gt;</span> <span class="token punctuation">{</span>
<span class="token macro property">cfg_if!</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token attribute attr-name">#[cfg(target_arch = <span class="token string">&quot;wasm32&quot;</span>)]</span> <span class="token punctuation">{</span>
<span class="token keyword">let</span> url <span class="token operator">=</span> <span class="token function">format_url</span><span class="token punctuation">(</span>file_name<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> data <span class="token operator">=</span> <span class="token namespace">reqwest<span class="token punctuation">::</span></span><span class="token function">get</span><span class="token punctuation">(</span>url<span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token keyword">await</span><span class="token operator">?</span>
<span class="token punctuation">.</span><span class="token function">bytes</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token keyword">await</span><span class="token operator">?</span>
<span class="token punctuation">.</span><span class="token function">to_vec</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
<span class="token keyword">let</span> path <span class="token operator">=</span> <span class="token namespace">std<span class="token punctuation">::</span>path<span class="token punctuation">::</span></span><span class="token class-name">Path</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token macro property">env!</span><span class="token punctuation">(</span><span class="token string">&quot;OUT_DIR&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">&quot;res&quot;</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>file_name<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> data <span class="token operator">=</span> <span class="token namespace">std<span class="token punctuation">::</span>fs<span class="token punctuation">::</span></span><span class="token function">read</span><span class="token punctuation">(</span>path<span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token class-name">Ok</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre></div><div class="note"><p>We're using <code>OUT_DIR</code> on desktop to get to our <code>res</code> folder.</p></div> <p>I'm using <a href="https://docs.rs/reqwest" target="_blank" rel="noopener noreferrer">reqwest<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> to handle loading the requests when using WASM. Add the following to the Cargo.toml:</p> <div class="language-toml extra-class"><pre class="language-toml"><code><span class="token punctuation">[</span><span class="token table class-name">target.'cfg(target_arch = &quot;wasm32&quot;)'.dependencies</span><span class="token punctuation">]</span>
<span class="token comment"># Other dependencies</span>
<span class="token key property">reqwest</span> <span class="token punctuation">=</span> <span class="token punctuation">{</span> <span class="token key property">version</span> <span class="token punctuation">=</span> <span class="token string">&quot;0.11&quot;</span> <span class="token punctuation">}</span>
</code></pre></div><p>We'll also need to add the <code>Location</code> feature to <code>web-sys</code>:</p> <div class="language-toml extra-class"><pre class="language-toml"><code><span class="token key property">web-sys</span> <span class="token punctuation">=</span> <span class="token punctuation">{</span> <span class="token key property">version</span> <span class="token punctuation">=</span> <span class="token string">&quot;0.3&quot;</span><span class="token punctuation">,</span> <span class="token key property">features</span> <span class="token punctuation">=</span> <span class="token punctuation">[</span>
<span class="token string">&quot;Document&quot;</span><span class="token punctuation">,</span>
<span class="token string">&quot;Window&quot;</span><span class="token punctuation">,</span>
<span class="token string">&quot;Element&quot;</span><span class="token punctuation">,</span>
<span class="token string">&quot;Location&quot;</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">}</span>
</code></pre></div><p>Make sure to add <code>resources</code> as a module in <code>lib.rs</code>:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">mod</span> <span class="token module-declaration namespace">resources</span><span class="token punctuation">;</span>
</code></pre></div><h2 id="loading-models-with-tobj"><a href="#loading-models-with-tobj" class="header-anchor">#</a> Loading models with TOBJ</h2> <p>We're going to use the <a href="https://docs.rs/tobj/3.0/tobj/" target="_blank" rel="noopener noreferrer">tobj<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> library to load our model. Let's add it to our <code>Cargo.toml</code>.</p> <div class="language-toml extra-class"><pre class="language-toml"><code><span class="token punctuation">[</span><span class="token table class-name">dependencies</span><span class="token punctuation">]</span>
<span class="token comment"># other dependencies...</span>
<span class="token key property">tobj</span> <span class="token punctuation">=</span> <span class="token punctuation">{</span> <span class="token key property">version</span> <span class="token punctuation">=</span> <span class="token string">&quot;3.2.1&quot;</span><span class="token punctuation">,</span> <span class="token key property">features</span> <span class="token punctuation">=</span> <span class="token punctuation">[</span>
<span class="token string">&quot;async&quot;</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">}</span>
</code></pre></div><p>Before we can load our model though, we need somewhere to put it.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token comment">// model.rs</span>
<span class="token keyword">pub</span> <span class="token keyword">struct</span> <span class="token type-definition class-name">Model</span> <span class="token punctuation">{</span>
<span class="token keyword">pub</span> meshes<span class="token punctuation">:</span> <span class="token class-name">Vec</span><span class="token operator">&lt;</span><span class="token class-name">Mesh</span><span class="token operator">&gt;</span><span class="token punctuation">,</span>
<span class="token keyword">pub</span> materials<span class="token punctuation">:</span> <span class="token class-name">Vec</span><span class="token operator">&lt;</span><span class="token class-name">Material</span><span class="token operator">&gt;</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
</code></pre></div><p>You'll notice that our <code>Model</code> struct has a <code>Vec</code> for the <code>meshes</code>, and for <code>materials</code>. This is important as our obj file can include multiple meshes and materials. We still need to create the <code>Mesh</code> and <code>Material</code> classes, so let's do that.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">pub</span> <span class="token keyword">struct</span> <span class="token type-definition class-name">Material</span> <span class="token punctuation">{</span>
<span class="token keyword">pub</span> name<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">,</span>
<span class="token keyword">pub</span> diffuse_texture<span class="token punctuation">:</span> <span class="token namespace">texture<span class="token punctuation">::</span></span><span class="token class-name">Texture</span><span class="token punctuation">,</span>
<span class="token keyword">pub</span> bind_group<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BindGroup</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token keyword">pub</span> <span class="token keyword">struct</span> <span class="token type-definition class-name">Mesh</span> <span class="token punctuation">{</span>
<span class="token keyword">pub</span> name<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">,</span>
<span class="token keyword">pub</span> vertex_buffer<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Buffer</span><span class="token punctuation">,</span>
<span class="token keyword">pub</span> index_buffer<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Buffer</span><span class="token punctuation">,</span>
<span class="token keyword">pub</span> num_elements<span class="token punctuation">:</span> <span class="token keyword">u32</span><span class="token punctuation">,</span>
<span class="token keyword">pub</span> material<span class="token punctuation">:</span> <span class="token keyword">usize</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
</code></pre></div><p>The <code>Material</code> 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 <a href="../../intermediate/tutorial11-normals">later</a>. The name is more for debugging purposes.</p> <p>Speaking of textures, we'll need to add a function to load a <code>Texture</code> in <code>resources.rs</code>.</p> <div class="language-rust extra-class"><pre class="language-rust"><code>
<span class="token keyword">pub</span> <span class="token keyword">async</span> <span class="token keyword">fn</span> <span class="token function-definition function">load_texture</span><span class="token punctuation">(</span>
file_name<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">str</span><span class="token punctuation">,</span>
device<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Device</span><span class="token punctuation">,</span>
queue<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Queue</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token namespace">anyhow<span class="token punctuation">::</span></span><span class="token class-name">Result</span><span class="token operator">&lt;</span><span class="token namespace">texture<span class="token punctuation">::</span></span><span class="token class-name">Texture</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">let</span> data <span class="token operator">=</span> <span class="token function">load_binary</span><span class="token punctuation">(</span>file_name<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token keyword">await</span><span class="token operator">?</span><span class="token punctuation">;</span>
<span class="token namespace">texture<span class="token punctuation">::</span></span><span class="token class-name">Texture</span><span class="token punctuation">::</span><span class="token function">from_bytes</span><span class="token punctuation">(</span>device<span class="token punctuation">,</span> queue<span class="token punctuation">,</span> <span class="token operator">&amp;</span>data<span class="token punctuation">,</span> file_name<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre></div><p>The <code>load_texture</code> method will be useful when we load the textures for our models, as <code>include_bytes!</code> requires that we know the name of the file at compile time which we can't really guarantee with model textures.</p> <p><code>Mesh</code> holds a vertex buffer, an index buffer, and the number of indices in the mesh. We're using an <code>usize</code> for the material. This <code>usize</code> will be used to index the <code>materials</code> list when it comes time to draw.</p> <p>With all that out of the way, we can get to loading our model.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">pub</span> <span class="token keyword">async</span> <span class="token keyword">fn</span> <span class="token function-definition function">load_model</span><span class="token punctuation">(</span>
file_name<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">str</span><span class="token punctuation">,</span>
device<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Device</span><span class="token punctuation">,</span>
queue<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Queue</span><span class="token punctuation">,</span>
layout<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BindGroupLayout</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token namespace">anyhow<span class="token punctuation">::</span></span><span class="token class-name">Result</span><span class="token operator">&lt;</span><span class="token namespace">model<span class="token punctuation">::</span></span><span class="token class-name">Model</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">let</span> obj_text <span class="token operator">=</span> <span class="token function">load_string</span><span class="token punctuation">(</span>file_name<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token keyword">await</span><span class="token operator">?</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> obj_cursor <span class="token operator">=</span> <span class="token class-name">Cursor</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span>obj_text<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> <span class="token keyword">mut</span> obj_reader <span class="token operator">=</span> <span class="token class-name">BufReader</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span>obj_cursor<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> <span class="token punctuation">(</span>models<span class="token punctuation">,</span> obj_materials<span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token namespace">tobj<span class="token punctuation">::</span></span><span class="token function">load_obj_buf_async</span><span class="token punctuation">(</span>
<span class="token operator">&amp;</span><span class="token keyword">mut</span> obj_reader<span class="token punctuation">,</span>
<span class="token operator">&amp;</span><span class="token namespace">tobj<span class="token punctuation">::</span></span><span class="token class-name">LoadOptions</span> <span class="token punctuation">{</span>
triangulate<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
single_index<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
<span class="token punctuation">..</span><span class="token class-name">Default</span><span class="token punctuation">::</span><span class="token function">default</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token closure-params"><span class="token closure-punctuation punctuation">|</span>p<span class="token closure-punctuation punctuation">|</span></span> <span class="token keyword">async</span> <span class="token keyword">move</span> <span class="token punctuation">{</span>
<span class="token keyword">let</span> mat_text <span class="token operator">=</span> <span class="token function">load_string</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>p<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token keyword">await</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token namespace">tobj<span class="token punctuation">::</span></span><span class="token function">load_mtl_buf</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token class-name">BufReader</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token class-name">Cursor</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span>mat_text<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token keyword">await</span><span class="token operator">?</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> <span class="token keyword">mut</span> materials <span class="token operator">=</span> <span class="token class-name">Vec</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> m <span class="token keyword">in</span> obj_materials<span class="token operator">?</span> <span class="token punctuation">{</span>
<span class="token keyword">let</span> diffuse_texture <span class="token operator">=</span> <span class="token function">load_texture</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>m<span class="token punctuation">.</span>diffuse_texture<span class="token punctuation">,</span> device<span class="token punctuation">,</span> queue<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token keyword">await</span><span class="token operator">?</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> bind_group <span class="token operator">=</span> device<span class="token punctuation">.</span><span class="token function">create_bind_group</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BindGroupDescriptor</span> <span class="token punctuation">{</span>
layout<span class="token punctuation">,</span>
entries<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token punctuation">[</span>
<span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BindGroupEntry</span> <span class="token punctuation">{</span>
binding<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
resource<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BindingResource</span><span class="token punctuation">::</span><span class="token class-name">TextureView</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>diffuse_texture<span class="token punctuation">.</span>view<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BindGroupEntry</span> <span class="token punctuation">{</span>
binding<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span>
resource<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BindingResource</span><span class="token punctuation">::</span><span class="token class-name">Sampler</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>diffuse_texture<span class="token punctuation">.</span>sampler<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span>
label<span class="token punctuation">:</span> <span class="token class-name">None</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
materials<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token namespace">model<span class="token punctuation">::</span></span><span class="token class-name">Material</span> <span class="token punctuation">{</span>
name<span class="token punctuation">:</span> m<span class="token punctuation">.</span>name<span class="token punctuation">,</span>
diffuse_texture<span class="token punctuation">,</span>
bind_group<span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token keyword">let</span> meshes <span class="token operator">=</span> models
<span class="token punctuation">.</span><span class="token function">into_iter</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token closure-punctuation punctuation">|</span>m<span class="token closure-punctuation punctuation">|</span></span> <span class="token punctuation">{</span>
<span class="token keyword">let</span> vertices <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">..</span>m<span class="token punctuation">.</span>mesh<span class="token punctuation">.</span>positions<span class="token punctuation">.</span><span class="token function">len</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token number">3</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token closure-punctuation punctuation">|</span>i<span class="token closure-punctuation punctuation">|</span></span> <span class="token namespace">model<span class="token punctuation">::</span></span><span class="token class-name">ModelVertex</span> <span class="token punctuation">{</span>
position<span class="token punctuation">:</span> <span class="token punctuation">[</span>
m<span class="token punctuation">.</span>mesh<span class="token punctuation">.</span>positions<span class="token punctuation">[</span>i <span class="token operator">*</span> <span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
m<span class="token punctuation">.</span>mesh<span class="token punctuation">.</span>positions<span class="token punctuation">[</span>i <span class="token operator">*</span> <span class="token number">3</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
m<span class="token punctuation">.</span>mesh<span class="token punctuation">.</span>positions<span class="token punctuation">[</span>i <span class="token operator">*</span> <span class="token number">3</span> <span class="token operator">+</span> <span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span>
tex_coords<span class="token punctuation">:</span> <span class="token punctuation">[</span>m<span class="token punctuation">.</span>mesh<span class="token punctuation">.</span>texcoords<span class="token punctuation">[</span>i <span class="token operator">*</span> <span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">,</span> m<span class="token punctuation">.</span>mesh<span class="token punctuation">.</span>texcoords<span class="token punctuation">[</span>i <span class="token operator">*</span> <span class="token number">2</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
normal<span class="token punctuation">:</span> <span class="token punctuation">[</span>
m<span class="token punctuation">.</span>mesh<span class="token punctuation">.</span>normals<span class="token punctuation">[</span>i <span class="token operator">*</span> <span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
m<span class="token punctuation">.</span>mesh<span class="token punctuation">.</span>normals<span class="token punctuation">[</span>i <span class="token operator">*</span> <span class="token number">3</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
m<span class="token punctuation">.</span>mesh<span class="token punctuation">.</span>normals<span class="token punctuation">[</span>i <span class="token operator">*</span> <span class="token number">3</span> <span class="token operator">+</span> <span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">collect</span><span class="token punctuation">::</span><span class="token operator">&lt;</span><span class="token class-name">Vec</span><span class="token operator">&lt;</span>_<span class="token operator">&gt;&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> vertex_buffer <span class="token operator">=</span> device<span class="token punctuation">.</span><span class="token function">create_buffer_init</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token namespace">wgpu<span class="token punctuation">::</span>util<span class="token punctuation">::</span></span><span class="token class-name">BufferInitDescriptor</span> <span class="token punctuation">{</span>
label<span class="token punctuation">:</span> <span class="token class-name">Some</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token macro property">format!</span><span class="token punctuation">(</span><span class="token string">&quot;{:?} Vertex Buffer&quot;</span><span class="token punctuation">,</span> file_name<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
contents<span class="token punctuation">:</span> <span class="token namespace">bytemuck<span class="token punctuation">::</span></span><span class="token function">cast_slice</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>vertices<span class="token punctuation">)</span><span class="token punctuation">,</span>
usage<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BufferUsages</span><span class="token punctuation">::</span><span class="token constant">VERTEX</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> index_buffer <span class="token operator">=</span> device<span class="token punctuation">.</span><span class="token function">create_buffer_init</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token namespace">wgpu<span class="token punctuation">::</span>util<span class="token punctuation">::</span></span><span class="token class-name">BufferInitDescriptor</span> <span class="token punctuation">{</span>
label<span class="token punctuation">:</span> <span class="token class-name">Some</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token macro property">format!</span><span class="token punctuation">(</span><span class="token string">&quot;{:?} Index Buffer&quot;</span><span class="token punctuation">,</span> file_name<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
contents<span class="token punctuation">:</span> <span class="token namespace">bytemuck<span class="token punctuation">::</span></span><span class="token function">cast_slice</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>m<span class="token punctuation">.</span>mesh<span class="token punctuation">.</span>indices<span class="token punctuation">)</span><span class="token punctuation">,</span>
usage<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BufferUsages</span><span class="token punctuation">::</span><span class="token constant">INDEX</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token namespace">model<span class="token punctuation">::</span></span><span class="token class-name">Mesh</span> <span class="token punctuation">{</span>
name<span class="token punctuation">:</span> file_name<span class="token punctuation">.</span><span class="token function">to_string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
vertex_buffer<span class="token punctuation">,</span>
index_buffer<span class="token punctuation">,</span>
num_elements<span class="token punctuation">:</span> m<span class="token punctuation">.</span>mesh<span class="token punctuation">.</span>indices<span class="token punctuation">.</span><span class="token function">len</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">as</span> <span class="token keyword">u32</span><span class="token punctuation">,</span>
material<span class="token punctuation">:</span> m<span class="token punctuation">.</span>mesh<span class="token punctuation">.</span>material_id<span class="token punctuation">.</span><span class="token function">unwrap_or</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">collect</span><span class="token punctuation">::</span><span class="token operator">&lt;</span><span class="token class-name">Vec</span><span class="token operator">&lt;</span>_<span class="token operator">&gt;&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Ok</span><span class="token punctuation">(</span><span class="token namespace">model<span class="token punctuation">::</span></span><span class="token class-name">Model</span> <span class="token punctuation">{</span> meshes<span class="token punctuation">,</span> materials <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre></div><h2 id="rendering-a-mesh"><a href="#rendering-a-mesh" class="header-anchor">#</a> Rendering a mesh</h2> <p>Before we can draw the model, we need to be able to draw an individual mesh. Let's create a trait called <code>DrawModel</code>, and implement it for <code>RenderPass</code>.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token comment">// model.rs</span>
<span class="token keyword">pub</span> <span class="token keyword">trait</span> <span class="token type-definition class-name">DrawModel</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">'a</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">fn</span> <span class="token function-definition function">draw_mesh</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">,</span> mesh<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'a</span> <span class="token class-name">Mesh</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">fn</span> <span class="token function-definition function">draw_mesh_instanced</span><span class="token punctuation">(</span>
<span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">,</span>
mesh<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'a</span> <span class="token class-name">Mesh</span><span class="token punctuation">,</span>
instances<span class="token punctuation">:</span> <span class="token class-name">Range</span><span class="token operator">&lt;</span><span class="token keyword">u32</span><span class="token operator">&gt;</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">impl</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">'a</span><span class="token punctuation">,</span> <span class="token lifetime-annotation symbol">'b</span><span class="token operator">&gt;</span> <span class="token class-name">DrawModel</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">'b</span><span class="token operator">&gt;</span> <span class="token keyword">for</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">RenderPass</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">'a</span><span class="token operator">&gt;</span>
<span class="token keyword">where</span>
<span class="token lifetime-annotation symbol">'b</span><span class="token punctuation">:</span> <span class="token lifetime-annotation symbol">'a</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span>
<span class="token keyword">fn</span> <span class="token function-definition function">draw_mesh</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">,</span> mesh<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'b</span> <span class="token class-name">Mesh</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">draw_mesh_instanced</span><span class="token punctuation">(</span>mesh<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">..</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">fn</span> <span class="token function-definition function">draw_mesh_instanced</span><span class="token punctuation">(</span>
<span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">,</span>
mesh<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'b</span> <span class="token class-name">Mesh</span><span class="token punctuation">,</span>
instances<span class="token punctuation">:</span> <span class="token class-name">Range</span><span class="token operator">&lt;</span><span class="token keyword">u32</span><span class="token operator">&gt;</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span><span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">set_vertex_buffer</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> mesh<span class="token punctuation">.</span>vertex_buffer<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token punctuation">..</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">set_index_buffer</span><span class="token punctuation">(</span>mesh<span class="token punctuation">.</span>index_buffer<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token punctuation">..</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">IndexFormat</span><span class="token punctuation">::</span><span class="token class-name">Uint32</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">draw_indexed</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">..</span>mesh<span class="token punctuation">.</span>num_elements<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> instances<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>We could have put these methods in an <code>impl Model</code>, but I felt it made more sense to have the <code>RenderPass</code> do all the rendering, as that's kind of its job. This does mean we have to import <code>DrawModel</code> when we go to render though.</p> <p>When we removed <code>vertex_buffer</code>, etc. we also removed their render_pass setup.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token comment">// lib.rs</span>
render_pass<span class="token punctuation">.</span><span class="token function">set_vertex_buffer</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token keyword">self</span><span class="token punctuation">.</span>instance_buffer<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token punctuation">..</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
render_pass<span class="token punctuation">.</span><span class="token function">set_pipeline</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">.</span>render_pipeline<span class="token punctuation">)</span><span class="token punctuation">;</span>
render_pass<span class="token punctuation">.</span><span class="token function">set_bind_group</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">.</span>diffuse_bind_group<span class="token punctuation">,</span> <span class="token operator">&amp;</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
render_pass<span class="token punctuation">.</span><span class="token function">set_bind_group</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">.</span>camera_bind_group<span class="token punctuation">,</span> <span class="token operator">&amp;</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token namespace">model<span class="token punctuation">::</span></span><span class="token class-name">DrawModel</span><span class="token punctuation">;</span>
render_pass<span class="token punctuation">.</span><span class="token function">draw_mesh_instanced</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">.</span>obj_model<span class="token punctuation">.</span>meshes<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">..</span><span class="token keyword">self</span><span class="token punctuation">.</span>instances<span class="token punctuation">.</span><span class="token function">len</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">as</span> <span class="token keyword">u32</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>Before that though we need to actually load the model and save it to <code>State</code>. Put the following in <code>State::new()</code>.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">let</span> obj_model <span class="token operator">=</span>
<span class="token namespace">resources<span class="token punctuation">::</span></span><span class="token function">load_model</span><span class="token punctuation">(</span><span class="token string">&quot;cube.obj&quot;</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span>device<span class="token punctuation">,</span> <span class="token operator">&amp;</span>queue<span class="token punctuation">,</span> <span class="token operator">&amp;</span>texture_bind_group_layout<span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token keyword">await</span>
<span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>Our new model is a bit bigger than our previous one so we're gonna need to adjust the spacing on our instances a bit.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">const</span> <span class="token constant">SPACE_BETWEEN</span><span class="token punctuation">:</span> <span class="token keyword">f32</span> <span class="token operator">=</span> <span class="token number">3.0</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> instances <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">..</span><span class="token constant">NUM_INSTANCES_PER_ROW</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">flat_map</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token closure-punctuation punctuation">|</span>z<span class="token closure-punctuation punctuation">|</span></span> <span class="token punctuation">{</span>
<span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">..</span><span class="token constant">NUM_INSTANCES_PER_ROW</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token keyword">move</span> <span class="token closure-params"><span class="token closure-punctuation punctuation">|</span>x<span class="token closure-punctuation punctuation">|</span></span> <span class="token punctuation">{</span>
<span class="token keyword">let</span> x <span class="token operator">=</span> <span class="token constant">SPACE_BETWEEN</span> <span class="token operator">*</span> <span class="token punctuation">(</span>x <span class="token keyword">as</span> <span class="token keyword">f32</span> <span class="token operator">-</span> <span class="token constant">NUM_INSTANCES_PER_ROW</span> <span class="token keyword">as</span> <span class="token keyword">f32</span> <span class="token operator">/</span> <span class="token number">2.0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> z <span class="token operator">=</span> <span class="token constant">SPACE_BETWEEN</span> <span class="token operator">*</span> <span class="token punctuation">(</span>z <span class="token keyword">as</span> <span class="token keyword">f32</span> <span class="token operator">-</span> <span class="token constant">NUM_INSTANCES_PER_ROW</span> <span class="token keyword">as</span> <span class="token keyword">f32</span> <span class="token operator">/</span> <span class="token number">2.0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> position <span class="token operator">=</span> <span class="token namespace">cgmath<span class="token punctuation">::</span></span><span class="token class-name">Vector3</span> <span class="token punctuation">{</span> x<span class="token punctuation">,</span> y<span class="token punctuation">:</span> <span class="token number">0.0</span><span class="token punctuation">,</span> z <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> rotation <span class="token operator">=</span> <span class="token keyword">if</span> position<span class="token punctuation">.</span><span class="token function">is_zero</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token namespace">cgmath<span class="token punctuation">::</span></span><span class="token class-name">Quaternion</span><span class="token punctuation">::</span><span class="token function">from_axis_angle</span><span class="token punctuation">(</span><span class="token namespace">cgmath<span class="token punctuation">::</span></span><span class="token class-name">Vector3</span><span class="token punctuation">::</span><span class="token function">unit_z</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token namespace">cgmath<span class="token punctuation">::</span></span><span class="token class-name">Deg</span><span class="token punctuation">(</span><span class="token number">0.0</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
<span class="token namespace">cgmath<span class="token punctuation">::</span></span><span class="token class-name">Quaternion</span><span class="token punctuation">::</span><span class="token function">from_axis_angle</span><span class="token punctuation">(</span>position<span class="token punctuation">.</span><span class="token function">normalize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token namespace">cgmath<span class="token punctuation">::</span></span><span class="token class-name">Deg</span><span class="token punctuation">(</span><span class="token number">45.0</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token class-name">Instance</span> <span class="token punctuation">{</span>
position<span class="token punctuation">,</span> rotation<span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">collect</span><span class="token punctuation">::</span><span class="token operator">&lt;</span><span class="token class-name">Vec</span><span class="token operator">&lt;</span>_<span class="token operator">&gt;&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>With all that done, you should get something like this.</p> <p><img src="/learn-wgpu/assets/img/cubes.988d14be.png" alt="cubes.png"></p> <h2 id="using-the-correct-textures"><a href="#using-the-correct-textures" class="header-anchor">#</a> Using the correct textures</h2> <p>If you look at the texture files for our obj, you'll see that they don't match up to our obj. The texture we want to see is this one,</p> <p><img src="/learn-wgpu/assets/img/cube-diffuse.03fc55af.jpg" alt="cube-diffuse.jpg"></p> <p>but we're still getting our happy tree texture.</p> <p>The reason for this is quite simple. Though we've created our textures we haven't created a bind group to give to the <code>RenderPass</code>. We're still using our old <code>diffuse_bind_group</code>. If we want to change that we need to use the bind group from our materials - the <code>bind_group</code> member of the <code>Material</code> struct.</p> <p>We're going to add a material parameter to <code>DrawModel</code>.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">pub</span> <span class="token keyword">trait</span> <span class="token type-definition class-name">DrawModel</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">'a</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">fn</span> <span class="token function-definition function">draw_mesh</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">,</span> mesh<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'a</span> <span class="token class-name">Mesh</span><span class="token punctuation">,</span> material<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'a</span> <span class="token class-name">Material</span><span class="token punctuation">,</span> camera_bind_group<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'a</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BindGroup</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">fn</span> <span class="token function-definition function">draw_mesh_instanced</span><span class="token punctuation">(</span>
<span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">,</span>
mesh<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'a</span> <span class="token class-name">Mesh</span><span class="token punctuation">,</span>
material<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'a</span> <span class="token class-name">Material</span><span class="token punctuation">,</span>
instances<span class="token punctuation">:</span> <span class="token class-name">Range</span><span class="token operator">&lt;</span><span class="token keyword">u32</span><span class="token operator">&gt;</span><span class="token punctuation">,</span>
camera_bind_group<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'a</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BindGroup</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">impl</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">'a</span><span class="token punctuation">,</span> <span class="token lifetime-annotation symbol">'b</span><span class="token operator">&gt;</span> <span class="token class-name">DrawModel</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">'b</span><span class="token operator">&gt;</span> <span class="token keyword">for</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">RenderPass</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">'a</span><span class="token operator">&gt;</span>
<span class="token keyword">where</span>
<span class="token lifetime-annotation symbol">'b</span><span class="token punctuation">:</span> <span class="token lifetime-annotation symbol">'a</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span>
<span class="token keyword">fn</span> <span class="token function-definition function">draw_mesh</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">,</span> mesh<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'b</span> <span class="token class-name">Mesh</span><span class="token punctuation">,</span> material<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'b</span> <span class="token class-name">Material</span><span class="token punctuation">,</span> camera_bind_group<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'b</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BindGroup</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">draw_mesh_instanced</span><span class="token punctuation">(</span>mesh<span class="token punctuation">,</span> material<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">..</span><span class="token number">1</span><span class="token punctuation">,</span> camera_bind_group<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">fn</span> <span class="token function-definition function">draw_mesh_instanced</span><span class="token punctuation">(</span>
<span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">,</span>
mesh<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'b</span> <span class="token class-name">Mesh</span><span class="token punctuation">,</span>
material<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'b</span> <span class="token class-name">Material</span><span class="token punctuation">,</span>
instances<span class="token punctuation">:</span> <span class="token class-name">Range</span><span class="token operator">&lt;</span><span class="token keyword">u32</span><span class="token operator">&gt;</span><span class="token punctuation">,</span>
camera_bind_group<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'b</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BindGroup</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">set_vertex_buffer</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> mesh<span class="token punctuation">.</span>vertex_buffer<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token punctuation">..</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">set_index_buffer</span><span class="token punctuation">(</span>mesh<span class="token punctuation">.</span>index_buffer<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token punctuation">..</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">IndexFormat</span><span class="token punctuation">::</span><span class="token class-name">Uint32</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">set_bind_group</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span>material<span class="token punctuation">.</span>bind_group<span class="token punctuation">,</span> <span class="token operator">&amp;</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">set_bind_group</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> camera_bind_group<span class="token punctuation">,</span> <span class="token operator">&amp;</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">draw_indexed</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">..</span>mesh<span class="token punctuation">.</span>num_elements<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> instances<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>We need to change the render code to reflect this.</p> <div class="language-rust extra-class"><pre class="language-rust"><code>render_pass<span class="token punctuation">.</span><span class="token function">set_vertex_buffer</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token keyword">self</span><span class="token punctuation">.</span>instance_buffer<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token punctuation">..</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
render_pass<span class="token punctuation">.</span><span class="token function">set_pipeline</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">.</span>render_pipeline<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> mesh <span class="token operator">=</span> <span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">.</span>obj_model<span class="token punctuation">.</span>meshes<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> material <span class="token operator">=</span> <span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">.</span>obj_model<span class="token punctuation">.</span>materials<span class="token punctuation">[</span>mesh<span class="token punctuation">.</span>material<span class="token punctuation">]</span><span class="token punctuation">;</span>
render_pass<span class="token punctuation">.</span><span class="token function">draw_mesh_instanced</span><span class="token punctuation">(</span>mesh<span class="token punctuation">,</span> material<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">..</span><span class="token keyword">self</span><span class="token punctuation">.</span>instances<span class="token punctuation">.</span><span class="token function">len</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">as</span> <span class="token keyword">u32</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">.</span>camera_bind_group<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>With all that in place, we should get the following.</p> <p><img src="/learn-wgpu/assets/img/cubes-correct.2db711eb.png" alt="cubes-correct.png"></p> <h2 id="rendering-the-entire-model"><a href="#rendering-the-entire-model" class="header-anchor">#</a> Rendering the entire model</h2> <p>Right now we are specifying the mesh and the material directly. This is useful if we want to draw a mesh with a different material. We're also not rendering other parts of the model (if we had some). Let's create a method for <code>DrawModel</code> that will draw all the parts of the model with their respective materials.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">pub</span> <span class="token keyword">trait</span> <span class="token type-definition class-name">DrawModel</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">'a</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
<span class="token keyword">fn</span> <span class="token function-definition function">draw_model</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">,</span> model<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'a</span> <span class="token class-name">Model</span><span class="token punctuation">,</span> camera_bind_group<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'a</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BindGroup</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">fn</span> <span class="token function-definition function">draw_model_instanced</span><span class="token punctuation">(</span>
<span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">,</span>
model<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'a</span> <span class="token class-name">Model</span><span class="token punctuation">,</span>
instances<span class="token punctuation">:</span> <span class="token class-name">Range</span><span class="token operator">&lt;</span><span class="token keyword">u32</span><span class="token operator">&gt;</span><span class="token punctuation">,</span>
camera_bind_group<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'a</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BindGroup</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">impl</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">'a</span><span class="token punctuation">,</span> <span class="token lifetime-annotation symbol">'b</span><span class="token operator">&gt;</span> <span class="token class-name">DrawModel</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">'b</span><span class="token operator">&gt;</span> <span class="token keyword">for</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">RenderPass</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">'a</span><span class="token operator">&gt;</span>
<span class="token keyword">where</span>
<span class="token lifetime-annotation symbol">'b</span><span class="token punctuation">:</span> <span class="token lifetime-annotation symbol">'a</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
<span class="token keyword">fn</span> <span class="token function-definition function">draw_model</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">,</span> model<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'b</span> <span class="token class-name">Model</span><span class="token punctuation">,</span> camera_bind_group<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'b</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BindGroup</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">draw_model_instanced</span><span class="token punctuation">(</span>model<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">..</span><span class="token number">1</span><span class="token punctuation">,</span> camera_bind_group<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">fn</span> <span class="token function-definition function">draw_model_instanced</span><span class="token punctuation">(</span>
<span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">,</span>
model<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'b</span> <span class="token class-name">Model</span><span class="token punctuation">,</span>
instances<span class="token punctuation">:</span> <span class="token class-name">Range</span><span class="token operator">&lt;</span><span class="token keyword">u32</span><span class="token operator">&gt;</span><span class="token punctuation">,</span>
camera_bind_group<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'b</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BindGroup</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">for</span> mesh <span class="token keyword">in</span> <span class="token operator">&amp;</span>model<span class="token punctuation">.</span>meshes <span class="token punctuation">{</span>
<span class="token keyword">let</span> material <span class="token operator">=</span> <span class="token operator">&amp;</span>model<span class="token punctuation">.</span>materials<span class="token punctuation">[</span>mesh<span class="token punctuation">.</span>material<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">draw_mesh_instanced</span><span class="token punctuation">(</span>mesh<span class="token punctuation">,</span> material<span class="token punctuation">,</span> instances<span class="token punctuation">.</span><span class="token function">clone</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> camera_bind_group<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>The code in <code>lib.rs</code> will change accordingly.</p> <div class="language-rust extra-class"><pre class="language-rust"><code>render_pass<span class="token punctuation">.</span><span class="token function">set_vertex_buffer</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token keyword">self</span><span class="token punctuation">.</span>instance_buffer<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token punctuation">..</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
render_pass<span class="token punctuation">.</span><span class="token function">set_pipeline</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">.</span>render_pipeline<span class="token punctuation">)</span><span class="token punctuation">;</span>
render_pass<span class="token punctuation">.</span><span class="token function">draw_model_instanced</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">.</span>obj_model<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">..</span><span class="token keyword">self</span><span class="token punctuation">.</span>instances<span class="token punctuation">.</span><span class="token function">len</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">as</span> <span class="token keyword">u32</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">.</span>camera_bind_group<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><div id="wasm-example"><!----> <button>Try Tutorial9_models!</button></div> <div class="auto-github-link"><a href="https://github.com/sotrh/learn-wgpu/tree/master/code/beginner/tutorial9-models/" target="_blank" rel="noopener noreferrer">Check out the code!</a> <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></div></div> <footer class="page-edit"><!----> <div class="last-updated"><span class="prefix">Last Updated: </span> <span class="time">11/27/2023, 10:42:27 PM</span></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
<a href="/learn-wgpu/beginner/tutorial8-depth/" class="prev">
The Depth Buffer
</a></span> <span class="next"><a href="/learn-wgpu/intermediate/tutorial10-lighting/">
Working with Lights
</a>
</span></p></div> </main></div></div><div class="global-ui"><!----></div></div>
<script src="/learn-wgpu/assets/js/app.8ee4646c.js" defer></script><script src="/learn-wgpu/assets/js/2.2ef7287a.js" defer></script><script src="/learn-wgpu/assets/js/1.eaeeb819.js" defer></script><script src="/learn-wgpu/assets/js/36.2e1d433e.js" defer></script><script src="/learn-wgpu/assets/js/33.945dce62.js" defer></script><script src="/learn-wgpu/assets/js/37.5ecf7ce2.js" defer></script>
</body>
</html>