gh-pages
Ben Hansen 4 years ago
commit 385126f5d4

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 700 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 705 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 748 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 594 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 551 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 787 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 522 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 708 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 783 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 759 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 722 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 748 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 711 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 674 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 542 KiB

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="12" height="13"><g stroke-width="2" stroke="#aaa" fill="none"><path d="M11.29 11.71l-4-4"/><circle cx="5" cy="5" r="4"/></g></svg>

After

Width:  |  Height:  |  Size: 216 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

@ -0,0 +1 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[10],{169:function(t,e,n){},248:function(t,e,n){"use strict";var a=n(169);n.n(a).a},276:function(t,e,n){"use strict";n.r(e);var a={functional:!0,props:{type:{type:String,default:"tip"},text:String,vertical:{type:String,default:"top"}},render:function(t,e){var n=e.props,a=e.slots;return t("span",{class:["badge",n.type],style:{verticalAlign:n.vertical}},n.text||a().default)}},i=(n(248),n(10)),r=Object(i.a)(a,void 0,void 0,!1,null,"86b323a0",null);e.default=r.exports}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[22],{251:function(t,e,n){"use strict";n.r(e);var r={computed:{link:function(){return"https://github.com/sotrh/learn-wgpu/tree/master/code"+this.$page.path}}},i=n(10),s=Object(i.a)(r,(function(){var t=this.$createElement,e=this._self._c||t;return e("div",{staticClass:"auto-github-link"},[e("a",{attrs:{href:this.link,target:"_blank",rel:"noopener noreferrer"}},[this._v("Check out the code!")]),this._v(" "),e("OutboundLink")],1)}),[],!1,null,null,null);e.default=s.exports}}]);

@ -0,0 +1 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[23],{250:function(t,e,s){"use strict";s.r(e);var o=["There's nothing here.","How did we get here?","That's a Four-Oh-Four.","Looks like we've got some broken links."],n={methods:{getMsg:function(){return o[Math.floor(Math.random()*o.length)]}}},i=s(10),h=Object(i.a)(n,(function(){var t=this.$createElement,e=this._self._c||t;return e("div",{staticClass:"theme-container"},[e("div",{staticClass:"theme-default-content"},[e("h1",[this._v("404")]),this._v(" "),e("blockquote",[this._v(this._s(this.getMsg()))]),this._v(" "),e("router-link",{attrs:{to:"/"}},[this._v("Take me home.")])],1)])}),[],!1,null,null,null);e.default=h.exports}}]);

@ -0,0 +1 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[24],{253:function(t,e,a){"use strict";a.r(e);var o=a(10),r=Object(o.a)({},(function(){var t=this,e=t.$createElement,a=t._self._c||e;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"introduction"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#introduction"}},[t._v("#")]),t._v(" Introduction")]),t._v(" "),a("h2",{attrs:{id:"what-is-wgpu"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#what-is-wgpu"}},[t._v("#")]),t._v(" What is wgpu?")]),t._v(" "),a("p",[a("a",{attrs:{href:"https://github.com/gfx-rs/wgpu",target:"_blank",rel:"noopener noreferrer"}},[t._v("Wgpu"),a("OutboundLink")],1),t._v(" is a Rust implementation of the "),a("a",{attrs:{href:"https://gpuweb.github.io/gpuweb/",target:"_blank",rel:"noopener noreferrer"}},[t._v("WebGPU API spec"),a("OutboundLink")],1),t._v(". WebGPU is a specification published by the GPU for the Web Community Group. It aims to allow web code access to GPU functions in a safe and reliable manner. It does this by mimicking the Vulkan API, and translating that down to whatever API the host hardware is using (ie. DirectX, Metal, Vulkan).")]),t._v(" "),a("p",[t._v("Wgpu is still in development, so some of this doc is subject to change.")]),t._v(" "),a("h2",{attrs:{id:"why-rust"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#why-rust"}},[t._v("#")]),t._v(" Why Rust?")]),t._v(" "),a("p",[t._v("Wgpu actually has C bindings to allow you to write C/C++ code with it, as well as use other languages that interface with C. That being said, wgpu is written in Rust, and it has some convient Rust bindings that don't have to jump through any hoops. On top of that, I've been enjoying writing in Rust.")]),t._v(" "),a("p",[t._v("You should be fairly familiar with Rust before using this tutorial as I won't go into much detail on Rust syntax. If you're not super comfortable with Rust you can review the "),a("a",{attrs:{href:"https://www.rust-lang.org/learn",target:"_blank",rel:"noopener noreferrer"}},[t._v("Rust tutorial"),a("OutboundLink")],1),t._v(". You should also be familiar about "),a("a",{attrs:{href:"https://doc.rust-lang.org/cargo/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Cargo"),a("OutboundLink")],1),t._v(".")]),t._v(" "),a("p",[t._v("I'm using this project as a way to learn wgpu myself, so I might miss some important details, or explain things wrong. I'm always open to constructive feedback.")]),t._v(" "),a("h2",{attrs:{id:"contribution-and-support"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#contribution-and-support"}},[t._v("#")]),t._v(" Contribution and Support")]),t._v(" "),a("ul",[a("li",[t._v("I accept pull requests for fixing issues with this tutorial such as typos, incorrect information, and other inconsistencies.")]),t._v(" "),a("li",[t._v("Due to wgpu's rapidly changing api, I'm not accepting any new pull requests for showcase demos.")]),t._v(" "),a("li",[t._v("If you want to support me directly, check out my "),a("a",{attrs:{href:"https://www.patreon.com/sotrh",target:"_blank",rel:"noopener noreferrer"}},[t._v("patreon"),a("OutboundLink")],1),t._v("!")])])])}),[],!1,null,null,null);e.default=r.exports}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[27],{269:function(e,t,s){"use strict";s.r(t);var o=s(10),r=Object(o.a)({},(function(){var e=this,t=e.$createElement,s=e._self._c||t;return s("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[s("h1",{attrs:{id:"foreward"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#foreward"}},[e._v("#")]),e._v(" Foreward")]),e._v(" "),s("p",[e._v("The articles in this section are not meant to be tutorials. They are showcases of the various things you can do with "),s("code",[e._v("wgpu")]),e._v(". I won't go over specifics of creating "),s("code",[e._v("wgpu")]),e._v(" resources, as those will be covered elsewhere. The code for these examples is still available however, and will be accessible on Github.")])])}),[],!1,null,null,null);t.default=r.exports}}]);

File diff suppressed because one or more lines are too long

@ -0,0 +1 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[29],{274:function(t,s,n){"use strict";n.r(s);var e=n(10),o=Object(e.a)({},(function(){var t=this.$createElement,s=this._self._c||t;return s("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[s("h1",{attrs:{id:"coming-soon"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#coming-soon"}},[this._v("#")]),this._v(" Coming Soon!")]),this._v(" "),s("p",[this._v("This section has not yet been completed.")])])}),[],!1,null,null,null);s.default=o.exports}}]);

File diff suppressed because one or more lines are too long

@ -0,0 +1 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[30],{153:function(n,w,o){}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[9],{246:function(t,e,n){"use strict";var r=n(0),i=n(68),a=n(14),o=n(2),u=n(31),l=[],s=l.sort,c=o((function(){l.sort(void 0)})),f=o((function(){l.sort(null)})),d=u("sort");r({target:"Array",proto:!0,forced:c||!f||!d},{sort:function(t){return void 0===t?s.call(a(this)):s.call(a(this),i(t))}})},247:function(t,e,n){var r=n(11),i=Date.prototype,a=i.toString,o=i.getTime;new Date(NaN)+""!="Invalid Date"&&r(i,"toString",(function(){var t=o.call(this);return t==t?a.call(this):"Invalid Date"}))},252:function(t,e,n){"use strict";n.r(e);n(18),n(108),n(34),n(246),n(247),n(110);var r={data:function(){return{}},computed:{recentFiles:function(){return this.$site.pages.filter((function(t){return t.path.includes("beginner")||t.path.includes("intermediate")})).sort((function(t,e){var n=new Date(t.frontmatter.published).getTime()-new Date(e.frontmatter.published).getTime();return n<0?-1:n>0?1:0})).slice(0,5)}}},i=n(10),a=Object(i.a)(r,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",[n("ul",t._l(t.recentFiles,(function(e){return n("li",[n("a",{attrs:{href:e.path}},[t._v(t._s(e.title))])])})),0)])}),[],!1,null,null,null);e.default=a.exports}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,345 @@
<!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="description" content="">
<meta name="generator" content="VuePress 1.4.0">
<meta property="article:modified_time" content="2020-11-14T21:57:39.000Z"><meta property="og:site_name" content="Learn Wgpu"><meta property="og:title" content="Model Loading"><meta property="og:type" content="website"><meta property="og:url" content="/beginner/tutorial9-models/"><meta name="twitter:title" content="Model Loading"><meta name="twitter:url" content="/beginner/tutorial9-models/"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:label1" content="Written by"><meta name="twitter:data2" content="Benjamin R Hansen"><meta name="twitter:creator" content="https://twitter.com/sotrh760">
<link rel="preload" href="/learn-wgpu/assets/css/0.styles.7acc6ef6.css" as="style"><link rel="preload" href="/learn-wgpu/assets/js/app.10252059.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/2.6a9f728b.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/8.1fd4cc1c.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/22.2132e362.js" as="script"><link rel="prefetch" href="/learn-wgpu/assets/js/10.de8cadfb.js"><link rel="prefetch" href="/learn-wgpu/assets/js/11.53581734.js"><link rel="prefetch" href="/learn-wgpu/assets/js/12.8c46a0c8.js"><link rel="prefetch" href="/learn-wgpu/assets/js/13.4723ba5d.js"><link rel="prefetch" href="/learn-wgpu/assets/js/14.90ed5917.js"><link rel="prefetch" href="/learn-wgpu/assets/js/15.3056a06c.js"><link rel="prefetch" href="/learn-wgpu/assets/js/16.0af06f1e.js"><link rel="prefetch" href="/learn-wgpu/assets/js/17.1d99e854.js"><link rel="prefetch" href="/learn-wgpu/assets/js/18.9923f29d.js"><link rel="prefetch" href="/learn-wgpu/assets/js/19.dab68ffd.js"><link rel="prefetch" href="/learn-wgpu/assets/js/20.70e640cc.js"><link rel="prefetch" href="/learn-wgpu/assets/js/21.1dba0934.js"><link rel="prefetch" href="/learn-wgpu/assets/js/23.1a88f225.js"><link rel="prefetch" href="/learn-wgpu/assets/js/24.585372be.js"><link rel="prefetch" href="/learn-wgpu/assets/js/25.022f80fd.js"><link rel="prefetch" href="/learn-wgpu/assets/js/26.8484ba66.js"><link rel="prefetch" href="/learn-wgpu/assets/js/27.8b0a41bf.js"><link rel="prefetch" href="/learn-wgpu/assets/js/28.b9bf1b57.js"><link rel="prefetch" href="/learn-wgpu/assets/js/29.5c3f77ba.js"><link rel="prefetch" href="/learn-wgpu/assets/js/3.df177b88.js"><link rel="prefetch" href="/learn-wgpu/assets/js/30.dc887be9.js"><link rel="prefetch" href="/learn-wgpu/assets/js/4.89cbdecc.js"><link rel="prefetch" href="/learn-wgpu/assets/js/5.c2eff02b.js"><link rel="prefetch" href="/learn-wgpu/assets/js/6.086069e3.js"><link rel="prefetch" href="/learn-wgpu/assets/js/7.65364b9b.js"><link rel="prefetch" href="/learn-wgpu/assets/js/9.ecb6e79c.js">
<link rel="stylesheet" href="/learn-wgpu/assets/css/0.styles.7acc6ef6.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/" 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-swapchain/" class="sidebar-link">The Swapchain</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/" 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/#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-threading/" class="sidebar-link">Multi-threading with Wgpu and Rayon</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><a href="/learn-wgpu/news/" class="sidebar-link">News</a></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, but it's really slow if we want to include complex models with lots of polygons. Because of this, we're going modify our code to leverage the obj model format so that we can create a model in a software such as blender and display it in our code.</p> <p>Our <code>main.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 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 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 punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">VertexBufferDescriptor</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 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>
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>
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>
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 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 punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">VertexBufferDescriptor</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 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>main.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 our the <code>VertexBufferDescriptor</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>VertexBufferDescriptor</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 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 punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">VertexBufferDescriptor</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 namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">VertexBufferDescriptor</span> <span class="token punctuation">{</span>
stride<span class="token punctuation">:</span> <span class="token namespace">std<span class="token punctuation">::</span>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">InputStepMode</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 namespace">wgpu<span class="token punctuation">::</span></span><span class="token macro property">vertex_attr_array!</span><span class="token punctuation">[</span>
<span class="token number">0</span> <span class="token operator">=&gt;</span> <span class="token class-name">Float3</span><span class="token punctuation">,</span>
<span class="token number">1</span> <span class="token operator">=&gt;</span> <span class="token class-name">Float2</span><span class="token punctuation">,</span>
<span class="token number">2</span> <span class="token operator">=&gt;</span> <span class="token class-name">Float3</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>VertexBufferDescriptor</code>, but we added a <code>VertexAttributeDescriptor</code> for the <code>normal</code>. Remove the <code>Vertex</code> struct in <code>main.rs</code> as we won't need it anymore, and use our new <code>Vertex</code> from model for the <code>RenderPipeline</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_state<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">VertexStateDescriptor</span> <span class="token punctuation">{</span>
index_format<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">Uint16</span><span class="token punctuation">,</span>
vertex_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 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>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<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" 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></a> with the model and all of it's 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 projects 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 projects 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. Add the following lines to <code>build.rs</code> after you compile the shaders.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><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>
</code></pre></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> <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/0.1.12/tobj/" target="_blank" rel="noopener noreferrer">tobj<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" 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></a> library to load our model. 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 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/normal-mapping">later</a>. The name is more for debugging purposes.</p> <p>Speaking of textures, we'll need to add a <code>load()</code> method to <code>Texture</code> in <code>texture.rs</code>.</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>path<span class="token punctuation">::</span></span><span class="token class-name">Path</span><span class="token punctuation">;</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">load</span><span class="token operator">&lt;</span><span class="token class-name">P</span><span class="token punctuation">:</span> <span class="token class-name">AsRef</span><span class="token operator">&lt;</span><span class="token class-name">Path</span><span class="token operator">&gt;&gt;</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>
path<span class="token punctuation">:</span> <span class="token class-name">P</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 keyword">Self</span><span class="token punctuation">,</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">CommandBuffer</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token namespace">failure<span class="token punctuation">::</span></span><span class="token class-name">Error</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
<span class="token comment">// Needed to appease the borrow checker</span>
<span class="token keyword">let</span> path_copy <span class="token operator">=</span> path<span class="token punctuation">.</span><span class="token function">as_ref</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">to_path_buf</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> label <span class="token operator">=</span> path_copy<span class="token punctuation">.</span><span class="token function">to_str</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> img <span class="token operator">=</span> <span class="token namespace">image<span class="token punctuation">::</span></span><span class="token function">open</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 keyword">Self</span><span class="token punctuation">::</span><span class="token function">from_image</span><span class="token punctuation">(</span>device<span class="token punctuation">,</span> queue<span class="token punctuation">,</span> <span class="token operator">&amp;</span>img<span class="token punctuation">,</span> label<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre></div><p>The <code>load</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>While we're at it let's import <code>texture.rs</code> in <code>model.rs</code>.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">use</span> <span class="token keyword">crate</span><span class="token module-declaration namespace"><span class="token punctuation">::</span>texture</span><span class="token punctuation">;</span>
</code></pre></div><p>We also need to make a subtle change on <code>from_image()</code> method in <code>texture.rs</code>. PNGs work fine with <code>as_rgba8()</code>, as they have an alpha channel. But, JPEGs don't have an alpha channel, and the code would panic if we try to call <code>as_rgba8()</code> on the JPEG texture image we are going to use. Instead, we can use <code>to_rgba()</code> to handle such an image.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">let</span> rgba <span class="token operator">=</span> img<span class="token punctuation">.</span><span class="token function">to_rgba</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><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">impl</span> <span class="token class-name">Model</span> <span class="token punctuation">{</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">load</span><span class="token operator">&lt;</span><span class="token class-name">P</span><span class="token punctuation">:</span> <span class="token class-name">AsRef</span><span class="token operator">&lt;</span><span class="token class-name">Path</span><span class="token operator">&gt;&gt;</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>
path<span class="token punctuation">:</span> <span class="token class-name">P</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 keyword">Self</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">let</span> <span class="token punctuation">(</span>obj_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</span><span class="token punctuation">(</span>path<span class="token punctuation">.</span><span class="token function">as_ref</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">;</span>
<span class="token comment">// We're assuming that the texture files are stored with the obj file</span>
<span class="token keyword">let</span> containing_folder <span class="token operator">=</span> path<span class="token punctuation">.</span><span class="token function">as_ref</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">parent</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">context</span><span class="token punctuation">(</span><span class="token string">&quot;Directory has no parent&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> 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> mat <span class="token keyword">in</span> obj_materials <span class="token punctuation">{</span>
<span class="token keyword">let</span> diffuse_path <span class="token operator">=</span> mat<span class="token punctuation">.</span>diffuse_texture<span class="token punctuation">;</span>
<span class="token keyword">let</span> diffuse_texture <span class="token operator">=</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">load</span><span class="token punctuation">(</span>device<span class="token punctuation">,</span> queue<span class="token punctuation">,</span> containing_folder<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>diffuse_path<span class="token punctuation">)</span><span class="token punctuation">)</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 class-name">Material</span> <span class="token punctuation">{</span>
name<span class="token punctuation">:</span> mat<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 punctuation">}</span>
<span class="token keyword">let</span> <span class="token keyword">mut</span> meshes <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_models <span class="token punctuation">{</span>
<span class="token keyword">let</span> <span class="token keyword">mut</span> vertices <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> i <span class="token keyword">in</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>
vertices<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</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 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> path<span class="token punctuation">.</span><span class="token function">as_ref</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>
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">BufferUsage</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> path<span class="token punctuation">.</span><span class="token function">as_ref</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>
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">BufferUsage</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>
meshes<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token class-name">Mesh</span> <span class="token punctuation">{</span>
name<span class="token punctuation">:</span> m<span class="token punctuation">.</span>name<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 class-name">Ok</span><span class="token punctuation">(</span><span class="token keyword">Self</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>
<span class="token punctuation">}</span>
</code></pre></div><p>Make sure that you change the <code>IndexFormat</code> that the <code>RenderPipeline</code> uses from <code>Uint16</code> to <code>Uint32</code>. Tobj stores the indices as <code>u32</code>s, so using a lower bit stride will result in your model getting mangled.</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_state<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">VertexStateDescriptor</span> <span class="token punctuation">{</span>
index_format<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>
vertex_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 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><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 keyword">pub</span> <span class="token keyword">trait</span> <span class="token class-name">DrawModel</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 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">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 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">'a</span><span class="token punctuation">,</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 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 this methods in <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 it's job. This does mean we have to import <code>DrawModel</code> when we go to render though.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token comment">// main.rs</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>uniform_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> res_dir <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 keyword">let</span> obj_model <span class="token operator">=</span> <span class="token namespace">model<span class="token punctuation">::</span></span><span class="token class-name">Model</span><span class="token punctuation">::</span><span class="token function">load</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>
res_dir<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">&quot;cube.obj&quot;</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">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><div class="note"><p>We're using <code>OUT_DIR</code> here to get at our <code>res</code> folder.</p></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">clone</span><span class="token punctuation">(</span><span class="token punctuation">)</span><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 create a bind group for our materials. Add a <code>bind_group</code> field to <code>Material</code>.</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 comment">// NEW!</span>
<span class="token punctuation">}</span>
</code></pre></div><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 class-name">DrawModel</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 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> uniforms<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">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>
uniforms<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 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">'a</span><span class="token punctuation">,</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> uniforms<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> uniforms<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>
uniforms<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 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> <span class="token operator">&amp;</span>uniforms<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_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>uniform_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 class-name">DrawModel</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 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> uniforms<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">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>
uniforms<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 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">'a</span><span class="token punctuation">,</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> uniforms<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> uniforms<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>
uniforms<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> uniforms<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>main.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_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>uniform_bind_group<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></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> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" 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></div></div> <footer class="page-edit"><!----> <div class="last-updated"><span class="prefix">Last Updated: </span> <span class="time">11/14/2020, 2:57:39 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.10252059.js" defer></script><script src="/learn-wgpu/assets/js/2.6a9f728b.js" defer></script><script src="/learn-wgpu/assets/js/8.1fd4cc1c.js" defer></script><script src="/learn-wgpu/assets/js/22.2132e362.js" defer></script>
</body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,348 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>A Better Camera | Learn Wgpu</title>
<meta name="description" content="">
<meta name="generator" content="VuePress 1.4.0">
<meta property="article:modified_time" content="2020-11-11T22:41:06.000Z"><meta property="og:site_name" content="Learn Wgpu"><meta property="og:title" content="A Better Camera"><meta property="og:type" content="website"><meta property="og:url" content="/intermediate/tutorial12-camera/"><meta name="twitter:title" content="A Better Camera"><meta name="twitter:url" content="/intermediate/tutorial12-camera/"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:label1" content="Written by"><meta name="twitter:data2" content="Benjamin R Hansen"><meta name="twitter:creator" content="https://twitter.com/sotrh760">
<link rel="preload" href="/learn-wgpu/assets/css/0.styles.7acc6ef6.css" as="style"><link rel="preload" href="/learn-wgpu/assets/js/app.10252059.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/2.6a9f728b.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/14.90ed5917.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/22.2132e362.js" as="script"><link rel="prefetch" href="/learn-wgpu/assets/js/10.de8cadfb.js"><link rel="prefetch" href="/learn-wgpu/assets/js/11.53581734.js"><link rel="prefetch" href="/learn-wgpu/assets/js/12.8c46a0c8.js"><link rel="prefetch" href="/learn-wgpu/assets/js/13.4723ba5d.js"><link rel="prefetch" href="/learn-wgpu/assets/js/15.3056a06c.js"><link rel="prefetch" href="/learn-wgpu/assets/js/16.0af06f1e.js"><link rel="prefetch" href="/learn-wgpu/assets/js/17.1d99e854.js"><link rel="prefetch" href="/learn-wgpu/assets/js/18.9923f29d.js"><link rel="prefetch" href="/learn-wgpu/assets/js/19.dab68ffd.js"><link rel="prefetch" href="/learn-wgpu/assets/js/20.70e640cc.js"><link rel="prefetch" href="/learn-wgpu/assets/js/21.1dba0934.js"><link rel="prefetch" href="/learn-wgpu/assets/js/23.1a88f225.js"><link rel="prefetch" href="/learn-wgpu/assets/js/24.585372be.js"><link rel="prefetch" href="/learn-wgpu/assets/js/25.022f80fd.js"><link rel="prefetch" href="/learn-wgpu/assets/js/26.8484ba66.js"><link rel="prefetch" href="/learn-wgpu/assets/js/27.8b0a41bf.js"><link rel="prefetch" href="/learn-wgpu/assets/js/28.b9bf1b57.js"><link rel="prefetch" href="/learn-wgpu/assets/js/29.5c3f77ba.js"><link rel="prefetch" href="/learn-wgpu/assets/js/3.df177b88.js"><link rel="prefetch" href="/learn-wgpu/assets/js/30.dc887be9.js"><link rel="prefetch" href="/learn-wgpu/assets/js/4.89cbdecc.js"><link rel="prefetch" href="/learn-wgpu/assets/js/5.c2eff02b.js"><link rel="prefetch" href="/learn-wgpu/assets/js/6.086069e3.js"><link rel="prefetch" href="/learn-wgpu/assets/js/7.65364b9b.js"><link rel="prefetch" href="/learn-wgpu/assets/js/8.1fd4cc1c.js"><link rel="prefetch" href="/learn-wgpu/assets/js/9.ecb6e79c.js">
<link rel="stylesheet" href="/learn-wgpu/assets/css/0.styles.7acc6ef6.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/" class="sidebar-link">Introduction</a></li><li><section class="sidebar-group depth-0"><p class="sidebar-heading"><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-swapchain/" class="sidebar-link">The Swapchain</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/" class="sidebar-link">Model Loading</a></li></ul></section></li><li><section class="sidebar-group depth-0"><p class="sidebar-heading open"><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="active sidebar-link">A Better Camera</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/learn-wgpu/intermediate/tutorial12-camera/#the-camera" class="sidebar-link">The Camera</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/intermediate/tutorial12-camera/#the-projection" class="sidebar-link">The Projection</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/intermediate/tutorial12-camera/#cleaning-up-main-rs" class="sidebar-link">Cleaning up main.rs</a></li></ul></li><li><a href="/learn-wgpu/intermediate/tutorial13-threading/" class="sidebar-link">Multi-threading with Wgpu and Rayon</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><a href="/learn-wgpu/news/" class="sidebar-link">News</a></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><h1 id="a-better-camera"><a href="#a-better-camera" class="header-anchor">#</a> A Better Camera</h1> <p>I've been putting this off for a while. Implementing a camera isn't specifically related to using WGPU properly, but it's been bugging me so let's do it.</p> <p><code>main.rs</code> is getting a little crowded, so let's create a <code>camera.rs</code> file to put our camera code. The first thing we're going to put in it in is some imports and our <code>OPENGL_TO_WGPU_MATRIX</code>.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">use</span> <span class="token namespace">cgmath<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">winit<span class="token punctuation">::</span>event<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">winit<span class="token punctuation">::</span>dpi<span class="token punctuation">::</span></span><span class="token class-name">PhysicalPosition</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span>time<span class="token punctuation">::</span></span><span class="token class-name">Duration</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span></span><span class="token keyword">f32</span><span class="token punctuation">::</span><span class="token namespace">consts<span class="token punctuation">::</span></span><span class="token constant">FRAC_PI_2</span><span class="token punctuation">;</span>
<span class="token attribute attr-name">#[rustfmt::skip]</span>
<span class="token keyword">pub</span> <span class="token keyword">const</span> <span class="token constant">OPENGL_TO_WGPU_MATRIX</span><span class="token punctuation">:</span> <span class="token namespace">cgmath<span class="token punctuation">::</span></span><span class="token class-name">Matrix4</span><span class="token operator">&lt;</span><span class="token keyword">f32</span><span class="token operator">&gt;</span> <span class="token operator">=</span> <span class="token namespace">cgmath<span class="token punctuation">::</span></span><span class="token class-name">Matrix4</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span>
<span class="token number">1.0</span><span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">,</span>
<span class="token number">0.0</span><span class="token punctuation">,</span> <span class="token number">1.0</span><span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">,</span>
<span class="token number">0.0</span><span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">,</span> <span class="token number">0.5</span><span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">,</span>
<span class="token number">0.0</span><span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">,</span> <span class="token number">0.5</span><span class="token punctuation">,</span> <span class="token number">1.0</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><h2 id="the-camera"><a href="#the-camera" class="header-anchor">#</a> The Camera</h2> <p>Next we need create a new <code>Camera</code> struct. We're going to be using a FPS style camera, so we'll store the position and the yaw (horizontal rotation), and pitch (vertical rotation). We'll have a <code>calc_matrix</code> method to create our view matrix.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token attribute attr-name">#[derive(Debug)]</span>
<span class="token keyword">pub</span> <span class="token keyword">struct</span> <span class="token type-definition class-name">Camera</span> <span class="token punctuation">{</span>
<span class="token keyword">pub</span> position<span class="token punctuation">:</span> <span class="token class-name">Point3</span><span class="token operator">&lt;</span><span class="token keyword">f32</span><span class="token operator">&gt;</span><span class="token punctuation">,</span>
yaw<span class="token punctuation">:</span> <span class="token class-name">Rad</span><span class="token operator">&lt;</span><span class="token keyword">f32</span><span class="token operator">&gt;</span><span class="token punctuation">,</span>
pitch<span class="token punctuation">:</span> <span class="token class-name">Rad</span><span class="token operator">&lt;</span><span class="token keyword">f32</span><span class="token operator">&gt;</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token keyword">impl</span> <span class="token class-name">Camera</span> <span class="token punctuation">{</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">new</span><span class="token operator">&lt;</span>
<span class="token class-name">V</span><span class="token punctuation">:</span> <span class="token class-name">Into</span><span class="token operator">&lt;</span><span class="token class-name">Point3</span><span class="token operator">&lt;</span><span class="token keyword">f32</span><span class="token operator">&gt;&gt;</span><span class="token punctuation">,</span>
<span class="token class-name">Y</span><span class="token punctuation">:</span> <span class="token class-name">Into</span><span class="token operator">&lt;</span><span class="token class-name">Rad</span><span class="token operator">&lt;</span><span class="token keyword">f32</span><span class="token operator">&gt;&gt;</span><span class="token punctuation">,</span>
<span class="token class-name">P</span><span class="token punctuation">:</span> <span class="token class-name">Into</span><span class="token operator">&lt;</span><span class="token class-name">Rad</span><span class="token operator">&lt;</span><span class="token keyword">f32</span><span class="token operator">&gt;&gt;</span><span class="token punctuation">,</span>
<span class="token operator">&gt;</span><span class="token punctuation">(</span>
position<span class="token punctuation">:</span> <span class="token class-name">V</span><span class="token punctuation">,</span>
yaw<span class="token punctuation">:</span> <span class="token class-name">Y</span><span class="token punctuation">,</span>
pitch<span class="token punctuation">:</span> <span class="token class-name">P</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">Self</span> <span class="token punctuation">{</span>
<span class="token keyword">Self</span> <span class="token punctuation">{</span>
position<span class="token punctuation">:</span> position<span class="token punctuation">.</span><span class="token function">into</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
yaw<span class="token punctuation">:</span> yaw<span class="token punctuation">.</span><span class="token function">into</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
pitch<span class="token punctuation">:</span> pitch<span class="token punctuation">.</span><span class="token function">into</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">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">calc_matrix</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">Matrix4</span><span class="token operator">&lt;</span><span class="token keyword">f32</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
<span class="token class-name">Matrix4</span><span class="token punctuation">::</span><span class="token function">look_at_dir</span><span class="token punctuation">(</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>position<span class="token punctuation">,</span>
<span class="token class-name">Vector3</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>yaw<span class="token number">.0</span><span class="token punctuation">.</span><span class="token function">cos</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>pitch<span class="token number">.0</span><span class="token punctuation">.</span><span class="token function">sin</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>yaw<span class="token number">.0</span><span class="token punctuation">.</span><span class="token function">sin</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">normalize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token class-name">Vector3</span><span class="token punctuation">::</span><span class="token function">unit_y</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><h2 id="the-projection"><a href="#the-projection" class="header-anchor">#</a> The Projection</h2> <p>I've decided to split the projection from the camera. The projection only really needs to change if the window resizes, so let's create a <code>Projection</code> struct.</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">Projection</span> <span class="token punctuation">{</span>
aspect<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
fovy<span class="token punctuation">:</span> <span class="token class-name">Rad</span><span class="token operator">&lt;</span><span class="token keyword">f32</span><span class="token operator">&gt;</span><span class="token punctuation">,</span>
znear<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
zfar<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token keyword">impl</span> <span class="token class-name">Projection</span> <span class="token punctuation">{</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">new</span><span class="token operator">&lt;</span><span class="token class-name">F</span><span class="token punctuation">:</span> <span class="token class-name">Into</span><span class="token operator">&lt;</span><span class="token class-name">Rad</span><span class="token operator">&lt;</span><span class="token keyword">f32</span><span class="token operator">&gt;&gt;</span><span class="token operator">&gt;</span><span class="token punctuation">(</span>
width<span class="token punctuation">:</span> <span class="token keyword">u32</span><span class="token punctuation">,</span>
height<span class="token punctuation">:</span> <span class="token keyword">u32</span><span class="token punctuation">,</span>
fovy<span class="token punctuation">:</span> <span class="token class-name">F</span><span class="token punctuation">,</span>
znear<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
zfar<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">Self</span> <span class="token punctuation">{</span>
<span class="token keyword">Self</span> <span class="token punctuation">{</span>
aspect<span class="token punctuation">:</span> width <span class="token keyword">as</span> <span class="token keyword">f32</span> <span class="token operator">/</span> height <span class="token keyword">as</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
fovy<span class="token punctuation">:</span> fovy<span class="token punctuation">.</span><span class="token function">into</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
znear<span class="token punctuation">,</span>
zfar<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">fn</span> <span class="token function-definition function">resize</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> width<span class="token punctuation">:</span> <span class="token keyword">u32</span><span class="token punctuation">,</span> height<span class="token punctuation">:</span> <span class="token keyword">u32</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>aspect <span class="token operator">=</span> width <span class="token keyword">as</span> <span class="token keyword">f32</span> <span class="token operator">/</span> height <span class="token keyword">as</span> <span class="token keyword">f32</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">calc_matrix</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">Matrix4</span><span class="token operator">&lt;</span><span class="token keyword">f32</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
<span class="token constant">OPENGL_TO_WGPU_MATRIX</span> <span class="token operator">*</span> <span class="token function">perspective</span><span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">.</span>fovy<span class="token punctuation">,</span> <span class="token keyword">self</span><span class="token punctuation">.</span>aspect<span class="token punctuation">,</span> <span class="token keyword">self</span><span class="token punctuation">.</span>znear<span class="token punctuation">,</span> <span class="token keyword">self</span><span class="token punctuation">.</span>zfar<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>On thing to note: <code>cgmath</code> currently returns a right-handed projection matrix from the <code>perspective</code> function. This means that the z-axis points out of the screen. If you want the z-axis to be <em>into</em> the screen (aka. a left-handed projection matrix), you'll have to code your own.</p> <p>You can tell the difference between a right-handed coordinate system and a left-handed one by using your hands. Point your thumb to the right. This is the x-axis. Point your pointer finger up. This is the y-axis. Extend your middle finger. This is the z-axis. On your right hand your middle finger should be pointing towards you. On your left hand it should be pointing away.</p> <p><img src="/learn-wgpu/assets/img/left_right_hand.ccabf5d0.gif" alt="./left_right_hand.gif"></p> <h1 id="the-camera-controller"><a href="#the-camera-controller" class="header-anchor">#</a> The Camera Controller</h1> <p>As our camera is different, so we'll need a new camera controller. Add the following to <code>camera.rs</code>.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token attribute attr-name">#[derive(Debug)]</span>
<span class="token keyword">pub</span> <span class="token keyword">struct</span> <span class="token type-definition class-name">CameraController</span> <span class="token punctuation">{</span>
amount_left<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
amount_right<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
amount_forward<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
amount_backward<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
amount_up<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
amount_down<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
rotate_horizontal<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
rotate_vertical<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
scroll<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
speed<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
sensitivity<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token keyword">impl</span> <span class="token class-name">CameraController</span> <span class="token punctuation">{</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">new</span><span class="token punctuation">(</span>speed<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span> sensitivity<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">Self</span> <span class="token punctuation">{</span>
<span class="token keyword">Self</span> <span class="token punctuation">{</span>
amount_left<span class="token punctuation">:</span> <span class="token number">0.0</span><span class="token punctuation">,</span>
amount_right<span class="token punctuation">:</span> <span class="token number">0.0</span><span class="token punctuation">,</span>
amount_forward<span class="token punctuation">:</span> <span class="token number">0.0</span><span class="token punctuation">,</span>
amount_backward<span class="token punctuation">:</span> <span class="token number">0.0</span><span class="token punctuation">,</span>
amount_up<span class="token punctuation">:</span> <span class="token number">0.0</span><span class="token punctuation">,</span>
amount_down<span class="token punctuation">:</span> <span class="token number">0.0</span><span class="token punctuation">,</span>
rotate_horizontal<span class="token punctuation">:</span> <span class="token number">0.0</span><span class="token punctuation">,</span>
rotate_vertical<span class="token punctuation">:</span> <span class="token number">0.0</span><span class="token punctuation">,</span>
scroll<span class="token punctuation">:</span> <span class="token number">0.0</span><span class="token punctuation">,</span>
speed<span class="token punctuation">,</span>
sensitivity<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">fn</span> <span class="token function-definition function">process_keyboard</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> key<span class="token punctuation">:</span> <span class="token class-name">VirtualKeyCode</span><span class="token punctuation">,</span> state<span class="token punctuation">:</span> <span class="token class-name">ElementState</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">bool</span><span class="token punctuation">{</span>
<span class="token keyword">let</span> amount <span class="token operator">=</span> <span class="token keyword">if</span> state <span class="token operator">==</span> <span class="token class-name">ElementState</span><span class="token punctuation">::</span><span class="token class-name">Pressed</span> <span class="token punctuation">{</span> <span class="token number">1.0</span> <span class="token punctuation">}</span> <span class="token keyword">else</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 keyword">match</span> key <span class="token punctuation">{</span>
<span class="token class-name">VirtualKeyCode</span><span class="token punctuation">::</span><span class="token class-name">W</span> <span class="token operator">|</span> <span class="token class-name">VirtualKeyCode</span><span class="token punctuation">::</span><span class="token class-name">Up</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>amount_forward <span class="token operator">=</span> amount<span class="token punctuation">;</span>
<span class="token boolean">true</span>
<span class="token punctuation">}</span>
<span class="token class-name">VirtualKeyCode</span><span class="token punctuation">::</span><span class="token class-name">S</span> <span class="token operator">|</span> <span class="token class-name">VirtualKeyCode</span><span class="token punctuation">::</span><span class="token class-name">Down</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>amount_backward <span class="token operator">=</span> amount<span class="token punctuation">;</span>
<span class="token boolean">true</span>
<span class="token punctuation">}</span>
<span class="token class-name">VirtualKeyCode</span><span class="token punctuation">::</span><span class="token class-name">A</span> <span class="token operator">|</span> <span class="token class-name">VirtualKeyCode</span><span class="token punctuation">::</span><span class="token class-name">Left</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>amount_left <span class="token operator">=</span> amount<span class="token punctuation">;</span>
<span class="token boolean">true</span>
<span class="token punctuation">}</span>
<span class="token class-name">VirtualKeyCode</span><span class="token punctuation">::</span><span class="token class-name">D</span> <span class="token operator">|</span> <span class="token class-name">VirtualKeyCode</span><span class="token punctuation">::</span><span class="token class-name">Right</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>amount_right <span class="token operator">=</span> amount<span class="token punctuation">;</span>
<span class="token boolean">true</span>
<span class="token punctuation">}</span>
<span class="token class-name">VirtualKeyCode</span><span class="token punctuation">::</span><span class="token class-name">Space</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>amount_up <span class="token operator">=</span> amount<span class="token punctuation">;</span>
<span class="token boolean">true</span>
<span class="token punctuation">}</span>
<span class="token class-name">VirtualKeyCode</span><span class="token punctuation">::</span><span class="token class-name">LShift</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>amount_down <span class="token operator">=</span> amount<span class="token punctuation">;</span>
<span class="token boolean">true</span>
<span class="token punctuation">}</span>
_ <span class="token operator">=&gt;</span> <span class="token boolean">false</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">fn</span> <span class="token function-definition function">process_mouse</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> mouse_dx<span class="token punctuation">:</span> <span class="token keyword">f64</span><span class="token punctuation">,</span> mouse_dy<span class="token punctuation">:</span> <span class="token keyword">f64</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>rotate_horizontal <span class="token operator">=</span> mouse_dx <span class="token keyword">as</span> <span class="token keyword">f32</span><span class="token punctuation">;</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>rotate_vertical <span class="token operator">=</span> mouse_dy <span class="token keyword">as</span> <span class="token keyword">f32</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">process_scroll</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> delta<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token class-name">MouseScrollDelta</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>scroll <span class="token operator">=</span> <span class="token operator">-</span><span class="token keyword">match</span> delta <span class="token punctuation">{</span>
<span class="token comment">// I'm assuming a line is about 100 pixels</span>
<span class="token class-name">MouseScrollDelta</span><span class="token punctuation">::</span><span class="token class-name">LineDelta</span><span class="token punctuation">(</span>_<span class="token punctuation">,</span> scroll<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> scroll <span class="token operator">*</span> <span class="token number">100.0</span><span class="token punctuation">,</span>
<span class="token class-name">MouseScrollDelta</span><span class="token punctuation">::</span><span class="token class-name">PixelDelta</span><span class="token punctuation">(</span><span class="token class-name">PhysicalPosition</span> <span class="token punctuation">{</span>
y<span class="token punctuation">:</span> scroll<span class="token punctuation">,</span>
<span class="token punctuation">..</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token operator">*</span>scroll <span class="token keyword">as</span> <span class="token keyword">f32</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">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">update_camera</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> camera<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token class-name">Camera</span><span class="token punctuation">,</span> dt<span class="token punctuation">:</span> <span class="token class-name">Duration</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">let</span> dt <span class="token operator">=</span> dt<span class="token punctuation">.</span><span class="token function">as_secs_f32</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Move forward/backward and left/right</span>
<span class="token keyword">let</span> <span class="token punctuation">(</span>yaw_sin<span class="token punctuation">,</span> yaw_cos<span class="token punctuation">)</span> <span class="token operator">=</span> camera<span class="token punctuation">.</span>yaw<span class="token number">.0</span><span class="token punctuation">.</span><span class="token function">sin_cos</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> forward <span class="token operator">=</span> <span class="token class-name">Vector3</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span>yaw_cos<span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">,</span> yaw_sin<span class="token punctuation">)</span><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 keyword">let</span> right <span class="token operator">=</span> <span class="token class-name">Vector3</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token operator">-</span>yaw_sin<span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">,</span> yaw_cos<span class="token punctuation">)</span><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>
camera<span class="token punctuation">.</span>position <span class="token operator">+=</span> forward <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">.</span>amount_forward <span class="token operator">-</span> <span class="token keyword">self</span><span class="token punctuation">.</span>amount_backward<span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token keyword">self</span><span class="token punctuation">.</span>speed <span class="token operator">*</span> dt<span class="token punctuation">;</span>
camera<span class="token punctuation">.</span>position <span class="token operator">+=</span> right <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">.</span>amount_right <span class="token operator">-</span> <span class="token keyword">self</span><span class="token punctuation">.</span>amount_left<span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token keyword">self</span><span class="token punctuation">.</span>speed <span class="token operator">*</span> dt<span class="token punctuation">;</span>
<span class="token comment">// Move in/out (aka. &quot;zoom&quot;)</span>
<span class="token comment">// Note: this isn't an actual zoom. The camera's position</span>
<span class="token comment">// changes when zooming. I've added this to make it easier</span>
<span class="token comment">// to get closer to an object you want to focus on.</span>
<span class="token keyword">let</span> <span class="token punctuation">(</span>pitch_sin<span class="token punctuation">,</span> pitch_cos<span class="token punctuation">)</span> <span class="token operator">=</span> camera<span class="token punctuation">.</span>pitch<span class="token number">.0</span><span class="token punctuation">.</span><span class="token function">sin_cos</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> scrollward <span class="token operator">=</span> <span class="token class-name">Vector3</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span>pitch_cos <span class="token operator">*</span> yaw_cos<span class="token punctuation">,</span> pitch_sin<span class="token punctuation">,</span> pitch_cos <span class="token operator">*</span> yaw_sin<span class="token punctuation">)</span><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>
camera<span class="token punctuation">.</span>position <span class="token operator">+=</span> scrollward <span class="token operator">*</span> <span class="token keyword">self</span><span class="token punctuation">.</span>scroll <span class="token operator">*</span> <span class="token keyword">self</span><span class="token punctuation">.</span>speed <span class="token operator">*</span> <span class="token keyword">self</span><span class="token punctuation">.</span>sensitivity <span class="token operator">*</span> dt<span class="token punctuation">;</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>scroll <span class="token operator">=</span> <span class="token number">0.0</span><span class="token punctuation">;</span>
<span class="token comment">// Move up/down. Since we don't use roll, we can just</span>
<span class="token comment">// modify the y coordinate directly.</span>
camera<span class="token punctuation">.</span>position<span class="token punctuation">.</span>y <span class="token operator">+=</span> <span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">.</span>amount_up <span class="token operator">-</span> <span class="token keyword">self</span><span class="token punctuation">.</span>amount_down<span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token keyword">self</span><span class="token punctuation">.</span>speed <span class="token operator">*</span> dt<span class="token punctuation">;</span>
<span class="token comment">// Rotate</span>
camera<span class="token punctuation">.</span>yaw <span class="token operator">+=</span> <span class="token class-name">Rad</span><span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">.</span>rotate_horizontal<span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token keyword">self</span><span class="token punctuation">.</span>sensitivity <span class="token operator">*</span> dt<span class="token punctuation">;</span>
camera<span class="token punctuation">.</span>pitch <span class="token operator">+=</span> <span class="token class-name">Rad</span><span class="token punctuation">(</span><span class="token operator">-</span><span class="token keyword">self</span><span class="token punctuation">.</span>rotate_vertical<span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token keyword">self</span><span class="token punctuation">.</span>sensitivity <span class="token operator">*</span> dt<span class="token punctuation">;</span>
<span class="token comment">// If process_mouse isn't called every frame, these values</span>
<span class="token comment">// will not get set to zero, and the camera will rotate</span>
<span class="token comment">// when moving in a non cardinal direction.</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>rotate_horizontal <span class="token operator">=</span> <span class="token number">0.0</span><span class="token punctuation">;</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>rotate_vertical <span class="token operator">=</span> <span class="token number">0.0</span><span class="token punctuation">;</span>
<span class="token comment">// Keep the camera's angle from going too high/low.</span>
<span class="token keyword">if</span> camera<span class="token punctuation">.</span>pitch <span class="token operator">&lt;</span> <span class="token operator">-</span><span class="token class-name">Rad</span><span class="token punctuation">(</span><span class="token constant">FRAC_PI_2</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
camera<span class="token punctuation">.</span>pitch <span class="token operator">=</span> <span class="token operator">-</span><span class="token class-name">Rad</span><span class="token punctuation">(</span><span class="token constant">FRAC_PI_2</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 keyword">if</span> camera<span class="token punctuation">.</span>pitch <span class="token operator">&gt;</span> <span class="token class-name">Rad</span><span class="token punctuation">(</span><span class="token constant">FRAC_PI_2</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
camera<span class="token punctuation">.</span>pitch <span class="token operator">=</span> <span class="token class-name">Rad</span><span class="token punctuation">(</span><span class="token constant">FRAC_PI_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>
</code></pre></div><h2 id="cleaning-up-main-rs"><a href="#cleaning-up-main-rs" class="header-anchor">#</a> Cleaning up <code>main.rs</code></h2> <p>First things first we need to delete <code>Camera</code> and <code>CameraController</code> as well as the extra <code>OPENGL_TO_WGPU_MATRIX</code> from <code>main.rs</code>. Once you've done that import <code>camera.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">model</span><span class="token punctuation">;</span>
<span class="token keyword">mod</span> <span class="token module-declaration namespace">texture</span><span class="token punctuation">;</span>
<span class="token keyword">mod</span> <span class="token module-declaration namespace">camera</span><span class="token punctuation">;</span> <span class="token comment">// NEW!</span>
</code></pre></div><p>We need to update <code>update_view_proj</code> to use our new <code>Camera</code> and <code>Projection</code>.</p> <div class="language-rust extra-class"><pre class="language-rust"><code>
<span class="token keyword">impl</span> <span class="token class-name">Uniforms</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
<span class="token comment">// UPDATED!</span>
<span class="token keyword">fn</span> <span class="token function-definition function">update_view_proj</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> camera<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token namespace">camera<span class="token punctuation">::</span></span><span class="token class-name">Camera</span><span class="token punctuation">,</span> projection<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token namespace">camera<span class="token punctuation">::</span></span><span class="token class-name">Projection</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>view_position <span class="token operator">=</span> camera<span class="token punctuation">.</span>position<span class="token punctuation">.</span><span class="token function">to_homogeneous</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>view_proj <span class="token operator">=</span> projection<span class="token punctuation">.</span><span class="token function">calc_matrix</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">*</span> camera<span class="token punctuation">.</span><span class="token function">calc_matrix</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>We need to change our <code>State</code> to use our <code>Camera</code>, <code>CameraProjection</code> and <code>Projection</code> as well. We'll also add two fields for later: <code>last_mouse_pos</code>, and <code>mouse_pressed</code>.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">struct</span> <span class="token type-definition class-name">State</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
camera<span class="token punctuation">:</span> <span class="token namespace">camera<span class="token punctuation">::</span></span><span class="token class-name">Camera</span><span class="token punctuation">,</span> <span class="token comment">// UPDATED!</span>
projection<span class="token punctuation">:</span> <span class="token namespace">camera<span class="token punctuation">::</span></span><span class="token class-name">Projection</span><span class="token punctuation">,</span> <span class="token comment">// NEW!</span>
camera_controller<span class="token punctuation">:</span> <span class="token namespace">camera<span class="token punctuation">::</span></span><span class="token class-name">CameraController</span><span class="token punctuation">,</span> <span class="token comment">// UPDATED!</span>
<span class="token comment">// ...</span>
<span class="token comment">// NEW!</span>
last_mouse_pos<span class="token punctuation">:</span> <span class="token class-name">PhysicalPosition</span><span class="token operator">&lt;</span><span class="token keyword">f64</span><span class="token operator">&gt;</span><span class="token punctuation">,</span>
mouse_pressed<span class="token punctuation">:</span> <span class="token keyword">bool</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
</code></pre></div><p>You'll need to import <code>winit::dpi::PhysicalPosition</code> if you haven't already.</p> <p>We need to update <code>new()</code> as well.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">impl</span> <span class="token class-name">State</span> <span class="token punctuation">{</span>
<span class="token keyword">async</span> <span class="token keyword">fn</span> <span class="token function-definition function">new</span><span class="token punctuation">(</span>window<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token class-name">Window</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">Self</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
<span class="token comment">// UPDATED!</span>
<span class="token keyword">let</span> camera <span class="token operator">=</span> <span class="token namespace">camera<span class="token punctuation">::</span></span><span class="token class-name">Camera</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 number">0.0</span><span class="token punctuation">,</span> <span class="token number">5.0</span><span class="token punctuation">,</span> <span class="token number">10.0</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 operator">-</span><span class="token number">90.0</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 operator">-</span><span class="token number">20.0</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> projection <span class="token operator">=</span> <span class="token namespace">camera<span class="token punctuation">::</span></span><span class="token class-name">Projection</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span>sc_desc<span class="token punctuation">.</span>width<span class="token punctuation">,</span> sc_desc<span class="token punctuation">.</span>height<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 number">0.1</span><span class="token punctuation">,</span> <span class="token number">100.0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> camera_controller <span class="token operator">=</span> <span class="token namespace">camera<span class="token punctuation">::</span></span><span class="token class-name">CameraController</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token number">4.0</span><span class="token punctuation">,</span> <span class="token number">0.4</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// ...</span>
<span class="token keyword">Self</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
camera<span class="token punctuation">,</span>
projection<span class="token punctuation">,</span>
camera_controller<span class="token punctuation">,</span>
<span class="token comment">// ...</span>
<span class="token comment">// NEW!</span>
last_mouse_pos<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token number">0.0</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 function">into</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
mouse_pressed<span class="token punctuation">:</span> <span class="token boolean">false</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>We need to change our <code>projection</code> in <code>resize</code> as well.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">fn</span> <span class="token function-definition function">resize</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> new_size<span class="token punctuation">:</span> <span class="token namespace">winit<span class="token punctuation">::</span>dpi<span class="token punctuation">::</span></span><span class="token class-name">PhysicalSize</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 comment">// UPDATED!</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>projection<span class="token punctuation">.</span><span class="token function">resize</span><span class="token punctuation">(</span>new_size<span class="token punctuation">.</span>width<span class="token punctuation">,</span> new_size<span class="token punctuation">.</span>height<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// ...</span>
<span class="token punctuation">}</span>
</code></pre></div><p><code>input</code> will need to be updated as well.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token comment">// UPDATED!</span>
<span class="token keyword">fn</span> <span class="token function-definition function">input</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> event<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token class-name">WindowEvent</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">bool</span> <span class="token punctuation">{</span>
<span class="token keyword">match</span> event <span class="token punctuation">{</span>
<span class="token class-name">WindowEvent</span><span class="token punctuation">::</span><span class="token class-name">KeyboardInput</span> <span class="token punctuation">{</span>
input<span class="token punctuation">:</span> <span class="token class-name">KeyboardInput</span> <span class="token punctuation">{</span>
virtual_keycode<span class="token punctuation">:</span> <span class="token class-name">Some</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span><span class="token punctuation">,</span>
state<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 operator">=&gt;</span> <span class="token keyword">self</span><span class="token punctuation">.</span>camera_controller<span class="token punctuation">.</span><span class="token function">process_keyboard</span><span class="token punctuation">(</span><span class="token operator">*</span>key<span class="token punctuation">,</span> <span class="token operator">*</span>state<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token class-name">WindowEvent</span><span class="token punctuation">::</span><span class="token class-name">MouseWheel</span> <span class="token punctuation">{</span>
delta<span class="token punctuation">,</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 keyword">self</span><span class="token punctuation">.</span>camera_controller<span class="token punctuation">.</span><span class="token function">process_scroll</span><span class="token punctuation">(</span>delta<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token boolean">true</span>
<span class="token punctuation">}</span>
<span class="token class-name">WindowEvent</span><span class="token punctuation">::</span><span class="token class-name">MouseInput</span> <span class="token punctuation">{</span>
button<span class="token punctuation">:</span> <span class="token class-name">MouseButton</span><span class="token punctuation">::</span><span class="token class-name">Left</span><span class="token punctuation">,</span>
state<span class="token punctuation">,</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 keyword">self</span><span class="token punctuation">.</span>mouse_pressed <span class="token operator">=</span> <span class="token operator">*</span>state <span class="token operator">==</span> <span class="token class-name">ElementState</span><span class="token punctuation">::</span><span class="token class-name">Pressed</span><span class="token punctuation">;</span>
<span class="token boolean">true</span>
<span class="token punctuation">}</span>
<span class="token class-name">WindowEvent</span><span class="token punctuation">::</span><span class="token class-name">CursorMoved</span> <span class="token punctuation">{</span>
position<span class="token punctuation">,</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 keyword">let</span> mouse_dx <span class="token operator">=</span> position<span class="token punctuation">.</span>x <span class="token operator">-</span> <span class="token keyword">self</span><span class="token punctuation">.</span>last_mouse_pos<span class="token punctuation">.</span>x<span class="token punctuation">;</span>
<span class="token keyword">let</span> mouse_dy <span class="token operator">=</span> position<span class="token punctuation">.</span>y <span class="token operator">-</span> <span class="token keyword">self</span><span class="token punctuation">.</span>last_mouse_pos<span class="token punctuation">.</span>y<span class="token punctuation">;</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>last_mouse_pos <span class="token operator">=</span> <span class="token operator">*</span>position<span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token keyword">self</span><span class="token punctuation">.</span>mouse_pressed <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>camera_controller<span class="token punctuation">.</span><span class="token function">process_mouse</span><span class="token punctuation">(</span>mouse_dx<span class="token punctuation">,</span> mouse_dy<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token boolean">true</span>
<span class="token punctuation">}</span>
_ <span class="token operator">=&gt;</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>The <code>update</code> function requires a bit more explanation. The <code>update_camera</code> function on the <code>CameraController</code> has a parameter <code>dt: Duration</code> which is the delta time or time between frames. This is to help smooth out the camera movement so that it's not locked be the framerate. Currently we aren't calculating <code>dt</code>, so I decided to pass it into <code>update</code> as a parameter.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">fn</span> <span class="token function-definition function">update</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> dt<span class="token punctuation">:</span> <span class="token namespace">std<span class="token punctuation">::</span>time<span class="token punctuation">::</span></span><span class="token class-name">Duration</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// UPDATED!</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>camera_controller<span class="token punctuation">.</span><span class="token function">update_camera</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>camera<span class="token punctuation">,</span> dt<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>uniforms<span class="token punctuation">.</span><span class="token function">update_view_proj</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">.</span>camera<span class="token punctuation">,</span> <span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">.</span>projection<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// ..</span>
<span class="token punctuation">}</span>
</code></pre></div><p>While we're at it, let's use <code>dt</code> for the light's rotation as well.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">self</span><span class="token punctuation">.</span>light<span class="token punctuation">.</span>position <span class="token operator">=</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 punctuation">(</span><span class="token number">0.0</span><span class="token punctuation">,</span> <span class="token number">1.0</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 function">into</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">60.0</span> <span class="token operator">*</span> dt<span class="token punctuation">.</span><span class="token function">as_secs_f32</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token operator">*</span> old_position<span class="token punctuation">;</span> <span class="token comment">// UPDATED!</span>
</code></pre></div><p>We still need to calculate <code>dt</code>. Let's do that in the <code>main</code> function.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><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">{</span>
<span class="token comment">// ...</span>
<span class="token keyword">let</span> <span class="token keyword">mut</span> state <span class="token operator">=</span> <span class="token function">block_on</span><span class="token punctuation">(</span><span class="token class-name">State</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>window<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> last_render_time <span class="token operator">=</span> <span class="token namespace">std<span class="token punctuation">::</span>time<span class="token punctuation">::</span></span><span class="token class-name">Instant</span><span class="token punctuation">::</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
event_loop<span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token keyword">move</span> <span class="token closure-params"><span class="token closure-punctuation punctuation">|</span>event<span class="token punctuation">,</span> _<span class="token punctuation">,</span> control_flow<span class="token closure-punctuation punctuation">|</span></span> <span class="token punctuation">{</span>
<span class="token operator">*</span>control_flow <span class="token operator">=</span> <span class="token class-name">ControlFlow</span><span class="token punctuation">::</span><span class="token class-name">Poll</span><span class="token punctuation">;</span>
<span class="token keyword">match</span> event <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
<span class="token comment">// UPDATED!</span>
<span class="token class-name">Event</span><span class="token punctuation">::</span><span class="token class-name">RedrawRequested</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 keyword">let</span> now <span class="token operator">=</span> <span class="token namespace">std<span class="token punctuation">::</span>time<span class="token punctuation">::</span></span><span class="token class-name">Instant</span><span class="token punctuation">::</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> dt <span class="token operator">=</span> now <span class="token operator">-</span> last_render_time<span class="token punctuation">;</span>
last_render_time <span class="token operator">=</span> now<span class="token punctuation">;</span>
state<span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span>dt<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// ...</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 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>With that we should be able to move our camera wherever we want.</p> <p><img src="/learn-wgpu/assets/img/screenshot.4f5740bc.png" alt="./screenshot.png"></p> <div class="auto-github-link"><a href="https://github.com/sotrh/learn-wgpu/tree/master/code/intermediate/tutorial12-camera/" target="_blank" rel="noopener noreferrer">Check out the code!</a> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" 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></div></div> <footer class="page-edit"><!----> <div class="last-updated"><span class="prefix">Last Updated: </span> <span class="time">11/11/2020, 3:41:06 PM</span></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
<a href="/learn-wgpu/intermediate/tutorial11-normals/" class="prev">
Normal Mapping
</a></span> <span class="next"><a href="/learn-wgpu/intermediate/tutorial13-threading/">
Multi-threading with Wgpu and Rayon
</a>
</span></p></div> </main></div></div><div class="global-ui"><!----></div></div>
<script src="/learn-wgpu/assets/js/app.10252059.js" defer></script><script src="/learn-wgpu/assets/js/2.6a9f728b.js" defer></script><script src="/learn-wgpu/assets/js/14.90ed5917.js" defer></script><script src="/learn-wgpu/assets/js/22.2132e362.js" defer></script>
</body>
</html>

@ -0,0 +1,138 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Multi-threading with Wgpu and Rayon | Learn Wgpu</title>
<meta name="description" content="">
<meta name="generator" content="VuePress 1.4.0">
<meta property="article:modified_time" content="2020-09-28T04:52:35.000Z"><meta property="og:site_name" content="Learn Wgpu"><meta property="og:title" content="Multi-threading with Wgpu and Rayon"><meta property="og:type" content="website"><meta property="og:url" content="/intermediate/tutorial13-threading/"><meta name="twitter:title" content="Multi-threading with Wgpu and Rayon"><meta name="twitter:url" content="/intermediate/tutorial13-threading/"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:label1" content="Written by"><meta name="twitter:data2" content="Benjamin R Hansen"><meta name="twitter:creator" content="https://twitter.com/sotrh760">
<link rel="preload" href="/learn-wgpu/assets/css/0.styles.7acc6ef6.css" as="style"><link rel="preload" href="/learn-wgpu/assets/js/app.10252059.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/2.6a9f728b.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/26.8484ba66.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/22.2132e362.js" as="script"><link rel="prefetch" href="/learn-wgpu/assets/js/10.de8cadfb.js"><link rel="prefetch" href="/learn-wgpu/assets/js/11.53581734.js"><link rel="prefetch" href="/learn-wgpu/assets/js/12.8c46a0c8.js"><link rel="prefetch" href="/learn-wgpu/assets/js/13.4723ba5d.js"><link rel="prefetch" href="/learn-wgpu/assets/js/14.90ed5917.js"><link rel="prefetch" href="/learn-wgpu/assets/js/15.3056a06c.js"><link rel="prefetch" href="/learn-wgpu/assets/js/16.0af06f1e.js"><link rel="prefetch" href="/learn-wgpu/assets/js/17.1d99e854.js"><link rel="prefetch" href="/learn-wgpu/assets/js/18.9923f29d.js"><link rel="prefetch" href="/learn-wgpu/assets/js/19.dab68ffd.js"><link rel="prefetch" href="/learn-wgpu/assets/js/20.70e640cc.js"><link rel="prefetch" href="/learn-wgpu/assets/js/21.1dba0934.js"><link rel="prefetch" href="/learn-wgpu/assets/js/23.1a88f225.js"><link rel="prefetch" href="/learn-wgpu/assets/js/24.585372be.js"><link rel="prefetch" href="/learn-wgpu/assets/js/25.022f80fd.js"><link rel="prefetch" href="/learn-wgpu/assets/js/27.8b0a41bf.js"><link rel="prefetch" href="/learn-wgpu/assets/js/28.b9bf1b57.js"><link rel="prefetch" href="/learn-wgpu/assets/js/29.5c3f77ba.js"><link rel="prefetch" href="/learn-wgpu/assets/js/3.df177b88.js"><link rel="prefetch" href="/learn-wgpu/assets/js/30.dc887be9.js"><link rel="prefetch" href="/learn-wgpu/assets/js/4.89cbdecc.js"><link rel="prefetch" href="/learn-wgpu/assets/js/5.c2eff02b.js"><link rel="prefetch" href="/learn-wgpu/assets/js/6.086069e3.js"><link rel="prefetch" href="/learn-wgpu/assets/js/7.65364b9b.js"><link rel="prefetch" href="/learn-wgpu/assets/js/8.1fd4cc1c.js"><link rel="prefetch" href="/learn-wgpu/assets/js/9.ecb6e79c.js">
<link rel="stylesheet" href="/learn-wgpu/assets/css/0.styles.7acc6ef6.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/" class="sidebar-link">Introduction</a></li><li><section class="sidebar-group depth-0"><p class="sidebar-heading"><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-swapchain/" class="sidebar-link">The Swapchain</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/" class="sidebar-link">Model Loading</a></li></ul></section></li><li><section class="sidebar-group depth-0"><p class="sidebar-heading open"><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-threading/" class="active sidebar-link">Multi-threading with Wgpu and Rayon</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/learn-wgpu/intermediate/tutorial13-threading/#threading-build-rs" class="sidebar-link">Threading build.rs</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/intermediate/tutorial13-threading/#parallelizing-loading-models-and-textures" class="sidebar-link">Parallelizing loading models and textures</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/intermediate/tutorial13-threading/#it-s-that-easy" class="sidebar-link">It's that easy!</a></li></ul></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><a href="/learn-wgpu/news/" class="sidebar-link">News</a></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><h1 id="multi-threading-with-wgpu-and-rayon"><a href="#multi-threading-with-wgpu-and-rayon" class="header-anchor">#</a> Multi-threading with Wgpu and Rayon</h1> <p>The main selling point of Vulkan, DirectX 12, Metal, and by extension Wgpu is that these APIs is that they designed from the ground up to be thread safe. Up to this point we have been doing everything on a single thread. That's about to change.</p> <div class="note"><p>I won't go into what threads are in this tutorial. That is a course in and of itself. All we'll be covering is using threading to make loading resources faster.</p> <p>We won't go over multithreading rendering as we don't have enough different types of objects to justify that yet. This will change in a coming tutorial</p></div> <h2 id="threading-build-rs"><a href="#threading-build-rs" class="header-anchor">#</a> Threading build.rs</h2> <p>If you remember <a href="../../beginner/tutorial3-pipeline">the pipeline tutorial</a>, we created a build script to compile our GLSL shaders to spirv. That had a section in the <code>main</code> function that looked like this.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token comment">// This could be parallelized</span>
<span class="token keyword">let</span> shaders <span class="token operator">=</span> shader_paths<span class="token punctuation">.</span><span class="token function">iter_mut</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">flatten</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>glob_result<span class="token closure-punctuation punctuation">|</span></span> <span class="token punctuation">{</span>
<span class="token class-name">ShaderData</span><span class="token punctuation">::</span><span class="token function">load</span><span class="token punctuation">(</span>glob_result<span class="token operator">?</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 class-name">Result</span><span class="token operator">&lt;</span>_<span class="token operator">&gt;&gt;</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 function">into_iter</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">Result</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 operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>That <code>This could be parallelized</code> comment will soon become <code>This is parallelized</code>. We're going to add a build dependecy to <a href="https://docs.rs/rayon" target="_blank" rel="noopener noreferrer">rayon<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" 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></a> 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">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>
<span class="token key property">rayon</span> <span class="token punctuation">=</span> <span class="token string">&quot;1.4&quot;</span> <span class="token comment"># NEW!</span>
<span class="token key property">shaderc</span> <span class="token punctuation">=</span> <span class="token string">&quot;0.6&quot;</span>
</code></pre></div><p>First some housekeeping. Our <code>build.rs</code> code currently uses an array to store the globs to find our projects shaders. We're going to switch to using a <code>Vec</code> to make things play nicer with <code>rayon</code>.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token comment">// Collect all shaders recursively within /src/</span>
<span class="token comment">// UDPATED!</span>
<span class="token keyword">let</span> <span class="token keyword">mut</span> shader_paths <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>
shader_paths<span class="token punctuation">.</span><span class="token function">extend</span><span class="token punctuation">(</span><span class="token function">glob</span><span class="token punctuation">(</span><span class="token string">&quot;./src/**/*.vert&quot;</span><span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
shader_paths<span class="token punctuation">.</span><span class="token function">extend</span><span class="token punctuation">(</span><span class="token function">glob</span><span class="token punctuation">(</span><span class="token string">&quot;./src/**/*.frag&quot;</span><span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
shader_paths<span class="token punctuation">.</span><span class="token function">extend</span><span class="token punctuation">(</span><span class="token function">glob</span><span class="token punctuation">(</span><span class="token string">&quot;./src/**/*.comp&quot;</span><span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>We'll also need to import <code>rayon</code> as well.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">use</span> <span class="token namespace">rayon<span class="token punctuation">::</span>prelude<span class="token punctuation">::</span></span><span class="token operator">*</span><span class="token punctuation">;</span>
</code></pre></div><p>Now we can change our shader source collection code to the following.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token comment">// UPDATED!</span>
<span class="token comment">// This is parallelized</span>
<span class="token keyword">let</span> shaders <span class="token operator">=</span> shader_paths<span class="token punctuation">.</span><span class="token function">into_par_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>glob_result<span class="token closure-punctuation punctuation">|</span></span> <span class="token punctuation">{</span>
<span class="token class-name">ShaderData</span><span class="token punctuation">::</span><span class="token function">load</span><span class="token punctuation">(</span>glob_result<span class="token operator">?</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 class-name">Result</span><span class="token operator">&lt;</span>_<span class="token operator">&gt;&gt;</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 function">into_iter</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">Result</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 operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>Super simple isn't it? By using <code>into_par_iter</code>, <code>rayon</code> will try to spread our shader loading across multiple threads if it can. This means that our build script will load the shader text source for multiple shaders at the same time. This has the potential to drastically reduce our build times.</p> <p>We can compare the speeds of our compilation by running <code>cargo build</code> on both this tutorial and the previous one.</p> <div class="language-bash extra-class"><pre class="language-bash"><code>$ cargo build --bin tutorial12-camera
Compiling tutorial12-camera v0.1.0 <span class="token punctuation">(</span>/home/benjamin/dev/learn-wgpu/code/intermediate/tutorial12-camera<span class="token punctuation">)</span>
Finished dev <span class="token punctuation">[</span>unoptimized + debuginfo<span class="token punctuation">]</span> target<span class="token punctuation">(</span>s<span class="token punctuation">)</span> <span class="token keyword">in</span> 1m 13s
$ cargo build --bin tutorial13-threading
Compiling tutorial13-threading v0.1.0 <span class="token punctuation">(</span>/home/benjamin/dev/learn-wgpu/code/intermediate/tutorial13-threading<span class="token punctuation">)</span>
Finished dev <span class="token punctuation">[</span>unoptimized + debuginfo<span class="token punctuation">]</span> target<span class="token punctuation">(</span>s<span class="token punctuation">)</span> <span class="token keyword">in</span> <span class="token number">24</span>.33s
</code></pre></div><p>Our build speed is a little more than twice as fast!</p> <div class="note"><p>I got these build speeds after building the project one time to get <code>rayon</code> installed, and then deleting the .spv files from the previous two projects.</p></div> <h2 id="parallelizing-loading-models-and-textures"><a href="#parallelizing-loading-models-and-textures" class="header-anchor">#</a> Parallelizing loading models and textures</h2> <p>Currently we load the materials and meshes of our model one at a time. This is a perfect opportunity for multithreading! All our changes will be in <code>model.rs</code>. Let's first start with the materials. We'll convert the regular for loop into a <code>par_iter().map()</code>.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token comment">// model.rs</span>
<span class="token keyword">impl</span> <span class="token class-name">Model</span> <span class="token punctuation">{</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">load</span><span class="token operator">&lt;</span><span class="token class-name">P</span><span class="token punctuation">:</span> <span class="token class-name">AsRef</span><span class="token operator">&lt;</span><span class="token class-name">Path</span><span class="token operator">&gt;&gt;</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>
path<span class="token punctuation">:</span> <span class="token class-name">P</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 keyword">Self</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
<span class="token comment">// UPDATED!</span>
<span class="token keyword">let</span> materials <span class="token operator">=</span> obj_materials<span class="token punctuation">.</span><span class="token function">par_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>mat<span class="token closure-punctuation punctuation">|</span></span> <span class="token punctuation">{</span>
<span class="token comment">// We can also parallelize loading the textures!</span>
<span class="token keyword">let</span> <span class="token keyword">mut</span> textures <span class="token operator">=</span> <span class="token punctuation">[</span>
<span class="token punctuation">(</span>containing_folder<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>mat<span class="token punctuation">.</span>diffuse_texture<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">(</span>containing_folder<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>mat<span class="token punctuation">.</span>normal_texture<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token boolean">true</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">par_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><span class="token punctuation">(</span>texture_path<span class="token punctuation">,</span> is_normal_map<span class="token punctuation">)</span><span class="token closure-punctuation punctuation">|</span></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">load</span><span class="token punctuation">(</span>device<span class="token punctuation">,</span> queue<span class="token punctuation">,</span> texture_path<span class="token punctuation">,</span> <span class="token operator">*</span>is_normal_map<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">Result</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 operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">;</span>
<span class="token comment">// Pop removes from the end of the list.</span>
<span class="token keyword">let</span> normal_texture <span class="token operator">=</span> textures<span class="token punctuation">.</span><span class="token function">pop</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> diffuse_texture <span class="token operator">=</span> textures<span class="token punctuation">.</span><span class="token function">pop</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 class-name">Ok</span><span class="token punctuation">(</span><span class="token class-name">Material</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span>
device<span class="token punctuation">,</span>
<span class="token operator">&amp;</span>mat<span class="token punctuation">.</span>name<span class="token punctuation">,</span>
diffuse_texture<span class="token punctuation">,</span>
normal_texture<span class="token punctuation">,</span>
layout<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">Result</span><span class="token operator">&lt;</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;&gt;</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">;</span>
<span class="token comment">// ...</span>
<span class="token punctuation">}</span>
<span class="token comment">// ...</span>
<span class="token punctuation">}</span>
</code></pre></div><p>Next we can update the meshes to be loaded in parallel.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">impl</span> <span class="token class-name">Model</span> <span class="token punctuation">{</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">load</span><span class="token operator">&lt;</span><span class="token class-name">P</span><span class="token punctuation">:</span> <span class="token class-name">AsRef</span><span class="token operator">&lt;</span><span class="token class-name">Path</span><span class="token operator">&gt;&gt;</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>
path<span class="token punctuation">:</span> <span class="token class-name">P</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 keyword">Self</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
<span class="token comment">// UPDATED!</span>
<span class="token keyword">let</span> meshes <span class="token operator">=</span> obj_models<span class="token punctuation">.</span><span class="token function">par_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> <span class="token keyword">mut</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">into_par_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>i<span class="token closure-punctuation punctuation">|</span></span> <span class="token punctuation">{</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><span class="token function">into</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><span class="token function">into</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 function">into</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token comment">// We'll calculate these later</span>
tangent<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token number">0.0</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 function">into</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
bitangent<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token number">0.0</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 function">into</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 comment">// ...</span>
<span class="token punctuation">}</span>
<span class="token comment">// ...</span>
<span class="token punctuation">}</span>
<span class="token comment">// ...</span>
<span class="token punctuation">}</span>
</code></pre></div><p>We've parallelized loading the meshes, and making the vertex array for them. Propably a bit overkill, but <code>rayon</code> should prevent us from using too many threads.</p> <div class="note"><p>You'll notice that we didn't use <code>rayon</code> for calculating the tangent, and bitangent. I tried to get it to work, but I was having trouble finding a way to do it without multiple mutable references to <code>vertices</code>. I don't feel like introducing a <code>std::sync::Mutex</code>, so I'll leave it for now.</p> <p>This is honestly a better job for a compute shader, as the model data is going to get loaded into a buffer anyway.</p></div> <h2 id="it-s-that-easy"><a href="#it-s-that-easy" class="header-anchor">#</a> It's that easy!</h2> <p>Most of the <code>wgpu</code> types are <code>Send + Sync</code>, so we can use them in threads without much trouble. It was so easy, that I feel like this tutorial is too short! I'll just leave off with a speed comparison between the previous model loading code and the current code.</p> <div class="language- extra-class"><pre class="language-text"><code>Elapsed (Original): 309.596382ms
Elapsed (Threaded): 199.645027ms
</code></pre></div><p>We're not loading that many resources, so the speed up is minimal. We'll be doing more stuff with threading, but this is a good introduction.</p> <div class="auto-github-link"><a href="https://github.com/sotrh/learn-wgpu/tree/master/code/intermediate/tutorial13-threading/" target="_blank" rel="noopener noreferrer">Check out the code!</a> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" 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></div></div> <footer class="page-edit"><!----> <div class="last-updated"><span class="prefix">Last Updated: </span> <span class="time">9/27/2020, 10:52:35 PM</span></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
<a href="/learn-wgpu/intermediate/tutorial12-camera/" class="prev">
A Better Camera
</a></span> <span class="next"><a href="/learn-wgpu/showcase/">
Foreward
</a>
</span></p></div> </main></div></div><div class="global-ui"><!----></div></div>
<script src="/learn-wgpu/assets/js/app.10252059.js" defer></script><script src="/learn-wgpu/assets/js/2.6a9f728b.js" defer></script><script src="/learn-wgpu/assets/js/26.8484ba66.js" defer></script><script src="/learn-wgpu/assets/js/22.2132e362.js" defer></script>
</body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,127 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Compute Example: Tangents and Bitangents | Learn Wgpu</title>
<meta name="description" content="">
<meta name="generator" content="VuePress 1.4.0">
<meta property="article:modified_time" content="2020-11-21T20:16:07.000Z"><meta property="og:site_name" content="Learn Wgpu"><meta property="og:title" content="Compute Example: Tangents and Bitangents"><meta property="og:type" content="website"><meta property="og:url" content="/showcase/compute/"><meta name="twitter:title" content="Compute Example: Tangents and Bitangents"><meta name="twitter:url" content="/showcase/compute/"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:label1" content="Written by"><meta name="twitter:data2" content="Benjamin R Hansen"><meta name="twitter:creator" content="https://twitter.com/sotrh760">
<link rel="preload" href="/learn-wgpu/assets/css/0.styles.7acc6ef6.css" as="style"><link rel="preload" href="/learn-wgpu/assets/js/app.10252059.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/2.6a9f728b.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/7.65364b9b.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/22.2132e362.js" as="script"><link rel="prefetch" href="/learn-wgpu/assets/js/10.de8cadfb.js"><link rel="prefetch" href="/learn-wgpu/assets/js/11.53581734.js"><link rel="prefetch" href="/learn-wgpu/assets/js/12.8c46a0c8.js"><link rel="prefetch" href="/learn-wgpu/assets/js/13.4723ba5d.js"><link rel="prefetch" href="/learn-wgpu/assets/js/14.90ed5917.js"><link rel="prefetch" href="/learn-wgpu/assets/js/15.3056a06c.js"><link rel="prefetch" href="/learn-wgpu/assets/js/16.0af06f1e.js"><link rel="prefetch" href="/learn-wgpu/assets/js/17.1d99e854.js"><link rel="prefetch" href="/learn-wgpu/assets/js/18.9923f29d.js"><link rel="prefetch" href="/learn-wgpu/assets/js/19.dab68ffd.js"><link rel="prefetch" href="/learn-wgpu/assets/js/20.70e640cc.js"><link rel="prefetch" href="/learn-wgpu/assets/js/21.1dba0934.js"><link rel="prefetch" href="/learn-wgpu/assets/js/23.1a88f225.js"><link rel="prefetch" href="/learn-wgpu/assets/js/24.585372be.js"><link rel="prefetch" href="/learn-wgpu/assets/js/25.022f80fd.js"><link rel="prefetch" href="/learn-wgpu/assets/js/26.8484ba66.js"><link rel="prefetch" href="/learn-wgpu/assets/js/27.8b0a41bf.js"><link rel="prefetch" href="/learn-wgpu/assets/js/28.b9bf1b57.js"><link rel="prefetch" href="/learn-wgpu/assets/js/29.5c3f77ba.js"><link rel="prefetch" href="/learn-wgpu/assets/js/3.df177b88.js"><link rel="prefetch" href="/learn-wgpu/assets/js/30.dc887be9.js"><link rel="prefetch" href="/learn-wgpu/assets/js/4.89cbdecc.js"><link rel="prefetch" href="/learn-wgpu/assets/js/5.c2eff02b.js"><link rel="prefetch" href="/learn-wgpu/assets/js/6.086069e3.js"><link rel="prefetch" href="/learn-wgpu/assets/js/8.1fd4cc1c.js"><link rel="prefetch" href="/learn-wgpu/assets/js/9.ecb6e79c.js">
<link rel="stylesheet" href="/learn-wgpu/assets/css/0.styles.7acc6ef6.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/" class="sidebar-link">Introduction</a></li><li><section class="sidebar-group depth-0"><p class="sidebar-heading"><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-swapchain/" class="sidebar-link">The Swapchain</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/" class="sidebar-link">Model Loading</a></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-threading/" class="sidebar-link">Multi-threading with Wgpu and Rayon</a></li></ul></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading open"><span>Showcase</span> <span class="arrow down"></span></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/learn-wgpu/showcase/" class="sidebar-link">Foreward</a></li><li><a href="/learn-wgpu/showcase/windowless/" class="sidebar-link">Wgpu without a window</a></li><li><a href="/learn-wgpu/showcase/gifs/" class="sidebar-link">Creating gifs</a></li><li><a href="/learn-wgpu/showcase/pong/" class="sidebar-link">Pong</a></li><li><a href="/learn-wgpu/showcase/compute/" class="active sidebar-link">Compute Example: Tangents and Bitangents</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/learn-wgpu/showcase/compute/#possible-improvements" class="sidebar-link">Possible Improvements</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/showcase/compute/#results" class="sidebar-link">Results</a></li></ul></li><li><a href="/learn-wgpu/showcase/alignment/" class="sidebar-link">Memory Layout in GLSL</a></li><li><a href="/learn-wgpu/showcase/imgui-demo/" class="sidebar-link">Basic Imgui Demo</a></li></ul></section></li><li><a href="/learn-wgpu/news/" class="sidebar-link">News</a></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><h1 id="compute-example-tangents-and-bitangents"><a href="#compute-example-tangents-and-bitangents" class="header-anchor">#</a> Compute Example: Tangents and Bitangents</h1> <p>This proved more difficult than I anticipated. The first problem I encountered was some vertex data corruption due to the shader reading my vertex data incorrectly. I was using my <code>ModelVertex</code> struct I used in the <a href="/learn-wgpu/intermediate/tutorial11-normals/">normal mapping tutorial</a>.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><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>
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>
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>
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>
tangent<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>
bitangent<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>
</code></pre></div><p>This structure works perfectly fine when used as a vertex buffer. Using it as a storage buffer proved less convenient. My previous code used a GLSL struct similar to my <code>ModelVertex</code>.</p> <div class="language-glsl extra-class"><pre class="language-glsl"><code><span class="token keyword">struct</span> <span class="token class-name">ModelVertex</span> <span class="token punctuation">{</span>
<span class="token keyword">vec3</span> position<span class="token punctuation">;</span>
<span class="token keyword">vec2</span> tex_coords<span class="token punctuation">;</span>
<span class="token keyword">vec3</span> normal<span class="token punctuation">;</span>
<span class="token keyword">vec3</span> tangent<span class="token punctuation">;</span>
<span class="token keyword">vec3</span> bitangent<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><p>At first glance, this seems just fine, but OpenGL experts would likely see a problem with the structure. Our fields aren't aligned properly to support the <code>std430</code> alignment that storage buffers require.. I won't get into detail but you can check out the <a href="/showcase/alignment">alignment showcase</a> if you want to know more. To summarize, the <code>vec2</code> for the <code>tex_coords</code> was messing up the byte alignment, corrupting the vertex data resulting in the following:</p> <p><img src="/learn-wgpu/assets/img/corruption.675b1eca.png" alt="./corruption.png"></p> <p>I could have fixed this by adding a padding field after <code>tex_coords</code> on the Rust side, but that would require modifying the <code>VertexBufferDescriptor</code>. I ended up solving this problem by using the components of the vectors directly and resulted with a struct like this:</p> <div class="language-glsl extra-class"><pre class="language-glsl"><code><span class="token keyword">struct</span> <span class="token class-name">ModelVertex</span> <span class="token punctuation">{</span>
<span class="token keyword">float</span> x<span class="token punctuation">;</span> <span class="token keyword">float</span> y<span class="token punctuation">;</span> <span class="token keyword">float</span> z<span class="token punctuation">;</span>
<span class="token keyword">float</span> uv<span class="token punctuation">;</span> <span class="token keyword">float</span> uw<span class="token punctuation">;</span>
<span class="token keyword">float</span> nx<span class="token punctuation">;</span> <span class="token keyword">float</span> ny<span class="token punctuation">;</span> <span class="token keyword">float</span> nz<span class="token punctuation">;</span>
<span class="token keyword">float</span> tx<span class="token punctuation">;</span> <span class="token keyword">float</span> ty<span class="token punctuation">;</span> <span class="token keyword">float</span> tz<span class="token punctuation">;</span>
<span class="token keyword">float</span> bx<span class="token punctuation">;</span> <span class="token keyword">float</span> by<span class="token punctuation">;</span> <span class="token keyword">float</span> bz<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><p>Since <code>std430</code> will use the alignment of the largest element of the struct, using all floats means the struct will be aligned to 4 bytes. This is alignment matches what <code>ModelVertex</code> uses in Rust. This was kind of a pain to work with, but it fixed the corruption issue.</p> <p>The second problem required me to rethink how I was computing the tangent and bitangent. The previous algorithm I was using only computed the tangent and bitangent for each triangle and set all the vertices in that triangle to use the same tangent and bitangent. While this is fine in a single threaded context, the code breaks down when trying to compute the triangles in parallel. The reason is that multiple triangles can share the same vertices. This means that when we go to save the resulting tangents, we inevitably end up trying to write to the same vertex from multiple different threads which is a big no no. You can see the issue with this method below:</p> <p><img src="/learn-wgpu/assets/img/black_triangles.df338b97.png" alt="./black_triangles.png"></p> <p>Those black triangles were the result of multiple GPU threads trying to modify the same vertices. Looking at the data in Render Doc I could see that the tangents and bitangents were garbage numbers such as <code>NaN</code>.</p> <p><img src="/learn-wgpu/assets/img/render_doc_output.e0c8b298.png" alt="./render_doc_output.png"></p> <p>While on the CPU we could introduce a synchronization primitive such as a <code>Mutex</code> to fix this issue, AFAIK there isn't really such a thing on the GPU. Instead I decided to swap my code to work with each vertex individually. There are some hurdles with that, but those will be easier to explain in code. Let's start with the <code>main</code> function.</p> <div class="language-glsl extra-class"><pre class="language-glsl"><code><span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">uint</span> vertexIndex <span class="token operator">=</span> gl_GlobalInvocationID<span class="token punctuation">.</span>x<span class="token punctuation">;</span>
ModelVertex result <span class="token operator">=</span> <span class="token function">calcTangentBitangent</span><span class="token punctuation">(</span>vertexIndex<span class="token punctuation">)</span><span class="token punctuation">;</span>
dstVertices<span class="token punctuation">[</span>vertexIndex<span class="token punctuation">]</span> <span class="token operator">=</span> result<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>We use the <code>gl_GlobalInvocationID.x</code> to get the index of the vertex we want to compute the tangents for. I opted to put the actual calculation into it's own method. Let's take a look at that.</p> <div class="language-glsl extra-class"><pre class="language-glsl"><code>ModelVertex <span class="token function">calcTangentBitangent</span><span class="token punctuation">(</span><span class="token keyword">uint</span> vertexIndex<span class="token punctuation">)</span> <span class="token punctuation">{</span>
ModelVertex v <span class="token operator">=</span> srcVertices<span class="token punctuation">[</span>vertexIndex<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">vec3</span> tangent <span class="token operator">=</span> <span class="token keyword">vec3</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 keyword">vec3</span> bitangent <span class="token operator">=</span> <span class="token keyword">vec3</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 keyword">uint</span> trianglesIncluded <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token comment">// Find the triangles that use v</span>
<span class="token comment">// * Loop over every triangle (i + 3)</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">uint</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> numIndices<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>
<span class="token keyword">uint</span> index0 <span class="token operator">=</span> indices<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">uint</span> index1 <span class="token operator">=</span> indices<span class="token punctuation">[</span>i<span class="token operator">+</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">uint</span> index2 <span class="token operator">=</span> indices<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>
<span class="token comment">// Only perform the calculation if one of the indices</span>
<span class="token comment">// matches our vertexIndex</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>index0 <span class="token operator">==</span> vertexIndex <span class="token operator">||</span> index1 <span class="token operator">==</span> vertexIndex <span class="token operator">||</span> index2 <span class="token operator">==</span> vertexIndex<span class="token punctuation">)</span> <span class="token punctuation">{</span>
ModelVertex v0 <span class="token operator">=</span> srcVertices<span class="token punctuation">[</span>index0<span class="token punctuation">]</span><span class="token punctuation">;</span>
ModelVertex v1 <span class="token operator">=</span> srcVertices<span class="token punctuation">[</span>index1<span class="token punctuation">]</span><span class="token punctuation">;</span>
ModelVertex v2 <span class="token operator">=</span> srcVertices<span class="token punctuation">[</span>index2<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">vec3</span> pos0 <span class="token operator">=</span> <span class="token function">getPos</span><span class="token punctuation">(</span>v0<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">vec3</span> pos1 <span class="token operator">=</span> <span class="token function">getPos</span><span class="token punctuation">(</span>v1<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">vec3</span> pos2 <span class="token operator">=</span> <span class="token function">getPos</span><span class="token punctuation">(</span>v2<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">vec2</span> uv0 <span class="token operator">=</span> <span class="token function">getUV</span><span class="token punctuation">(</span>v0<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">vec2</span> uv1 <span class="token operator">=</span> <span class="token function">getUV</span><span class="token punctuation">(</span>v1<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">vec2</span> uv2 <span class="token operator">=</span> <span class="token function">getUV</span><span class="token punctuation">(</span>v2<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">vec3</span> delta_pos1 <span class="token operator">=</span> pos1 <span class="token operator">-</span> pos0<span class="token punctuation">;</span>
<span class="token keyword">vec3</span> delta_pos2 <span class="token operator">=</span> pos2 <span class="token operator">-</span> pos0<span class="token punctuation">;</span>
<span class="token keyword">vec2</span> delta_uv1 <span class="token operator">=</span> uv1 <span class="token operator">-</span> uv0<span class="token punctuation">;</span>
<span class="token keyword">vec2</span> delta_uv2 <span class="token operator">=</span> uv2 <span class="token operator">-</span> uv0<span class="token punctuation">;</span>
<span class="token keyword">float</span> r <span class="token operator">=</span> <span class="token number">1.0</span> <span class="token operator">/</span> <span class="token punctuation">(</span>delta_uv1<span class="token punctuation">.</span>x <span class="token operator">*</span> delta_uv2<span class="token punctuation">.</span>y <span class="token operator">-</span> delta_uv1<span class="token punctuation">.</span>y <span class="token operator">*</span> delta_uv2<span class="token punctuation">.</span>x<span class="token punctuation">)</span><span class="token punctuation">;</span>
tangent <span class="token operator">+=</span> <span class="token punctuation">(</span>delta_pos1 <span class="token operator">*</span> delta_uv2<span class="token punctuation">.</span>y <span class="token operator">-</span> delta_pos2 <span class="token operator">*</span> delta_uv1<span class="token punctuation">.</span>y<span class="token punctuation">)</span> <span class="token operator">*</span> r<span class="token punctuation">;</span>
bitangent <span class="token operator">+=</span> <span class="token punctuation">(</span>delta_pos2 <span class="token operator">*</span> delta_uv1<span class="token punctuation">.</span>x <span class="token operator">-</span> delta_pos1 <span class="token operator">*</span> delta_uv2<span class="token punctuation">.</span>x<span class="token punctuation">)</span> <span class="token operator">*</span> r<span class="token punctuation">;</span>
trianglesIncluded <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>
<span class="token comment">// Average the tangent and bitangents</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>trianglesIncluded <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
tangent <span class="token operator">/=</span> trianglesIncluded<span class="token punctuation">;</span>
bitangent <span class="token operator">/=</span> trianglesIncluded<span class="token punctuation">;</span>
tangent <span class="token operator">=</span> <span class="token function">normalize</span><span class="token punctuation">(</span>tangent<span class="token punctuation">)</span><span class="token punctuation">;</span>
bitangent <span class="token operator">=</span> <span class="token function">normalize</span><span class="token punctuation">(</span>bitangent<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// Save the results</span>
v<span class="token punctuation">.</span>tx <span class="token operator">=</span> tangent<span class="token punctuation">.</span>x<span class="token punctuation">;</span>
v<span class="token punctuation">.</span>ty <span class="token operator">=</span> tangent<span class="token punctuation">.</span>y<span class="token punctuation">;</span>
v<span class="token punctuation">.</span>tz <span class="token operator">=</span> tangent<span class="token punctuation">.</span>z<span class="token punctuation">;</span>
v<span class="token punctuation">.</span>bx <span class="token operator">=</span> bitangent<span class="token punctuation">.</span>x<span class="token punctuation">;</span>
v<span class="token punctuation">.</span>by <span class="token operator">=</span> bitangent<span class="token punctuation">.</span>y<span class="token punctuation">;</span>
v<span class="token punctuation">.</span>bz <span class="token operator">=</span> bitangent<span class="token punctuation">.</span>z<span class="token punctuation">;</span>
<span class="token keyword">return</span> v<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><h2 id="possible-improvements"><a href="#possible-improvements" class="header-anchor">#</a> Possible Improvements</h2> <p>Looping over every triangle for every vertex is likely raising some red flags for some of you. In a single threaded context, this algorithm would end up being O(N*M). As we are utilizing the high number of threads availble to our GPU, this is less of an issue, but it still means our GPU is burning more cycles than it needs to.</p> <p>One way I came up with to possibly improve performance is to store the index of each triangle in a hash map like structure with the vertex index as keys. Here's some pseudo code:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">for</span> t <span class="token keyword">in</span> <span class="token number">0</span><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 operator">/</span> <span class="token number">3</span> <span class="token punctuation">{</span>
triangle_map<span class="token punctuation">[</span>indices<span class="token punctuation">[</span>t <span class="token operator">*</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 function">push</span><span class="token punctuation">(</span>t<span class="token punctuation">)</span><span class="token punctuation">;</span>
triangle_map<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">(</span>indices<span class="token punctuation">[</span>t <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> t<span class="token punctuation">)</span><span class="token punctuation">;</span>
triangle_map<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">(</span>indices<span class="token punctuation">[</span>t <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> t<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>We'd then need to flatten this structure to pass it to the GPU. We'd also need a second array to index the first.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">for</span> <span class="token punctuation">(</span>i<span class="token punctuation">,</span> <span class="token punctuation">(</span>_v<span class="token punctuation">,</span> t_list<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">in</span> triangle_map<span class="token punctuation">.</span><span class="token function">iter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">enumerate</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
triangle_map_indices<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token class-name">TriangleMapIndex</span> <span class="token punctuation">{</span>
start<span class="token punctuation">:</span> i<span class="token punctuation">,</span>
len<span class="token punctuation">:</span> t_list<span class="token punctuation">.</span><span class="token function">len</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>
flat_triangle_map<span class="token punctuation">.</span><span class="token function">extend</span><span class="token punctuation">(</span>t_list<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>I ultimately decided against this method as it was more complicated, and I haven't had time to benchmark it to see if it's faster that the simple method.</p> <h2 id="results"><a href="#results" class="header-anchor">#</a> Results</h2> <p>The tangents and bitangents are now getting calculated correctly and on the GPU!</p> <p><img src="/learn-wgpu/assets/img/results.7918efc1.png" alt="./results.png"></p> <div class="auto-github-link"><a href="https://github.com/sotrh/learn-wgpu/tree/master/code/showcase/compute/" target="_blank" rel="noopener noreferrer">Check out the code!</a> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" 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></div></div> <footer class="page-edit"><!----> <div class="last-updated"><span class="prefix">Last Updated: </span> <span class="time">11/21/2020, 1:16:07 PM</span></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
<a href="/learn-wgpu/showcase/pong/" class="prev">
Pong
</a></span> <span class="next"><a href="/learn-wgpu/showcase/alignment/">
Memory Layout in GLSL
</a>
</span></p></div> </main></div></div><div class="global-ui"><!----></div></div>
<script src="/learn-wgpu/assets/js/app.10252059.js" defer></script><script src="/learn-wgpu/assets/js/2.6a9f728b.js" defer></script><script src="/learn-wgpu/assets/js/7.65364b9b.js" defer></script><script src="/learn-wgpu/assets/js/22.2132e362.js" defer></script>
</body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Foreward | Learn Wgpu</title>
<meta name="description" content="">
<meta name="generator" content="VuePress 1.4.0">
<meta property="article:modified_time" content="2020-03-30T01:51:50.000Z"><meta property="og:site_name" content="Learn Wgpu"><meta property="og:title" content="Foreward"><meta property="og:type" content="website"><meta property="og:url" content="/showcase/"><meta name="twitter:title" content="Foreward"><meta name="twitter:url" content="/showcase/"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:label1" content="Written by"><meta name="twitter:data2" content="Benjamin R Hansen"><meta name="twitter:creator" content="https://twitter.com/sotrh760">
<link rel="preload" href="/learn-wgpu/assets/css/0.styles.7acc6ef6.css" as="style"><link rel="preload" href="/learn-wgpu/assets/js/app.10252059.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/2.6a9f728b.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/27.8b0a41bf.js" as="script"><link rel="prefetch" href="/learn-wgpu/assets/js/10.de8cadfb.js"><link rel="prefetch" href="/learn-wgpu/assets/js/11.53581734.js"><link rel="prefetch" href="/learn-wgpu/assets/js/12.8c46a0c8.js"><link rel="prefetch" href="/learn-wgpu/assets/js/13.4723ba5d.js"><link rel="prefetch" href="/learn-wgpu/assets/js/14.90ed5917.js"><link rel="prefetch" href="/learn-wgpu/assets/js/15.3056a06c.js"><link rel="prefetch" href="/learn-wgpu/assets/js/16.0af06f1e.js"><link rel="prefetch" href="/learn-wgpu/assets/js/17.1d99e854.js"><link rel="prefetch" href="/learn-wgpu/assets/js/18.9923f29d.js"><link rel="prefetch" href="/learn-wgpu/assets/js/19.dab68ffd.js"><link rel="prefetch" href="/learn-wgpu/assets/js/20.70e640cc.js"><link rel="prefetch" href="/learn-wgpu/assets/js/21.1dba0934.js"><link rel="prefetch" href="/learn-wgpu/assets/js/22.2132e362.js"><link rel="prefetch" href="/learn-wgpu/assets/js/23.1a88f225.js"><link rel="prefetch" href="/learn-wgpu/assets/js/24.585372be.js"><link rel="prefetch" href="/learn-wgpu/assets/js/25.022f80fd.js"><link rel="prefetch" href="/learn-wgpu/assets/js/26.8484ba66.js"><link rel="prefetch" href="/learn-wgpu/assets/js/28.b9bf1b57.js"><link rel="prefetch" href="/learn-wgpu/assets/js/29.5c3f77ba.js"><link rel="prefetch" href="/learn-wgpu/assets/js/3.df177b88.js"><link rel="prefetch" href="/learn-wgpu/assets/js/30.dc887be9.js"><link rel="prefetch" href="/learn-wgpu/assets/js/4.89cbdecc.js"><link rel="prefetch" href="/learn-wgpu/assets/js/5.c2eff02b.js"><link rel="prefetch" href="/learn-wgpu/assets/js/6.086069e3.js"><link rel="prefetch" href="/learn-wgpu/assets/js/7.65364b9b.js"><link rel="prefetch" href="/learn-wgpu/assets/js/8.1fd4cc1c.js"><link rel="prefetch" href="/learn-wgpu/assets/js/9.ecb6e79c.js">
<link rel="stylesheet" href="/learn-wgpu/assets/css/0.styles.7acc6ef6.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/" class="sidebar-link">Introduction</a></li><li><section class="sidebar-group depth-0"><p class="sidebar-heading"><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-swapchain/" class="sidebar-link">The Swapchain</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/" class="sidebar-link">Model Loading</a></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-threading/" class="sidebar-link">Multi-threading with Wgpu and Rayon</a></li></ul></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading open"><span>Showcase</span> <span class="arrow down"></span></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/learn-wgpu/showcase/" class="active sidebar-link">Foreward</a></li><li><a href="/learn-wgpu/showcase/windowless/" class="sidebar-link">Wgpu without a window</a></li><li><a href="/learn-wgpu/showcase/gifs/" class="sidebar-link">Creating gifs</a></li><li><a href="/learn-wgpu/showcase/pong/" class="sidebar-link">Pong</a></li><li><a href="/learn-wgpu/showcase/compute/" class="sidebar-link">Compute Example: Tangents and Bitangents</a></li><li><a href="/learn-wgpu/showcase/alignment/" class="sidebar-link">Memory Layout in GLSL</a></li><li><a href="/learn-wgpu/showcase/imgui-demo/" class="sidebar-link">Basic Imgui Demo</a></li></ul></section></li><li><a href="/learn-wgpu/news/" class="sidebar-link">News</a></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><h1 id="foreward"><a href="#foreward" class="header-anchor">#</a> Foreward</h1> <p>The articles in this section are not meant to be tutorials. They are showcases of the various things you can do with <code>wgpu</code>. I won't go over specifics of creating <code>wgpu</code> resources, as those will be covered elsewhere. The code for these examples is still available however, and will be accessible on Github.</p></div> <footer class="page-edit"><!----> <div class="last-updated"><span class="prefix">Last Updated: </span> <span class="time">3/29/2020, 7:51:50 PM</span></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
<a href="/learn-wgpu/intermediate/tutorial13-threading/" class="prev">
Multi-threading with Wgpu and Rayon
</a></span> <span class="next"><a href="/learn-wgpu/showcase/windowless/">
Wgpu without a window
</a>
</span></p></div> </main></div></div><div class="global-ui"><!----></div></div>
<script src="/learn-wgpu/assets/js/app.10252059.js" defer></script><script src="/learn-wgpu/assets/js/2.6a9f728b.js" defer></script><script src="/learn-wgpu/assets/js/27.8b0a41bf.js" defer></script>
</body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Coming Soon! | Learn Wgpu</title>
<meta name="description" content="">
<meta name="generator" content="VuePress 1.4.0">
<meta property="article:modified_time" content="2019-11-05T08:02:41.000Z"><meta property="og:site_name" content="Learn Wgpu"><meta property="og:title" content="Coming Soon!"><meta property="og:type" content="website"><meta property="og:url" content="/todo.html"><meta name="twitter:title" content="Coming Soon!"><meta name="twitter:url" content="/todo.html"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:label1" content="Written by"><meta name="twitter:data2" content="Benjamin R Hansen"><meta name="twitter:creator" content="https://twitter.com/sotrh760">
<link rel="preload" href="/learn-wgpu/assets/css/0.styles.7acc6ef6.css" as="style"><link rel="preload" href="/learn-wgpu/assets/js/app.10252059.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/2.6a9f728b.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/29.5c3f77ba.js" as="script"><link rel="prefetch" href="/learn-wgpu/assets/js/10.de8cadfb.js"><link rel="prefetch" href="/learn-wgpu/assets/js/11.53581734.js"><link rel="prefetch" href="/learn-wgpu/assets/js/12.8c46a0c8.js"><link rel="prefetch" href="/learn-wgpu/assets/js/13.4723ba5d.js"><link rel="prefetch" href="/learn-wgpu/assets/js/14.90ed5917.js"><link rel="prefetch" href="/learn-wgpu/assets/js/15.3056a06c.js"><link rel="prefetch" href="/learn-wgpu/assets/js/16.0af06f1e.js"><link rel="prefetch" href="/learn-wgpu/assets/js/17.1d99e854.js"><link rel="prefetch" href="/learn-wgpu/assets/js/18.9923f29d.js"><link rel="prefetch" href="/learn-wgpu/assets/js/19.dab68ffd.js"><link rel="prefetch" href="/learn-wgpu/assets/js/20.70e640cc.js"><link rel="prefetch" href="/learn-wgpu/assets/js/21.1dba0934.js"><link rel="prefetch" href="/learn-wgpu/assets/js/22.2132e362.js"><link rel="prefetch" href="/learn-wgpu/assets/js/23.1a88f225.js"><link rel="prefetch" href="/learn-wgpu/assets/js/24.585372be.js"><link rel="prefetch" href="/learn-wgpu/assets/js/25.022f80fd.js"><link rel="prefetch" href="/learn-wgpu/assets/js/26.8484ba66.js"><link rel="prefetch" href="/learn-wgpu/assets/js/27.8b0a41bf.js"><link rel="prefetch" href="/learn-wgpu/assets/js/28.b9bf1b57.js"><link rel="prefetch" href="/learn-wgpu/assets/js/3.df177b88.js"><link rel="prefetch" href="/learn-wgpu/assets/js/30.dc887be9.js"><link rel="prefetch" href="/learn-wgpu/assets/js/4.89cbdecc.js"><link rel="prefetch" href="/learn-wgpu/assets/js/5.c2eff02b.js"><link rel="prefetch" href="/learn-wgpu/assets/js/6.086069e3.js"><link rel="prefetch" href="/learn-wgpu/assets/js/7.65364b9b.js"><link rel="prefetch" href="/learn-wgpu/assets/js/8.1fd4cc1c.js"><link rel="prefetch" href="/learn-wgpu/assets/js/9.ecb6e79c.js">
<link rel="stylesheet" href="/learn-wgpu/assets/css/0.styles.7acc6ef6.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/" class="sidebar-link">Introduction</a></li><li><section class="sidebar-group depth-0"><p class="sidebar-heading"><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-swapchain/" class="sidebar-link">The Swapchain</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/" class="sidebar-link">Model Loading</a></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-threading/" class="sidebar-link">Multi-threading with Wgpu and Rayon</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><a href="/learn-wgpu/news/" class="sidebar-link">News</a></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><h1 id="coming-soon"><a href="#coming-soon" class="header-anchor">#</a> Coming Soon!</h1> <p>This section has not yet been completed.</p></div> <footer class="page-edit"><!----> <div class="last-updated"><span class="prefix">Last Updated: </span> <span class="time">11/5/2019, 1:02:41 AM</span></div></footer> <!----> </main></div></div><div class="global-ui"><!----></div></div>
<script src="/learn-wgpu/assets/js/app.10252059.js" defer></script><script src="/learn-wgpu/assets/js/2.6a9f728b.js" defer></script><script src="/learn-wgpu/assets/js/29.5c3f77ba.js" defer></script>
</body>
</html>
Loading…
Cancel
Save