<divid="app"data-server-rendered="true"><divclass="theme-container"><divclass="theme-default-content"><h1>404</h1><blockquote>Looks like we've got some broken links.</blockquote><ahref="/learn-wgpu/"class="router-link-active">Take me home.</a></div></div><divclass="global-ui"><!----></div></div>
(window.webpackJsonp=window.webpackJsonp||[]).push([[10],{176:function(e,r,n){},260:function(e,r,n){vart={"./pong/pong.js":[263,1,2,35],"./pong/pong_bg.js":[156,1,2]};functiona(e){if(!n.o(t,e))returnPromise.resolve().then((function(){varr=newError("Cannot find module '"+e+"'");throwr.code="MODULE_NOT_FOUND",r}));varr=t[e],a=r[0];returnPromise.all(r.slice(1).map(n.e)).then((function(){returnn(a)}))}a.keys=function(){returnObject.keys(t)},a.id=260,e.exports=a},261:function(e,r,n){"use strict";vart=n(176);n.n(t).a},313:function(e,r,n){"use strict";n.r(r);n(109),n(17),n(23),n(49),n(78);vart=n(40);vara={props:{example:"",autoLoad:!1},data:function(){return{error:"",loading:!1,exampleStarted:!1}},computed:{exampleName:function(){returnthis.example.replace(/\w\S*/g,(function(e){returne.charAt(0).toUpperCase()+e.substr(1).toLowerCase()}))}},methods:{loadExample:function(){vare=this;returnObject(t.a)(regeneratorRuntime.mark((functionr(){returnregeneratorRuntime.wrap((function(r){for(;;)switch(r.prev=r.next){case0:returne.loading=!0,r.prev=1,r.next=4,n(260)("./".concat(e.example,"/").concat(e.example,".js"));case4:(0,r.sent)().then((function(){console.log("WASM Loaded")})),r.next=11;break;case8:r.prev=8,r.t0=r.catch(1),"Error: Using exceptions for control flow, don't mind me. This isn't actually an error!"!="".concat(r.t0)?(e.error='An error occurred loading "'.concat(e.example,'": ').concat(r.t0),console.error(r.t0),e.exampleStarted=!1):e.exampleStarted=!0;case11:e.loading=!1;case12:case"end":returnr.stop()}}),r,null,[[1,8]])})))()}},mounted:function(){vare=this;returnObject(t.a)(regeneratorRuntime.mark((functionr(){returnregeneratorRuntime.wrap((function(r){for(;;)switch(r.prev=r.next){case0:returnr.next=2,e.$nextTick();case2:if(!e.autoLoad){r.next=5;break}returnr.next=5,e.loadExample();case5:case"end":returnr.stop()}}),r)})))()}},o=(n(261),n(10)),c=Object(o.a)(a,(function(){vare=this,r=e.$createElement,n=e._self._c||r;returnn("div",{attrs:{id:"wasm-example"}},[e.error?n("div",{staticClass:"error"},[e._v("\n "+e._s(e.error)+"\n ")]):e._e(),e._v(" "),e.exampleStarted||e.autoLoad?e._e():n("button",{attrs:{disabled:e.loading},on:{click:function(r){returne.loadExample()}}},[e._v("Try "+e._s(e.exampleName)+"!")])])}),[],!1,null,null,null);r.default=c.exports}}]);
(window.webpackJsonp=window.webpackJsonp||[]).push([[10],{395:function(e,t,r){},517:function(e,t,r){"use strict";varn=r(1),a=r(2),o=r(30),u=r(61),c=r(14),i=a("".slice),s=Math.max,l=Math.min;n({target:"String",proto:!0,forced:!"".substr||"b"!=="ab".substr(-1)},{substr:function(e,t){varr,n,a=c(o(this)),d=a.length,p=u(e);returnp===1/0&&(p=0),p<0&&(p=s(d+p,0)),(r=void0===t?d:u(t))<=0||r===1/0||p>=(n=l(p+r,d))?"":i(a,p,n)}})},518:function(e,t,r){varn={"./tutorial13_threading/tutorial13_threading.js":[521,1,2,36],"./tutorial13_threading/tutorial13_threading_bg.js":[363,1,2],"./tutorial2_surface/tutorial2_surface.js":[533,1,3,37],"./tutorial2_surface/tutorial2_surface_bg.js":[364,1,3]};functiona(e){if(!r.o(n,e))returnPromise.resolve().then((function(){vart=newError("Cannot find module '"+e+"'");throwt.code="MODULE_NOT_FOUND",t}));vart=n[e],a=t[0];returnPromise.all(t.slice(1).map(r.e)).then((function(){returnr(a)}))}a.keys=function(){returnObject.keys(n)},a.id=518,e.exports=a},519:function(e,t,r){"use strict";r(395)},538:function(e,t,r){"use strict";r.r(t);varn=r(87);r(135),r(29),r(92),r(517),r(8),r(19),r(27),r(125);vara={name:"WasmExample",props:{example:"",autoLoad:!1},data:function(){return{error:"",loading:!1,exampleStarted:!1}},computed:{exampleName:function(){returnthis.example.replace(/\w\S*/g,(function(e){returne.charAt(0).toUpperCase()+e.substr(1).toLowerCase()}))}},methods:{loadExample:function(){vare=this;returnObject(n.a)(regeneratorRuntime.mark((functiont(){returnregeneratorRuntime.wrap((function(t){for(;;)switch(t.prev=t.next){case0:returne.loading=!0,t.prev=1,t.next=4,r(518)("./".concat(e.example,"/").concat(e.example,".js"));case4:t.next=9;break;case6:t.prev=6,t.t0=t.catch(1),"Error: Using exceptions for control flow, don't mind me. This isn't actually an error!"!="".concat(t.t0)?(e.error='An error occurred loading "'.concat(e.example,'": ').concat(t.t0),console.error(t.t0),e.exampleStarted=!1):e.exampleStarted=!0;case9:e.loading=!1;case10:case"end":returnt.stop()}}),t,null,[[1,6]])})))()}},mounted:function(){vare=this;returnObject(n.a)(regeneratorRuntime.mark((functiont(){returnregeneratorRuntime.wrap((function(t){for(;;)switch(t.prev=t.next){case0:returnt.next=2,e.$nextTick();case2:if(!e.autoLoad){t.next=5;break}returnt.next=5,e.loadExample();case5:case"end":returnt.stop()}}),t)})))()}},o=(r(519),r(23)),u=Object(o.a)(a,(function(){vare=this,t=e.$createElement,r=e._self._c||t;returnr("div",{attrs:{id:"wasm-example"}},[e.error?r("div",{staticClass:"error"},[e._v("\n "+e._s(e.error)+"\n ")]):e._e(),e._v(" "),e.exampleStarted||e.autoLoad?e._e():r("button",{attrs:{disabled:e.loading},on:{click:function(t){returne.loadExample()}}},[e._v("Try "+e._s(e.exampleName)+"!")])])}),[],!1,null,null,null);t.default=u.exports}}]);
(window.webpackJsonp=window.webpackJsonp||[]).push([[14],{394:function(t,e,n){},514:function(t,e,n){"use strict";n(394)},536:function(t,e,n){"use strict";n.r(e);vari={name:"AutoGithubLink",computed:{link:function(){return"https://github.com/sotrh/learn-wgpu/tree/master/code"+this.$page.path}}},r=(n(514),n(23)),u=Object(r.a)(i,(function(){vart=this.$createElement,e=this._self._c||t;returne("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=u.exports}}]);
(window.webpackJsonp=window.webpackJsonp||[]).push([[25],{311:function(t,e,n){"use strict";n.r(e);varr={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(){vart=this.$createElement,e=this._self._c||t;returne("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}}]);
(window.webpackJsonp=window.webpackJsonp||[]).push([[26],{310:function(t,e,s){"use strict";s.r(e);varo=["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(){returno[Math.floor(Math.random()*o.length)]}}},i=s(10),h=Object(i.a)(n,(function(){vart=this.$createElement,e=this._self._c||t;returne("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}}]);
(window.webpackJsonp=window.webpackJsonp||[]).push([[27],{535:function(t,e,s){"use strict";s.r(e);varo=["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(){returno[Math.floor(Math.random()*o.length)]}}},i=s(23),h=Object(i.a)(n,(function(){vart=this.$createElement,e=this._self._c||t;returne("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}}]);
(window.webpackJsonp=window.webpackJsonp||[]).push([[27],{314:function(t,e,a){"use strict";a.r(e);varn=a(10),r=Object(n.a)({},(function(){vart=this,e=t.$createElement,a=t._self._c||e;returna("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 convenient 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 with "),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 to learn wgpu myself, so I might miss some important details, or explain things badly. 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 ("),a("a",{attrs:{href:"https://github.com/sotrh/learn-wgpu",target:"_blank",rel:"noopener noreferrer"}},[t._v("GitHub repo"),a("OutboundLink")],1),t._v(") 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("!")])]),t._v(" "),a("h2",{attrs:{id:"special-thanks-to-these-patrons"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#special-thanks-to-these-patrons"}},[t._v("#")]),t._v(" Special thanks to these patrons!")]),t._v(" "),a("p",[a("em",[t._v("In no particular order")])]),t._v(" "),a("ul",[a("li",[t._v("Zeh Fernando")]),t._v(" "),a("li",[t._v("The toddling chaos")]),t._v(" "),a("li",[t._v("Jan Šipr")]),t._v(" "),a("li",[t._v("Bernard Llanos")]),t._v(" "),a("li",[t._v("Aron Granberg")]),t._v(" "),a("li",[t._v("Ian Gowen")]),t._v(" "),a("li",[t._v("Paul E Hansen")]),t._v(" "),a("li",[t._v("Lennart")]),t._v(" "),a("li",[t._v("Gunstein Vatnar")]),t._v(" "),a("li",[t._v("David Laban")])])])}),[],!1,null,null,null);e.default=r.exports}}]);
(window.webpackJsonp=window.webpackJsonp||[]).push([[28],{539:function(t,e,a){"use strict";a.r(e);varn=a(23),r=Object(n.a)({},(function(){vart=this,e=t.$createElement,a=t._self._c||e;returna("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 convenient 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 with "),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 to learn wgpu myself, so I might miss some important details, or explain things badly. 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 ("),a("a",{attrs:{href:"https://github.com/sotrh/learn-wgpu",target:"_blank",rel:"noopener noreferrer"}},[t._v("GitHub repo"),a("OutboundLink")],1),t._v(") 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("!")])]),t._v(" "),a("h2",{attrs:{id:"special-thanks-to-these-patrons"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#special-thanks-to-these-patrons"}},[t._v("#")]),t._v(" Special thanks to these patrons!")]),t._v(" "),a("p",[a("em",[t._v("In no particular order")])]),t._v(" "),a("ul",[a("li",[t._v("Zeh Fernando")]),t._v(" "),a("li",[t._v("The toddling chaos")]),t._v(" "),a("li",[t._v("Jan Šipr")]),t._v(" "),a("li",[t._v("Bernard Llanos")]),t._v(" "),a("li",[t._v("Aron Granberg")]),t._v(" "),a("li",[t._v("Ian Gowen")]),t._v(" "),a("li",[t._v("Paul E Hansen")]),t._v(" "),a("li",[t._v("Lennart")]),t._v(" "),a("li",[t._v("Gunstein Vatnar")]),t._v(" "),a("li",[t._v("David Laban")])])])}),[],!1,null,null,null);e.default=r.exports}}]);
(window.webpackJsonp=window.webpackJsonp||[]).push([[32],{331:function(e,t,o){"use strict";o.r(t);vars=o(10),r=Object(s.a)({},(function(){vare=this,t=e.$createElement,o=e._self._c||t;returno("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[o("h1",{attrs:{id:"foreword"}},[o("a",{staticClass:"header-anchor",attrs:{href:"#foreword"}},[e._v("#")]),e._v(" Foreword")]),e._v(" "),o("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 "),o("code",[e._v("wgpu")]),e._v(". I won't go over specifics of creating "),o("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}}]);
(window.webpackJsonp=window.webpackJsonp||[]).push([[33],{556:function(e,t,o){"use strict";o.r(t);vars=o(23),r=Object(s.a)({},(function(){vare=this,t=e.$createElement,o=e._self._c||t;returno("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[o("h1",{attrs:{id:"foreword"}},[o("a",{staticClass:"header-anchor",attrs:{href:"#foreword"}},[e._v("#")]),e._v(" Foreword")]),e._v(" "),o("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 "),o("code",[e._v("wgpu")]),e._v(". I won't go over specifics of creating "),o("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}}]);
(window.webpackJsonp=window.webpackJsonp||[]).push([[34],{338:function(t,s,n){"use strict";n.r(s);vare=n(10),o=Object(e.a)({},(function(){vart=this.$createElement,s=this._self._c||t;returns("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}}]);
(window.webpackJsonp=window.webpackJsonp||[]).push([[35],{563:function(t,s,n){"use strict";n.r(s);vare=n(23),o=Object(e.a)({},(function(){vart=this.$createElement,s=this._self._c||t;returns("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}}]);
<divid="app"data-server-rendered="true"><divclass="theme-container"><headerclass="navbar"><divclass="inner"><divclass="sidebar-button"><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"role="img"viewBox="0 0 448 512"class="icon"><pathfill="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><ahref="/learn-wgpu/"class="home-link router-link-active"><!----><spanclass="site-name">Learn Wgpu</span></a><divclass="links"><!----><divclass="search-box"><inputaria-label="Search"autocomplete="off"spellcheck="false"value=""><!----></div></div></div></header><divclass="sidebar-mask"></div><divclass="docs-layout"><asideclass="sidebar"><!----><ulclass="sidebar-links"><li><ahref="/learn-wgpu/"class="sidebar-link">Introduction</a></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading open"><span>Beginner</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/beginner/tutorial1-window/"class="sidebar-link">Dependencies and the window</a></li><li><ahref="/learn-wgpu/beginner/tutorial2-surface/"class="sidebar-link">The Surface</a></li><li><ahref="/learn-wgpu/beginner/tutorial3-pipeline/"class="sidebar-link">The Pipeline</a></li><li><ahref="/learn-wgpu/beginner/tutorial4-buffer/"class="sidebar-link">Buffers and Indices</a></li><li><ahref="/learn-wgpu/beginner/tutorial5-textures/"class="sidebar-link">Textures and bind groups</a></li><li><ahref="/learn-wgpu/beginner/tutorial6-uniforms/"class="sidebar-link">Uniform buffers and a 3d camera</a></li><li><ahref="/learn-wgpu/beginner/tutorial7-instancing/"class="sidebar-link">Instancing</a></li><li><ahref="/learn-wgpu/beginner/tutorial8-depth/"class="sidebar-link">The Depth Buffer</a></li><li><ahref="/learn-wgpu/beginner/tutorial9-models/"class="active sidebar-link">Model Loading</a><ulclass="sidebar-sub-headers"><liclass="sidebar-sub-header"><ahref="/learn-wgpu/beginner/tutorial9-models/#accessing-files-in-the-res-folder"class="sidebar-link">Accessing files in the res folder</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/beginner/tutorial9-models/#loading-models-with-tobj"class="sidebar-link">Loading models with TOBJ</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/beginner/tutorial9-models/#rendering-a-mesh"class="sidebar-link">Rendering a mesh</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/beginner/tutorial9-models/#using-the-correct-textures"class="sidebar-link">Using the correct textures</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/beginner/tutorial9-models/#rendering-the-entire-model"class="sidebar-link">Rendering the entire model</a></li></ul></li></ul></section></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading"><span>Intermediate</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/intermediate/tutorial10-lighting/"class="sidebar-link">Working with Lights</a></li><li><ahref="/learn-wgpu/intermediate/tutorial11-normals/"class="sidebar-link">Normal Mapping</a></li><li><ahref="/learn-wgpu/intermediate/tutorial12-camera/"class="sidebar-link">A Better Camera</a></li><li><ahref="/learn-wgpu/intermediate/tutorial13-threading/"class="sidebar-link">Multi-threading with Wgpu and Rayon</a></li></ul></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading"><span>Showcase</span><spanclass="arrow right"></span></p><!----></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading"><span>News</span><spanclass="arrow right"></span></p><!----></section></li></ul></aside><mainclass="page"><divclass="theme-default-content content__default"><h1id="model-loading"><ahref="#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><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token comment">// model.rs</span>
<divid="app"data-server-rendered="true"><divclass="theme-container"><headerclass="navbar"><divclass="inner"><divclass="sidebar-button"><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"role="img"viewBox="0 0 448 512"class="icon"><pathfill="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><ahref="/learn-wgpu/"class="home-link router-link-active"><!----><spanclass="site-name">Learn Wgpu</span></a><divclass="links"><!----><divclass="search-box"><inputaria-label="Search"autocomplete="off"spellcheck="false"value=""><!----></div></div></div></header><divclass="sidebar-mask"></div><divclass="docs-layout"><asideclass="sidebar"><!----><ulclass="sidebar-links"><li><ahref="/learn-wgpu/"aria-current="page"class="sidebar-link">Introduction</a></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading open"><span>Beginner</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/beginner/tutorial1-window/"class="sidebar-link">Dependencies and the window</a></li><li><ahref="/learn-wgpu/beginner/tutorial2-surface/"class="sidebar-link">The Surface</a></li><li><ahref="/learn-wgpu/beginner/tutorial3-pipeline/"class="sidebar-link">The Pipeline</a></li><li><ahref="/learn-wgpu/beginner/tutorial4-buffer/"class="sidebar-link">Buffers and Indices</a></li><li><ahref="/learn-wgpu/beginner/tutorial5-textures/"class="sidebar-link">Textures and bind groups</a></li><li><ahref="/learn-wgpu/beginner/tutorial6-uniforms/"class="sidebar-link">Uniform buffers and a 3d camera</a></li><li><ahref="/learn-wgpu/beginner/tutorial7-instancing/"class="sidebar-link">Instancing</a></li><li><ahref="/learn-wgpu/beginner/tutorial8-depth/"class="sidebar-link">The Depth Buffer</a></li><li><ahref="/learn-wgpu/beginner/tutorial9-models/"aria-current="page"class="active sidebar-link">Model Loading</a><ulclass="sidebar-sub-headers"><liclass="sidebar-sub-header"><ahref="/learn-wgpu/beginner/tutorial9-models/#accessing-files-in-the-res-folder"class="sidebar-link">Accessing files in the res folder</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/beginner/tutorial9-models/#accessing-files-from-wasm" class="sidebar-link">Accessing files from WASM</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/beginner/tutorial9-models/#loading-models-with-tobj" class="sidebar-link">Loading models with TOBJ</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/beginner/tutorial9-models/#rendering-a-mesh"class="sidebar-link">Rendering a mesh</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/beginner/tutorial9-models/#using-the-correct-textures"class="sidebar-link">Using the correct textures</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/beginner/tutorial9-models/#rendering-the-entire-model"class="sidebar-link">Rendering the entire model</a></li></ul></li></ul></section></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading"><span>Intermediate</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/intermediate/tutorial10-lighting/"class="sidebar-link">Working with Lights</a></li><li><ahref="/learn-wgpu/intermediate/tutorial11-normals/"class="sidebar-link">Normal Mapping</a></li><li><ahref="/learn-wgpu/intermediate/tutorial12-camera/"class="sidebar-link">A Better Camera</a></li></ul></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading"><span>Showcase</span><spanclass="arrow right"></span></p><!----></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading"><span>News</span><spanclass="arrow right"></span></p><!----></section></li></ul></aside><mainclass="page"><divclass="theme-default-content content__default"><h1id="model-loading"><ahref="#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><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token comment">// model.rs</span>
</code></pre></div><p>Since the <code>desc</code> method is implemented on the <code>Vertex</code> trait, the trait needs to be imported before the method will be accessible. Put the import towards the top of the file with the others.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">use</span><spanclass="token namespace">model<spanclass="token punctuation">::</span></span><spanclass="token class-name">Vertex</span><spanclass="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 <ahref="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"><pathfill="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><polygonfill="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><h2id="accessing-files-in-the-res-folder"><ahref="#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. Create a file called <code>build.rs</code> and add the following:</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">use</span><spanclass="token namespace">anyhow<spanclass="token punctuation">::</span></span><spanclass="token operator">*</span><spanclass="token punctuation">;</span>
</code></pre></div><p>Since the <code>desc</code> method is implemented on the <code>Vertex</code> trait, the trait needs to be imported before the method will be accessible. Put the import towards the top of the file with the others.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">use</span><spanclass="token namespace">model<spanclass="token punctuation">::</span></span><spanclass="token class-name">Vertex</span><spanclass="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 <ahref="https://github.com/sotrh/learn-wgpu/blob/master/code/beginner/tutorial9-models/res/cube.zip"target="_blank"rel="noopener noreferrer">zip file<span><svg xmlns="http://www.w3.org/2000/svg"aria-hidden="true" focusable="false" x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="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><polygonfill="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><spanclass="sr-only">(opens new window)</span></span></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><h2id="accessing-files-in-the-res-folder"><ahref="#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. Create a file called <code>build.rs</code> and add the following:</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">use</span><spanclass="token namespace">anyhow<spanclass="token punctuation">::</span></span><spanclass="token operator">*</span><spanclass="token punctuation">;</span>
</code></pre></div><h2id="loading-models-with-tobj"><ahref="#loading-models-with-tobj"class="header-anchor">#</a> Loading models with TOBJ</h2><p>We're going to use the <ahref="https://docs.rs/tobj/3.0/tobj/"target="_blank"rel="noopener noreferrer">tobj<svgxmlns="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"><pathfill="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><polygonfill="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. Let's add it to our <code>Cargo.toml</code>.</p><divclass="language-toml extra-class"><preclass="language-toml"><code><spanclass="token punctuation">[</span><spanclass="token table class-name">dependencies</span><spanclass="token punctuation">]</span>
</code></pre></div><h2id="accessing-files-from-wasm"><ahref="#accessing-files-from-wasm"class="header-anchor">#</a> Accessing files from WASM</h2><p>By design, you can't access files on a users filesystem in Web Assembly. Instead we'll serve those files up using a web serve, and then load those files into our code using an http request. In order to simplify this, let's create a file called <code>resources.rs</code> to handle this for us. We'll create two functions that will load text files and binary files respectively.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">use</span><spanclass="token namespace">std<spanclass="token punctuation">::</span>io<spanclass="token punctuation">::</span></span><spanclass="token punctuation">{</span><spanclass="token class-name">BufReader</span><spanclass="token punctuation">,</span><spanclass="token class-name">Cursor</span><spanclass="token punctuation">}</span><spanclass="token punctuation">;</span>
</code></pre></div><divclass="note"><p>We're using <code>OUT_DIR</code> on desktop to get at our <code>res</code> folder.</p></div><p>I'm using <ahref="https://docs.rs/reqwest"target="_blank"rel="noopener noreferrer">reqwest<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="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><polygonfill="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><spanclass="sr-only">(opens new window)</span></span></a> to handle loading the requests when using WASM. Add the following to the Cargo.toml:</p><divclass="language-toml extra-class"><preclass="language-toml"><code><spanclass="token punctuation">[</span><spanclass="token table class-name">target.'cfg(target_arch = "wasm32")'.dependencies</span><spanclass="token punctuation">]</span>
<spanclass="token comment"># Other dependencies</span>
</code></pre></div><p>We'll also need to add the <code>Location</code> feature to <code>web-sys</code>:</p><divclass="language-toml extra-class"><preclass="language-toml"><code><spanclass="token key property">web-sys</span><spanclass="token punctuation">=</span><spanclass="token punctuation">{</span><spanclass="token key property">version</span><spanclass="token punctuation">=</span><spanclass="token string">"0.3"</span><spanclass="token punctuation">,</span><spanclass="token key property">features</span><spanclass="token punctuation">=</span><spanclass="token punctuation">[</span>
</code></pre></div><p>Make sure to add <code>resources</code> as a module in <code>lib.rs</code>:</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">mod</span><spanclass="token module-declaration namespace">resources</span><spanclass="token punctuation">;</span>
</code></pre></div><h2id="loading-models-with-tobj"><ahref="#loading-models-with-tobj"class="header-anchor">#</a> Loading models with TOBJ</h2><p>We're going to use the <ahref="https://docs.rs/tobj/3.0/tobj/"target="_blank"rel="noopener noreferrer">tobj<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="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><polygonfill="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><spanclass="sr-only">(opens new window)</span></span></a> library to load our model. Let's add it to our <code>Cargo.toml</code>.</p><divclass="language-toml extra-class"><preclass="language-toml"><code><spanclass="token punctuation">[</span><spanclass="token table class-name">dependencies</span><spanclass="token punctuation">]</span>
<spanclass="token comment"># other dependencies...</span>
</code></pre></div><p>Before we can load our model though, we need somewhere to put it.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token comment">// model.rs</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 <ahref="../../intermediate/tutorial11-normals">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><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">use</span><spanclass="token namespace">std<spanclass="token punctuation">::</span>path<spanclass="token punctuation">::</span></span><spanclass="token class-name">Path</span><spanclass="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 <ahref="../../intermediate/tutorial11-normals">later</a>. The name is more for debugging purposes.</p><p>Speaking of textures, we'll need to add a function to load a<code>Texture</code> in <code>resources.rs</code>.</p><divclass="language-rust extra-class"><preclass="language-rust"><code>
</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><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">use</span><spanclass="token keyword">crate</span><spanclass="token module-declaration namespace"><spanclass="token punctuation">::</span>texture</span><spanclass="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_rgba8()</code> to handle such an image, which will generate a new image buffer with alpha channel even if the original image does not have one.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">let</span> rgba <spanclass="token operator">=</span> img<spanclass="token punctuation">.</span><spanclass="token function">to_rgba8</span><spanclass="token punctuation">(</span><spanclass="token punctuation">)</span><spanclass="token punctuation">;</span>
</code></pre></div><p>Since <code>rgba</code> is now a new image buffer, and not a reference to the original image's buffer, when it is used in the call to <code>write_texture</code> later, it needs to be passed as a reference instead.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token comment">//...</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><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">impl</span><spanclass="token class-name">Model</span><spanclass="token punctuation">{</span>
</code></pre></div><p>The <code>load_texture</code> method will be useful when we load the textures for our models, as <code>include_bytes!</code> requires that we know the name of the file at compile time which we can't really guarantee with model textures.</p><p><code>Mesh</code> holds a vertex buffer, an index buffer, and the number of indices in the mesh. We're using an <code>usize</code> for the material. This <code>usize</code> will be used to index the <code>materials</code> list when it comes time to draw.</p><p>With all that out of the way, we can get to loading our model.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">pub</span><spanclass="token keyword">async</span><spanclass="token keyword">fn</span><spanclass="token function-definition function">load_model</span><spanclass="token punctuation">(</span>
</code></pre></div><h2id="rendering-a-mesh"><ahref="#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><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">pub</span><spanclass="token keyword">trait</span><spanclass="token class-name">DrawModel</span><spanclass="token operator"><</span><spanclass="token lifetime-annotation symbol">'a</span><spanclass="token operator">></span><spanclass="token punctuation">{</span>
</code></pre></div><h2id="rendering-a-mesh"><ahref="#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><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token comment">// model.rs</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><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token comment">// main.rs</span>
</code></pre></div><p>We could have put this methods in an <code>impl Model</code>, but I felt it made more sense to have the <code>RenderPass</code> do all the rendering, as that's kind of it's job. This does mean we have to import <code>DrawModel</code> when we go to render though.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token comment">// lib.rs</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><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">let</span>res_dir<spanclass="token operator">=</span><spanclass="token namespace">std<spanclass="token punctuation">::</span>path<spanclass="token punctuation">::</span></span><spanclass="token class-name">Path</span><spanclass="token punctuation">::</span><spanclass="token function">new</span><spanclass="token punctuation">(</span><spanclass="token macro property">env!</span><spanclass="token punctuation">(</span><spanclass="token string">"OUT_DIR"</span><spanclass="token punctuation">)</span><spanclass="token punctuation">)</span><spanclass="token punctuation">.</span><spanclass="token function">join</span><spanclass="token punctuation">(</span><spanclass="token string">"res"</span><spanclass="token punctuation">)</span><spanclass="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><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">let</span>obj_model<spanclass="token operator">=</span><spanclass="token namespace">resources<spanclass="token punctuation">::</span></span><spanclass="token function">load_model</span><spanclass="token punctuation">(</span>
</code></pre></div><divclass="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><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">const</span><spanclass="token constant">SPACE_BETWEEN</span><spanclass="token punctuation">:</span><spanclass="token keyword">f32</span><spanclass="token operator">=</span><spanclass="token number">3.0</span><spanclass="token punctuation">;</span>
</code></pre></div><p>Our new model is a bit bigger than our previous one so we're gonna need to adjust the spacing on our instances a bit.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">const</span><spanclass="token constant">SPACE_BETWEEN</span><spanclass="token punctuation">:</span><spanclass="token keyword">f32</span><spanclass="token operator">=</span><spanclass="token number">3.0</span><spanclass="token punctuation">;</span>
</code></pre></div><p>With all that done, you should get something like this.</p><p><imgsrc="/learn-wgpu/assets/img/cubes.988d14be.png"alt="cubes.png"></p><h2id="using-the-correct-textures"><ahref="#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><imgsrc="/learn-wgpu/assets/img/cube-diffuse.03fc55af.jpg"alt="cube-diffuse.jpg"></p><p>but we're still getting our happy tree texture.</p><p>The reason for this is quite simple. Though we've created our textures we haven't created a bind group to give to the <code>RenderPass</code>. We're still using our old <code>diffuse_bind_group</code>. If we want to change that we need to use the bind group from our materials - the <code>bind_group</code> member of the <code>Material</code> struct.</p><p>We're going to add a material parameter to <code>DrawModel</code>.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">pub</span><spanclass="token keyword">trait</span><spanclass="token class-name">DrawModel</span><spanclass="token operator"><</span><spanclass="token lifetime-annotation symbol">'a</span><spanclass="token operator">></span><spanclass="token punctuation">{</span>
</code></pre></div><p>With all that done, you should get something like this.</p><p><imgsrc="/learn-wgpu/assets/img/cubes.988d14be.png"alt="cubes.png"></p><h2id="using-the-correct-textures"><ahref="#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><imgsrc="/learn-wgpu/assets/img/cube-diffuse.03fc55af.jpg"alt="cube-diffuse.jpg"></p><p>but we're still getting our happy tree texture.</p><p>The reason for this is quite simple. Though we've created our textures we haven't created a bind group to give to the <code>RenderPass</code>. We're still using our old <code>diffuse_bind_group</code>. If we want to change that we need to use the bind group from our materials - the <code>bind_group</code> member of the <code>Material</code> struct.</p><p>We're going to add a material parameter to <code>DrawModel</code>.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">pub</span><spanclass="token keyword">trait</span><spanclass="token type-definition class-name">DrawModel</span><spanclass="token operator"><</span><spanclass="token lifetime-annotation symbol">'a</span><spanclass="token operator">></span><spanclass="token punctuation">{</span>
</code></pre></div><p>With all that in place we should get the following.</p><p><imgsrc="/learn-wgpu/assets/img/cubes-correct.2db711eb.png"alt="cubes-correct.png"></p><h2id="rendering-the-entire-model"><ahref="#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><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">pub</span><spanclass="token keyword">trait</span><spanclass="token class-name">DrawModel</span><spanclass="token operator"><</span><spanclass="token lifetime-annotation symbol">'a</span><spanclass="token operator">></span><spanclass="token punctuation">{</span>
</code></pre></div><p>With all that in place we should get the following.</p><p><imgsrc="/learn-wgpu/assets/img/cubes-correct.2db711eb.png"alt="cubes-correct.png"></p><h2id="rendering-the-entire-model"><ahref="#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><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">pub</span><spanclass="token keyword">trait</span><spanclass="token type-definition class-name">DrawModel</span><spanclass="token operator"><</span><spanclass="token lifetime-annotation symbol">'a</span><spanclass="token operator">></span><spanclass="token punctuation">{</span>
<divid="app"data-server-rendered="true"><divclass="theme-container"><headerclass="navbar"><divclass="inner"><divclass="sidebar-button"><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"role="img"viewBox="0 0 448 512"class="icon"><pathfill="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><ahref="/learn-wgpu/"class="home-link router-link-active"><!----><spanclass="site-name">Learn Wgpu</span></a><divclass="links"><!----><divclass="search-box"><inputaria-label="Search"autocomplete="off"spellcheck="false"value=""><!----></div></div></div></header><divclass="sidebar-mask"></div><divclass="docs-layout"><asideclass="sidebar"><!----><ulclass="sidebar-links"><li><ahref="/learn-wgpu/"class="sidebar-link">Introduction</a></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading"><span>Beginner</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/beginner/tutorial1-window/"class="sidebar-link">Dependencies and the window</a></li><li><ahref="/learn-wgpu/beginner/tutorial2-surface/"class="sidebar-link">The Surface</a></li><li><ahref="/learn-wgpu/beginner/tutorial3-pipeline/"class="sidebar-link">The Pipeline</a></li><li><ahref="/learn-wgpu/beginner/tutorial4-buffer/"class="sidebar-link">Buffers and Indices</a></li><li><ahref="/learn-wgpu/beginner/tutorial5-textures/"class="sidebar-link">Textures and bind groups</a></li><li><ahref="/learn-wgpu/beginner/tutorial6-uniforms/"class="sidebar-link">Uniform buffers and a 3d camera</a></li><li><ahref="/learn-wgpu/beginner/tutorial7-instancing/"class="sidebar-link">Instancing</a></li><li><ahref="/learn-wgpu/beginner/tutorial8-depth/"class="sidebar-link">The Depth Buffer</a></li><li><ahref="/learn-wgpu/beginner/tutorial9-models/"class="sidebar-link">Model Loading</a></li></ul></section></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading open"><span>Intermediate</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/intermediate/tutorial10-lighting/"class="sidebar-link">Working with Lights</a></li><li><ahref="/learn-wgpu/intermediate/tutorial11-normals/"class="sidebar-link">Normal Mapping</a></li><li><ahref="/learn-wgpu/intermediate/tutorial12-camera/"class="active sidebar-link">A Better Camera</a><ulclass="sidebar-sub-headers"><liclass="sidebar-sub-header"><ahref="/learn-wgpu/intermediate/tutorial12-camera/#the-camera"class="sidebar-link">The Camera</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/intermediate/tutorial12-camera/#the-projection"class="sidebar-link">The Projection</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/intermediate/tutorial12-camera/#cleaning-up-main-rs"class="sidebar-link">Cleaning up main.rs</a></li></ul></li><li><ahref="/learn-wgpu/intermediate/tutorial13-threading/"class="sidebar-link">Multi-threading with Wgpu and Rayon</a></li></ul></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading"><span>Showcase</span><spanclass="arrow right"></span></p><!----></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading"><span>News</span><spanclass="arrow right"></span></p><!----></section></li></ul></aside><mainclass="page"><divclass="theme-default-content content__default"><h1id="a-better-camera"><ahref="#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><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">use</span><spanclass="token namespace">cgmath<spanclass="token punctuation">::</span></span><spanclass="token operator">*</span><spanclass="token punctuation">;</span>
<divid="app"data-server-rendered="true"><divclass="theme-container"><headerclass="navbar"><divclass="inner"><divclass="sidebar-button"><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"role="img"viewBox="0 0 448 512"class="icon"><pathfill="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><ahref="/learn-wgpu/"class="home-link router-link-active"><!----><spanclass="site-name">Learn Wgpu</span></a><divclass="links"><!----><divclass="search-box"><inputaria-label="Search"autocomplete="off"spellcheck="false"value=""><!----></div></div></div></header><divclass="sidebar-mask"></div><divclass="docs-layout"><asideclass="sidebar"><!----><ulclass="sidebar-links"><li><ahref="/learn-wgpu/"aria-current="page"class="sidebar-link">Introduction</a></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading"><span>Beginner</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/beginner/tutorial1-window/"class="sidebar-link">Dependencies and the window</a></li><li><ahref="/learn-wgpu/beginner/tutorial2-surface/"class="sidebar-link">The Surface</a></li><li><ahref="/learn-wgpu/beginner/tutorial3-pipeline/"class="sidebar-link">The Pipeline</a></li><li><ahref="/learn-wgpu/beginner/tutorial4-buffer/"class="sidebar-link">Buffers and Indices</a></li><li><ahref="/learn-wgpu/beginner/tutorial5-textures/"class="sidebar-link">Textures and bind groups</a></li><li><ahref="/learn-wgpu/beginner/tutorial6-uniforms/"class="sidebar-link">Uniform buffers and a 3d camera</a></li><li><ahref="/learn-wgpu/beginner/tutorial7-instancing/"class="sidebar-link">Instancing</a></li><li><ahref="/learn-wgpu/beginner/tutorial8-depth/"class="sidebar-link">The Depth Buffer</a></li><li><ahref="/learn-wgpu/beginner/tutorial9-models/"class="sidebar-link">Model Loading</a></li></ul></section></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading open"><span>Intermediate</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/intermediate/tutorial10-lighting/"class="sidebar-link">Working with Lights</a></li><li><ahref="/learn-wgpu/intermediate/tutorial11-normals/"class="sidebar-link">Normal Mapping</a></li><li><ahref="/learn-wgpu/intermediate/tutorial12-camera/"aria-current="page"class="active sidebar-link">A Better Camera</a><ulclass="sidebar-sub-headers"><liclass="sidebar-sub-header"><ahref="/learn-wgpu/intermediate/tutorial12-camera/#the-camera"class="sidebar-link">The Camera</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/intermediate/tutorial12-camera/#the-projection"class="sidebar-link">The Projection</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/intermediate/tutorial12-camera/#cleaning-up-main-rs"class="sidebar-link">Cleaning up main.rs</a></li></ul></li></ul></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading"><span>Showcase</span><spanclass="arrow right"></span></p><!----></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading"><span>News</span><spanclass="arrow right"></span></p><!----></section></li></ul></aside><mainclass="page"><divclass="theme-default-content content__default"><h1id="a-better-camera"><ahref="#a-better-camera"class="header-anchor">#</a> A Better Camera</h1><divclass="warn"><p>The shaders used in this example don't compile on WASM using version 0.12.0 of wgpu. They are working on the "gecko" branch, so to get the code working for WASM, change the wgpu entries in Cargo.toml to be the following.</p><divclass="language-toml extra-class"><preclass="language-toml"><code><spanclass="token punctuation">[</span><spanclass="token table class-name">dependencies</span><spanclass="token punctuation">]</span>
</code></pre></div><p>Once 0.13 comes out I'll revert to using the version published on crates.io.</p></div><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><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">use</span><spanclass="token namespace">cgmath<spanclass="token punctuation">::</span></span><spanclass="token operator">*</span><spanclass="token punctuation">;</span>
</code></pre></div><h2id="the-camera"><ahref="#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><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token attribute attr-name">#[derive(Debug)]</span>
</code></pre></div><divclass="note"><p><code>std::time::Instant</code> panics on WASM, so we'll use the <ahref="https://docs.rs/instant"target="_blank"rel="noopener noreferrer">instant crate<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="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><polygonfill="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><spanclass="sr-only">(opens new window)</span></span></a>. You'll want to include it in your <code>Cargo.toml</code>:</p><divclass="language-toml extra-class"><preclass="language-toml"><code><spanclass="token key property">instant</span><spanclass="token punctuation">=</span><spanclass="token string">"0.1"</span>
</code></pre></div></div><h2id="the-camera"><ahref="#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><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token attribute attr-name">#[derive(Debug)]</span>
</code></pre></div><p><code>input()</code> will need to be updated as well. Up to this point we have been using <code>WindowEvent</code>s for our camera controls. While this works, it's not the best solution. The <ahref="https://docs.rs/winit/0.24.0/winit/event/enum.WindowEvent.html?search=#variant.CursorMoved"target="_blank"rel="noopener noreferrer">winit docs<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"><pathfill="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><polygonfill="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> inform us that OS will often transform the data for the <code>CursorMoved</code> event to allow effects such as cursor acceleration. Because of this, we're going to change our<code>input()</code> function to use<code>DeviceEvent</code> instead of <code>WindowEvent</code>.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token comment">// UPDATED!</span>
</code></pre></div><p><code>input()</code> will need to be updated as well. Up to this point we have been using <code>WindowEvent</code>s for our camera controls. While this works, it's not the best solution. The <ahref="https://docs.rs/winit/0.24.0/winit/event/enum.WindowEvent.html?search=#variant.CursorMoved"target="_blank"rel="noopener noreferrer">winit docs<span><svg xmlns="http://www.w3.org/2000/svg"aria-hidden="true" focusable="false" x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="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><polygonfill="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><spanclass="sr-only">(opens new window)</span></span></a> inform us that OS will often transform the data for the <code>CursorMoved</code> event to allow effects such as cursor acceleration.</p><p>Now to fix this we could change the<code>input()</code> function to process<code>DeviceEvent</code> instead of <code>WindowEvent</code>, but keyboard and button presses don't get emitted as <code>DeviceEvent</code>s on MacOS and WASM. Instead, we'll just remove the <code>CursorMoved</code> check in <code>input()</code>, and a manual call to <code>camera_controller.process_mouse()</code> in the <code>run()</code> function.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token comment">// UPDATED!</span>
</code></pre></div><p>This change means will have to modify the event loop in <code>main()</code> as well.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">fn</span><spanclass="token function-definition function">main</span><spanclass="token punctuation">(</span><spanclass="token punctuation">)</span><spanclass="token punctuation">{</span>
</code></pre></div><p>Here are the changes to <code>run()</code>:</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">fn</span><spanclass="token function-definition function">main</span><spanclass="token punctuation">(</span><spanclass="token punctuation">)</span><spanclass="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><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">fn</span><spanclass="token function-definition function">update</span><spanclass="token punctuation">(</span><spanclass="token operator">&</span><spanclass="token keyword">mut</span><spanclass="token keyword">self</span><spanclass="token punctuation">,</span> dt<spanclass="token punctuation">:</span><spanclass="token namespace">std<spanclass="token punctuation">::</span>time<spanclass="token punctuation">::</span></span><spanclass="token class-name">Duration</span><spanclass="token punctuation">)</span><spanclass="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><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">fn</span><spanclass="token function-definition function">update</span><spanclass="token punctuation">(</span><spanclass="token operator">&</span><spanclass="token keyword">mut</span><spanclass="token keyword">self</span><spanclass="token punctuation">,</span> dt<spanclass="token punctuation">:</span><spanclass="token namespace">instant<spanclass="token punctuation">::</span></span><spanclass="token class-name">Duration</span><spanclass="token punctuation">)</span><spanclass="token punctuation">{</span>
</code></pre></div><p>We still need to calculate <code>dt</code>. Let's do that in the <code>main</code> function.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">fn</span><spanclass="token function-definition function">main</span><spanclass="token punctuation">(</span><spanclass="token punctuation">)</span><spanclass="token punctuation">{</span>
</code></pre></div><p>With that we should be able to move our camera wherever we want.</p><p><imgsrc="/learn-wgpu/assets/img/screenshot.4f5740bc.png"alt="./screenshot.png"></p><div class="auto-github-link"><ahref="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"><pathfill="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><polygonfill="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><footerclass="page-edit"><!----><divclass="last-updated"><spanclass="prefix">Last Updated: </span><spanclass="time">3/18/2022, 7:17:14 PM</span></div></footer><divclass="page-nav"><pclass="inner"><spanclass="prev">
</code></pre></div><p>With that we should be able to move our camera wherever we want.</p><p><imgsrc="/learn-wgpu/assets/img/screenshot.4f5740bc.png"alt="./screenshot.png"></p><divid="wasm-example"><!----><button>Try Tutorial12_camera!</button></div><divclass="auto-github-link"><ahref="https://github.com/sotrh/learn-wgpu/tree/master/code/intermediate/tutorial12-camera/"target="_blank"rel="noopener noreferrer">Check out the code!</a><span><svg xmlns="http://www.w3.org/2000/svg"aria-hidden="true" focusable="false" x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="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><polygonfill="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><spanclass="sr-only">(opens new window)</span></span></div></div><footerclass="page-edit"><!----><divclass="last-updated"><spanclass="prefix">Last Updated: </span><spanclass="time">3/26/2022, 12:15:11 AM</span></div></footer><divclass="page-nav"><pclass="inner"><spanclass="prev">
<metaproperty="article:modified_time"content="2022-03-18T19:17:14.000Z"><metaproperty="og:site_name"content="Learn Wgpu"><metaproperty="og:title"content="Multi-threading with Wgpu and Rayon"><metaproperty="og:type"content="website"><metaproperty="og:url"content="/intermediate/tutorial13-threading/"><metaname="twitter:title"content="Multi-threading with Wgpu and Rayon"><metaname="twitter:url"content="/intermediate/tutorial13-threading/"><metaname="twitter:card"content="summary_large_image"><metaname="twitter:label1"content="Written by"><metaname="twitter:data2"content="Benjamin Hansen"><metaname="twitter:creator"content="https://twitter.com/sotrh760">
<divid="app"data-server-rendered="true"><divclass="theme-container"><headerclass="navbar"><divclass="inner"><divclass="sidebar-button"><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"role="img"viewBox="0 0 448 512"class="icon"><pathfill="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><ahref="/learn-wgpu/"class="home-link router-link-active"><!----><spanclass="site-name">Learn Wgpu</span></a><divclass="links"><!----><divclass="search-box"><inputaria-label="Search"autocomplete="off"spellcheck="false"value=""><!----></div></div></div></header><divclass="sidebar-mask"></div><divclass="docs-layout"><asideclass="sidebar"><!----><ulclass="sidebar-links"><li><ahref="/learn-wgpu/"class="sidebar-link">Introduction</a></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading"><span>Beginner</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/beginner/tutorial1-window/"class="sidebar-link">Dependencies and the window</a></li><li><ahref="/learn-wgpu/beginner/tutorial2-surface/"class="sidebar-link">The Surface</a></li><li><ahref="/learn-wgpu/beginner/tutorial3-pipeline/"class="sidebar-link">The Pipeline</a></li><li><ahref="/learn-wgpu/beginner/tutorial4-buffer/"class="sidebar-link">Buffers and Indices</a></li><li><ahref="/learn-wgpu/beginner/tutorial5-textures/"class="sidebar-link">Textures and bind groups</a></li><li><ahref="/learn-wgpu/beginner/tutorial6-uniforms/"class="sidebar-link">Uniform buffers and a 3d camera</a></li><li><ahref="/learn-wgpu/beginner/tutorial7-instancing/"class="sidebar-link">Instancing</a></li><li><ahref="/learn-wgpu/beginner/tutorial8-depth/"class="sidebar-link">The Depth Buffer</a></li><li><ahref="/learn-wgpu/beginner/tutorial9-models/"class="sidebar-link">Model Loading</a></li></ul></section></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading open"><span>Intermediate</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/intermediate/tutorial10-lighting/"class="sidebar-link">Working with Lights</a></li><li><ahref="/learn-wgpu/intermediate/tutorial11-normals/"class="sidebar-link">Normal Mapping</a></li><li><ahref="/learn-wgpu/intermediate/tutorial12-camera/"class="sidebar-link">A Better Camera</a></li><li><ahref="/learn-wgpu/intermediate/tutorial13-threading/"class="active sidebar-link">Multi-threading with Wgpu and Rayon</a><ulclass="sidebar-sub-headers"><liclass="sidebar-sub-header"><ahref="/learn-wgpu/intermediate/tutorial13-threading/#parallelizing-loading-models-and-textures"class="sidebar-link">Parallelizing loading models and textures</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/intermediate/tutorial13-threading/#it-s-that-easy"class="sidebar-link">It's that easy!</a></li></ul></li></ul></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading"><span>Showcase</span><spanclass="arrow right"></span></p><!----></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading"><span>News</span><spanclass="arrow right"></span></p><!----></section></li></ul></aside><mainclass="page"><divclass="theme-default-content content__default"><h1id="multi-threading-with-wgpu-and-rayon"><ahref="#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><divclass="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><h2id="parallelizing-loading-models-and-textures"><ahref="#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><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token comment">// model.rs</span>
<divid="app"data-server-rendered="true"><divclass="theme-container"><headerclass="navbar"><divclass="inner"><divclass="sidebar-button"><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"role="img"viewBox="0 0 448 512"class="icon"><pathfill="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><ahref="/learn-wgpu/"class="home-link router-link-active"><!----><spanclass="site-name">Learn Wgpu</span></a><divclass="links"><!----><divclass="search-box"><inputaria-label="Search"autocomplete="off"spellcheck="false"value=""><!----></div></div></div></header><divclass="sidebar-mask"></div><divclass="docs-layout"><asideclass="sidebar"><!----><ulclass="sidebar-links"><li><ahref="/learn-wgpu/"aria-current="page"class="sidebar-link">Introduction</a></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading"><span>Beginner</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/beginner/tutorial1-window/"class="sidebar-link">Dependencies and the window</a></li><li><ahref="/learn-wgpu/beginner/tutorial2-surface/"class="sidebar-link">The Surface</a></li><li><ahref="/learn-wgpu/beginner/tutorial3-pipeline/"class="sidebar-link">The Pipeline</a></li><li><ahref="/learn-wgpu/beginner/tutorial4-buffer/"class="sidebar-link">Buffers and Indices</a></li><li><ahref="/learn-wgpu/beginner/tutorial5-textures/"class="sidebar-link">Textures and bind groups</a></li><li><ahref="/learn-wgpu/beginner/tutorial6-uniforms/"class="sidebar-link">Uniform buffers and a 3d camera</a></li><li><ahref="/learn-wgpu/beginner/tutorial7-instancing/"class="sidebar-link">Instancing</a></li><li><ahref="/learn-wgpu/beginner/tutorial8-depth/"class="sidebar-link">The Depth Buffer</a></li><li><ahref="/learn-wgpu/beginner/tutorial9-models/"class="sidebar-link">Model Loading</a></li></ul></section></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading"><span>Intermediate</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/intermediate/tutorial10-lighting/"class="sidebar-link">Working with Lights</a></li><li><ahref="/learn-wgpu/intermediate/tutorial11-normals/"class="sidebar-link">Normal Mapping</a></li><li><ahref="/learn-wgpu/intermediate/tutorial12-camera/"class="sidebar-link">A Better Camera</a></li></ul></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading"><span>Showcase</span><spanclass="arrow right"></span></p><!----></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading"><span>News</span><spanclass="arrow right"></span></p><!----></section></li></ul></aside><mainclass="page"><divclass="theme-default-content content__default"><h1id="multi-threading-with-wgpu-and-rayon"><ahref="#multi-threading-with-wgpu-and-rayon"class="header-anchor">#</a> Multi-threading with Wgpu and Rayon</h1><divclass="warn"><p>The shaders used in this example don't compile on WASM using version 0.12.0 of wgpu. They are working on the "gecko" branch, so to get the code working for WASM, change the wgpu entries in Cargo.toml to be the following.</p><divclass="language-toml extra-class"><preclass="language-toml"><code><spanclass="token punctuation">[</span><spanclass="token table class-name">dependencies</span><spanclass="token punctuation">]</span>
</code></pre></div><p>Once 0.13 comes out I'll revert to using the version published on crates.io.</p></div><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><divclass="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><h2id="parallelizing-loading-models-and-textures"><ahref="#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><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token comment">// resources.rs</span>
</code></pre></div><p>We've parallelized loading the meshes, and making the vertex array for them. Probably a bit overkill, but <code>rayon</code> should prevent us from using too many threads.</p><divclass="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><h2id="it-s-that-easy"><ahref="#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><divclass="language- extra-class"><preclass="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><divclass="auto-github-link"><ahref="https://github.com/sotrh/learn-wgpu/tree/master/code/intermediate/tutorial13-threading/"target="_blank"rel="noopener noreferrer">Check out the code!</a><svgxmlns="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"><pathfill="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><polygonfill="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><footerclass="page-edit"><!----><divclass="last-updated"><spanclass="prefix">Last Updated: </span><spanclass="time">3/18/2022, 7:17:14 PM</span></div></footer><divclass="page-nav"><pclass="inner"><spanclass="prev">
</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><divid="wasm-example"><!----><button>Try Tutorial12_camera!</button></div><divclass="auto-github-link"><ahref="https://github.com/sotrh/learn-wgpu/tree/master/code/intermediate/tutorial13-threading/"target="_blank"rel="noopener noreferrer">Check out the code!</a><span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="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><polygonfill="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><spanclass="sr-only">(opens new window)</span></span></div></div><footerclass="page-edit"><!----><divclass="last-updated"><spanclass="prefix">Last Updated: </span><spanclass="time">3/26/2022, 12:15:11 AM</span></div></footer><!----></main></div></div><divclass="global-ui"><!----></div></div>
<metaproperty="article:modified_time"content="2022-03-18T19:17:14.000Z"><metaproperty="og:site_name"content="Learn Wgpu"><metaproperty="og:title"content="Update to 0.12!"><metaproperty="og:type"content="website"><metaproperty="og:url"content="/news/0.12/"><metaname="twitter:title"content="Update to 0.12!"><metaname="twitter:url"content="/news/0.12/"><metaname="twitter:card"content="summary_large_image"><metaname="twitter:label1"content="Written by"><metaname="twitter:data2"content="Benjamin Hansen"><metaname="twitter:creator"content="https://twitter.com/sotrh760">
<divid="app"data-server-rendered="true"><divclass="theme-container"><headerclass="navbar"><divclass="inner"><divclass="sidebar-button"><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"role="img"viewBox="0 0 448 512"class="icon"><pathfill="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><ahref="/learn-wgpu/"class="home-link router-link-active"><!----><spanclass="site-name">Learn Wgpu</span></a><divclass="links"><!----><divclass="search-box"><inputaria-label="Search"autocomplete="off"spellcheck="false"value=""><!----></div></div></div></header><divclass="sidebar-mask"></div><divclass="docs-layout"><asideclass="sidebar"><!----><ulclass="sidebar-links"><li><ahref="/learn-wgpu/"class="sidebar-link">Introduction</a></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading"><span>Beginner</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/beginner/tutorial1-window/"class="sidebar-link">Dependencies and the window</a></li><li><ahref="/learn-wgpu/beginner/tutorial2-surface/"class="sidebar-link">The Surface</a></li><li><ahref="/learn-wgpu/beginner/tutorial3-pipeline/"class="sidebar-link">The Pipeline</a></li><li><ahref="/learn-wgpu/beginner/tutorial4-buffer/"class="sidebar-link">Buffers and Indices</a></li><li><ahref="/learn-wgpu/beginner/tutorial5-textures/"class="sidebar-link">Textures and bind groups</a></li><li><ahref="/learn-wgpu/beginner/tutorial6-uniforms/"class="sidebar-link">Uniform buffers and a 3d camera</a></li><li><ahref="/learn-wgpu/beginner/tutorial7-instancing/"class="sidebar-link">Instancing</a></li><li><ahref="/learn-wgpu/beginner/tutorial8-depth/"class="sidebar-link">The Depth Buffer</a></li><li><ahref="/learn-wgpu/beginner/tutorial9-models/"class="sidebar-link">Model Loading</a></li></ul></section></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading"><span>Intermediate</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/intermediate/tutorial10-lighting/"class="sidebar-link">Working with Lights</a></li><li><ahref="/learn-wgpu/intermediate/tutorial11-normals/"class="sidebar-link">Normal Mapping</a></li><li><ahref="/learn-wgpu/intermediate/tutorial12-camera/"class="sidebar-link">A Better Camera</a></li><li><ahref="/learn-wgpu/intermediate/tutorial13-threading/"class="sidebar-link">Multi-threading with Wgpu and Rayon</a></li></ul></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading"><span>Showcase</span><spanclass="arrow right"></span></p><!----></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading open"><span>News</span><spanclass="arrow down"></span></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/news/0.12/"class="active sidebar-link">Update to 0.12!</a><ulclass="sidebar-sub-headers"><liclass="sidebar-sub-header"><ahref="/learn-wgpu/news/0.12/#multi-view-added"class="sidebar-link">Multi view added</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/news/0.12/#no-more-block-attribute"class="sidebar-link">No more block attribute</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/news/0.12/#more-validation"class="sidebar-link">More validation</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/news/0.12/#misc"class="sidebar-link">Misc</a></li></ul></li><li><ahref="/learn-wgpu/news/pre-0.12/"class="sidebar-link">News (Pre 0.12)</a></li></ul></section></li></ul></aside><mainclass="page"><divclass="theme-default-content content__default"><h1id="update-to-0-12"><ahref="#update-to-0-12"class="header-anchor">#</a> Update to 0.12!</h1><p>There's not a ton of changes in this release, so the migration
<divid="app"data-server-rendered="true"><divclass="theme-container"><headerclass="navbar"><divclass="inner"><divclass="sidebar-button"><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"role="img"viewBox="0 0 448 512"class="icon"><pathfill="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><ahref="/learn-wgpu/"class="home-link router-link-active"><!----><spanclass="site-name">Learn Wgpu</span></a><divclass="links"><!----><divclass="search-box"><inputaria-label="Search"autocomplete="off"spellcheck="false"value=""><!----></div></div></div></header><divclass="sidebar-mask"></div><divclass="docs-layout"><asideclass="sidebar"><!----><ulclass="sidebar-links"><li><ahref="/learn-wgpu/"aria-current="page"class="sidebar-link">Introduction</a></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading"><span>Beginner</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/beginner/tutorial1-window/"class="sidebar-link">Dependencies and the window</a></li><li><ahref="/learn-wgpu/beginner/tutorial2-surface/"class="sidebar-link">The Surface</a></li><li><ahref="/learn-wgpu/beginner/tutorial3-pipeline/"class="sidebar-link">The Pipeline</a></li><li><ahref="/learn-wgpu/beginner/tutorial4-buffer/"class="sidebar-link">Buffers and Indices</a></li><li><ahref="/learn-wgpu/beginner/tutorial5-textures/"class="sidebar-link">Textures and bind groups</a></li><li><ahref="/learn-wgpu/beginner/tutorial6-uniforms/"class="sidebar-link">Uniform buffers and a 3d camera</a></li><li><ahref="/learn-wgpu/beginner/tutorial7-instancing/"class="sidebar-link">Instancing</a></li><li><ahref="/learn-wgpu/beginner/tutorial8-depth/"class="sidebar-link">The Depth Buffer</a></li><li><ahref="/learn-wgpu/beginner/tutorial9-models/"class="sidebar-link">Model Loading</a></li></ul></section></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading"><span>Intermediate</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/intermediate/tutorial10-lighting/"class="sidebar-link">Working with Lights</a></li><li><ahref="/learn-wgpu/intermediate/tutorial11-normals/"class="sidebar-link">Normal Mapping</a></li><li><ahref="/learn-wgpu/intermediate/tutorial12-camera/"class="sidebar-link">A Better Camera</a></li></ul></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading"><span>Showcase</span><spanclass="arrow right"></span></p><!----></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading open"><span>News</span><spanclass="arrow down"></span></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/news/0.12/" aria-current="page" class="active sidebar-link">Update to 0.12!</a><ulclass="sidebar-sub-headers"><liclass="sidebar-sub-header"><ahref="/learn-wgpu/news/0.12/#multi-view-added"class="sidebar-link">Multi view added</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/news/0.12/#no-more-block-attribute"class="sidebar-link">No more block attribute</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/news/0.12/#more-validation"class="sidebar-link">More validation</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/news/0.12/#misc"class="sidebar-link">Misc</a></li></ul></li><li><ahref="/learn-wgpu/news/pre-0.12/"class="sidebar-link">News (Pre 0.12)</a></li></ul></section></li></ul></aside><mainclass="page"><divclass="theme-default-content content__default"><h1id="update-to-0-12"><ahref="#update-to-0-12"class="header-anchor">#</a> Update to 0.12!</h1><p>There's not a ton of changes in this release, so the migration
wasn't too painful.</p><h2id="multi-view-added"><ahref="#multi-view-added"class="header-anchor">#</a> Multi view added</h2><p>The <code>RenderPipelineDescriptor</code> now includes a <code>multiview</code> field that
indicates the number of array textures if array textures are used
as render attachments.</p><h2id="no-more-block-attribute"><ahref="#no-more-block-attribute"class="header-anchor">#</a> No more block attribute</h2><p>The WGSL spec has changed and the <code>block</code> attribute is no longer a thing.
@ -46,11 +57,11 @@ I needed to do was add a padding field:</p> <div class="language-rust extra-clas
<spanclass="token comment">// Due to uniforms requiring 16 byte (4 float) spacing, we need to use a padding field here</span>
</code></pre></div><p>I updated the <ahref="../../intermediate/tutorial10-lighting">lighting tutorial</a> to reflect this change.</p><h2id="misc"><ahref="#misc"class="header-anchor">#</a> Misc</h2><p>Due to the recent deploy to <ahref="https://docs.rs/anyhow/latest/"target="_blank"rel="noopener noreferrer">anyhow<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"><pathfill="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><polygonfill="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> that
</code></pre></div><p>I updated the <ahref="../../intermediate/tutorial10-lighting">lighting tutorial</a> to reflect this change.</p><h2id="misc"><ahref="#misc"class="header-anchor">#</a> Misc</h2><p>Due to the recent deploy to <ahref="https://docs.rs/anyhow/latest/"target="_blank"rel="noopener noreferrer">anyhow<span><svg xmlns="http://www.w3.org/2000/svg"aria-hidden="true" focusable="false" x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="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><polygonfill="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><spanclass="sr-only">(opens new window)</span></span></a> that
breaks glob imports (aka. <code>use anyhow::*</code>), I had to switch qualified
imports and uses (ie. <code>anyhow::Result</code>). This was mostly an issue on my
build scripts for some of the showcase examples.</p><p>The main tutorial examples weren't affected, and the changes are minor, so
if your curious feel free to look at the repo.</p></div><footerclass="page-edit"><!----><divclass="last-updated"><spanclass="prefix">Last Updated: </span><spanclass="time">3/18/2022, 7:17:14 PM</span></div></footer><divclass="page-nav"><pclass="inner"><spanclass="prev">
if your curious feel free to look at the repo.</p></div><footerclass="page-edit"><!----><divclass="last-updated"><spanclass="prefix">Last Updated: </span><spanclass="time">3/26/2022, 12:15:11 AM</span></div></footer><divclass="page-nav"><pclass="inner"><spanclass="prev">
<metaproperty="article:modified_time"content="2022-03-18T19:17:14.000Z"><metaproperty="og:site_name"content="Learn Wgpu"><metaproperty="og:title"content="Memory Layout in WGSL"><metaproperty="og:type"content="website"><metaproperty="og:url"content="/showcase/alignment/"><metaname="twitter:title"content="Memory Layout in WGSL"><metaname="twitter:url"content="/showcase/alignment/"><metaname="twitter:card"content="summary_large_image"><metaname="twitter:label1"content="Written by"><metaname="twitter:data2"content="Benjamin Hansen"><metaname="twitter:creator"content="https://twitter.com/sotrh760">
<divid="app"data-server-rendered="true"><divclass="theme-container"><headerclass="navbar"><divclass="inner"><divclass="sidebar-button"><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"role="img"viewBox="0 0 448 512"class="icon"><pathfill="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><ahref="/learn-wgpu/"class="home-link router-link-active"><!----><spanclass="site-name">Learn Wgpu</span></a><divclass="links"><!----><divclass="search-box"><inputaria-label="Search"autocomplete="off"spellcheck="false"value=""><!----></div></div></div></header><divclass="sidebar-mask"></div><divclass="docs-layout"><asideclass="sidebar"><!----><ulclass="sidebar-links"><li><ahref="/learn-wgpu/"class="sidebar-link">Introduction</a></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading"><span>Beginner</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/beginner/tutorial1-window/"class="sidebar-link">Dependencies and the window</a></li><li><ahref="/learn-wgpu/beginner/tutorial2-surface/"class="sidebar-link">The Surface</a></li><li><ahref="/learn-wgpu/beginner/tutorial3-pipeline/"class="sidebar-link">The Pipeline</a></li><li><ahref="/learn-wgpu/beginner/tutorial4-buffer/"class="sidebar-link">Buffers and Indices</a></li><li><ahref="/learn-wgpu/beginner/tutorial5-textures/"class="sidebar-link">Textures and bind groups</a></li><li><ahref="/learn-wgpu/beginner/tutorial6-uniforms/"class="sidebar-link">Uniform buffers and a 3d camera</a></li><li><ahref="/learn-wgpu/beginner/tutorial7-instancing/"class="sidebar-link">Instancing</a></li><li><ahref="/learn-wgpu/beginner/tutorial8-depth/"class="sidebar-link">The Depth Buffer</a></li><li><ahref="/learn-wgpu/beginner/tutorial9-models/"class="sidebar-link">Model Loading</a></li></ul></section></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading"><span>Intermediate</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/intermediate/tutorial10-lighting/"class="sidebar-link">Working with Lights</a></li><li><ahref="/learn-wgpu/intermediate/tutorial11-normals/"class="sidebar-link">Normal Mapping</a></li><li><ahref="/learn-wgpu/intermediate/tutorial12-camera/"class="sidebar-link">A Better Camera</a></li><li><ahref="/learn-wgpu/intermediate/tutorial13-threading/"class="sidebar-link">Multi-threading with Wgpu and Rayon</a></li></ul></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading open"><span>Showcase</span><spanclass="arrow down"></span></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/showcase/"class="sidebar-link">Foreword</a></li><li><ahref="/learn-wgpu/showcase/windowless/"class="sidebar-link">Wgpu without a window</a></li><li><ahref="/learn-wgpu/showcase/gifs/"class="sidebar-link">Creating gifs</a></li><li><ahref="/learn-wgpu/showcase/pong/"class="sidebar-link">Pong</a></li><li><ahref="/learn-wgpu/showcase/compute/"class="sidebar-link">Compute Example: Tangents and Bitangents</a></li><li><ahref="/learn-wgpu/showcase/alignment/"class="active sidebar-link">Memory Layout in WGSL</a><ulclass="sidebar-sub-headers"><liclass="sidebar-sub-header"><ahref="/learn-wgpu/showcase/alignment/#alignment-of-vertex-and-index-buffers"class="sidebar-link">Alignment of vertex and index buffers</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/showcase/alignment/#alignment-of-uniform-and-storage-buffers"class="sidebar-link">Alignment of Uniform and Storage buffers</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/showcase/alignment/#how-to-deal-with-alignment-issues"class="sidebar-link">How to deal with alignment issues</a></li></ul></li></ul></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading"><span>News</span><spanclass="arrow right"></span></p><!----></section></li></ul></aside><mainclass="page"><divclass="theme-default-content content__default"><h1id="memory-layout-in-wgsl"><ahref="#memory-layout-in-wgsl"class="header-anchor">#</a> Memory Layout in WGSL</h1><divclass="warn"><p>This page is currently being reworked. I want to understand the topics a bit better, but
<divid="app"data-server-rendered="true"><divclass="theme-container"><headerclass="navbar"><divclass="inner"><divclass="sidebar-button"><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"role="img"viewBox="0 0 448 512"class="icon"><pathfill="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><ahref="/learn-wgpu/"class="home-link router-link-active"><!----><spanclass="site-name">Learn Wgpu</span></a><divclass="links"><!----><divclass="search-box"><inputaria-label="Search"autocomplete="off"spellcheck="false"value=""><!----></div></div></div></header><divclass="sidebar-mask"></div><divclass="docs-layout"><asideclass="sidebar"><!----><ulclass="sidebar-links"><li><ahref="/learn-wgpu/"aria-current="page"class="sidebar-link">Introduction</a></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading"><span>Beginner</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/beginner/tutorial1-window/"class="sidebar-link">Dependencies and the window</a></li><li><ahref="/learn-wgpu/beginner/tutorial2-surface/"class="sidebar-link">The Surface</a></li><li><ahref="/learn-wgpu/beginner/tutorial3-pipeline/"class="sidebar-link">The Pipeline</a></li><li><ahref="/learn-wgpu/beginner/tutorial4-buffer/"class="sidebar-link">Buffers and Indices</a></li><li><ahref="/learn-wgpu/beginner/tutorial5-textures/"class="sidebar-link">Textures and bind groups</a></li><li><ahref="/learn-wgpu/beginner/tutorial6-uniforms/"class="sidebar-link">Uniform buffers and a 3d camera</a></li><li><ahref="/learn-wgpu/beginner/tutorial7-instancing/"class="sidebar-link">Instancing</a></li><li><ahref="/learn-wgpu/beginner/tutorial8-depth/"class="sidebar-link">The Depth Buffer</a></li><li><ahref="/learn-wgpu/beginner/tutorial9-models/"class="sidebar-link">Model Loading</a></li></ul></section></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading"><span>Intermediate</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/intermediate/tutorial10-lighting/"class="sidebar-link">Working with Lights</a></li><li><ahref="/learn-wgpu/intermediate/tutorial11-normals/"class="sidebar-link">Normal Mapping</a></li><li><ahref="/learn-wgpu/intermediate/tutorial12-camera/"class="sidebar-link">A Better Camera</a></li></ul></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading open"><span>Showcase</span><spanclass="arrow down"></span></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/showcase/" aria-current="page" class="sidebar-link">Foreword</a></li><li><ahref="/learn-wgpu/showcase/windowless/"class="sidebar-link">Wgpu without a window</a></li><li><ahref="/learn-wgpu/showcase/gifs/"class="sidebar-link">Creating gifs</a></li><li><ahref="/learn-wgpu/showcase/pong/"class="sidebar-link">Pong</a></li><li><ahref="/learn-wgpu/showcase/compute/"class="sidebar-link">Compute Example: Tangents and Bitangents</a></li><li><ahref="/learn-wgpu/showcase/alignment/" aria-current="page" class="active sidebar-link">Memory Layout in WGSL</a><ulclass="sidebar-sub-headers"><liclass="sidebar-sub-header"><ahref="/learn-wgpu/showcase/alignment/#alignment-of-vertex-and-index-buffers"class="sidebar-link">Alignment of vertex and index buffers</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/showcase/alignment/#alignment-of-uniform-and-storage-buffers"class="sidebar-link">Alignment of Uniform and Storage buffers</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/showcase/alignment/#how-to-deal-with-alignment-issues"class="sidebar-link">How to deal with alignment issues</a></li></ul></li></ul></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading"><span>News</span><spanclass="arrow right"></span></p><!----></section></li></ul></aside><mainclass="page"><divclass="theme-default-content content__default"><h1id="memory-layout-in-wgsl"><ahref="#memory-layout-in-wgsl"class="header-anchor">#</a> Memory Layout in WGSL</h1><divclass="warn"><p>This page is currently being reworked. I want to understand the topics a bit better, but
as 0.12 is out I want to release what I have for now.</p></div><h2id="alignment-of-vertex-and-index-buffers"><ahref="#alignment-of-vertex-and-index-buffers"class="header-anchor">#</a> Alignment of vertex and index buffers</h2><p>Vertex buffers require defining a <code>VertexBufferLayout</code>, so the memory alignment is whatever
you tell WebGPU it should be. This can be really convenient for keeping down memory usage
on the GPU.</p><p>The Index Buffer use the alignment of whatever primitive type you specify via the <code>IndexFormat</code>
@ -22,7 +33,7 @@ on processing aligned by powers of 2. The exact specifics of why this is are bey
my level of knowledge, but it's important to know so that you can trouble shoot why your
shaders aren't working.</p><p>Let's take a look at the following table:</p><hr><table><thead><tr><th>Type</th><th>Alignment in Bytes</th><th>Size in Bytes</th></tr></thead><tbody><tr><td>scalar (i32, u32, f32)</td><td>4</td><td>4</td></tr><tr><td>vec2<T></td><td>8</td><td>8</td></tr><tr><td>vec3<T></td><td><strong>16</strong></td><td>12</td></tr><tr><td>vec4<T></td><td>16</td><td>16</td></tr></tbody></table><p>You can see for <code>vec3</code> the alignment is the next power of 2 from the size, 16. This can
catch beginners (and even veterans) off guard as it's not the most intuitive. This becomes especially
important when we start laying out structs. Take the light struct from the <ahref="/learn-wgpu/intermediate/tutorial10-lighting/#seeing-the-light">lighting tutorial</a>:</p><p>You can see the full table of the alignments in section <ahref="https://www.w3.org/TR/WGSL/#alignment-and-size"target="_blank"rel="noopener noreferrer">4.3.7.1 of the WGSL spec<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"><pathfill="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><polygonfill="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></p><divclass="language-wgsl extra-class"><preclass="language-text"><code>struct Light {
important when we start laying out structs. Take the light struct from the <ahref="/learn-wgpu/intermediate/tutorial10-lighting/#seeing-the-light">lighting tutorial</a>:</p><p>You can see the full table of the alignments in section <ahref="https://www.w3.org/TR/WGSL/#alignment-and-size"target="_blank"rel="noopener noreferrer">4.3.7.1 of the WGSL spec<span><svg xmlns="http://www.w3.org/2000/svg"aria-hidden="true" focusable="false" x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="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><polygonfill="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><spanclass="sr-only">(opens new window)</span></span></a></p><divclass="language-wgsl extra-class"><preclass="language-text"><code>struct Light {
position: vec3<f32>;
color: vec3<f32>;
};
@ -45,7 +56,7 @@ be able to do something like the following:</p> <div class="language-rust extra-
</code></pre></div><p>But this won't compile. The <ahref="https://docs.rs/bytemuck/"target="_blank"rel="noopener noreferrer">bytemuck crate<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"><pathfill="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><polygonfill="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> doesn't work with
</code></pre></div><p>But this won't compile. The <ahref="https://docs.rs/bytemuck/"target="_blank"rel="noopener noreferrer">bytemuck crate<span><svg xmlns="http://www.w3.org/2000/svg"aria-hidden="true" focusable="false" x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="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><polygonfill="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><spanclass="sr-only">(opens new window)</span></span></a> doesn't work with
structs with implicit padding bytes. Rust can't guarantee that the memory between the fields
has been initialized properly. This gave be an error when I tried it:</p><divclass="language- extra-class"><preclass="language-text"><code>error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
<divid="app"data-server-rendered="true"><divclass="theme-container"><headerclass="navbar"><divclass="inner"><divclass="sidebar-button"><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"role="img"viewBox="0 0 448 512"class="icon"><pathfill="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><ahref="/learn-wgpu/"class="home-link router-link-active"><!----><spanclass="site-name">Learn Wgpu</span></a><divclass="links"><!----><divclass="search-box"><inputaria-label="Search"autocomplete="off"spellcheck="false"value=""><!----></div></div></div></header><divclass="sidebar-mask"></div><divclass="docs-layout"><asideclass="sidebar"><!----><ulclass="sidebar-links"><li><ahref="/learn-wgpu/"class="sidebar-link">Introduction</a></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading"><span>Beginner</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/beginner/tutorial1-window/"class="sidebar-link">Dependencies and the window</a></li><li><ahref="/learn-wgpu/beginner/tutorial2-surface/"class="sidebar-link">The Surface</a></li><li><ahref="/learn-wgpu/beginner/tutorial3-pipeline/"class="sidebar-link">The Pipeline</a></li><li><ahref="/learn-wgpu/beginner/tutorial4-buffer/"class="sidebar-link">Buffers and Indices</a></li><li><ahref="/learn-wgpu/beginner/tutorial5-textures/"class="sidebar-link">Textures and bind groups</a></li><li><ahref="/learn-wgpu/beginner/tutorial6-uniforms/"class="sidebar-link">Uniform buffers and a 3d camera</a></li><li><ahref="/learn-wgpu/beginner/tutorial7-instancing/"class="sidebar-link">Instancing</a></li><li><ahref="/learn-wgpu/beginner/tutorial8-depth/"class="sidebar-link">The Depth Buffer</a></li><li><ahref="/learn-wgpu/beginner/tutorial9-models/"class="sidebar-link">Model Loading</a></li></ul></section></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading"><span>Intermediate</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/intermediate/tutorial10-lighting/"class="sidebar-link">Working with Lights</a></li><li><ahref="/learn-wgpu/intermediate/tutorial11-normals/"class="sidebar-link">Normal Mapping</a></li><li><ahref="/learn-wgpu/intermediate/tutorial12-camera/"class="sidebar-link">A Better Camera</a></li><li><ahref="/learn-wgpu/intermediate/tutorial13-threading/"class="sidebar-link">Multi-threading with Wgpu and Rayon</a></li></ul></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading open"><span>Showcase</span><spanclass="arrow down"></span></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/showcase/"class="sidebar-link">Foreword</a></li><li><ahref="/learn-wgpu/showcase/windowless/"class="sidebar-link">Wgpu without a window</a></li><li><ahref="/learn-wgpu/showcase/gifs/"class="sidebar-link">Creating gifs</a></li><li><ahref="/learn-wgpu/showcase/pong/"class="sidebar-link">Pong</a></li><li><ahref="/learn-wgpu/showcase/compute/"class="active sidebar-link">Compute Example: Tangents and Bitangents</a><ulclass="sidebar-sub-headers"><liclass="sidebar-sub-header"><ahref="/learn-wgpu/showcase/compute/#possible-improvements"class="sidebar-link">Possible Improvements</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/showcase/compute/#results"class="sidebar-link">Results</a></li></ul></li><li><ahref="/learn-wgpu/showcase/alignment/"class="sidebar-link">Memory Layout in WGSL</a></li></ul></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading"><span>News</span><spanclass="arrow right"></span></p><!----></section></li></ul></aside><mainclass="page"><divclass="theme-default-content content__default"><h1id="compute-example-tangents-and-bitangents"><ahref="#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 <ahref="/learn-wgpu/intermediate/tutorial11-normals/">normal mapping tutorial</a>.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token attribute attr-name">#[repr(C)]</span>
<divid="app"data-server-rendered="true"><divclass="theme-container"><headerclass="navbar"><divclass="inner"><divclass="sidebar-button"><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"role="img"viewBox="0 0 448 512"class="icon"><pathfill="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><ahref="/learn-wgpu/"class="home-link router-link-active"><!----><spanclass="site-name">Learn Wgpu</span></a><divclass="links"><!----><divclass="search-box"><inputaria-label="Search"autocomplete="off"spellcheck="false"value=""><!----></div></div></div></header><divclass="sidebar-mask"></div><divclass="docs-layout"><asideclass="sidebar"><!----><ulclass="sidebar-links"><li><ahref="/learn-wgpu/"aria-current="page"class="sidebar-link">Introduction</a></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading"><span>Beginner</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/beginner/tutorial1-window/"class="sidebar-link">Dependencies and the window</a></li><li><ahref="/learn-wgpu/beginner/tutorial2-surface/"class="sidebar-link">The Surface</a></li><li><ahref="/learn-wgpu/beginner/tutorial3-pipeline/"class="sidebar-link">The Pipeline</a></li><li><ahref="/learn-wgpu/beginner/tutorial4-buffer/"class="sidebar-link">Buffers and Indices</a></li><li><ahref="/learn-wgpu/beginner/tutorial5-textures/"class="sidebar-link">Textures and bind groups</a></li><li><ahref="/learn-wgpu/beginner/tutorial6-uniforms/"class="sidebar-link">Uniform buffers and a 3d camera</a></li><li><ahref="/learn-wgpu/beginner/tutorial7-instancing/"class="sidebar-link">Instancing</a></li><li><ahref="/learn-wgpu/beginner/tutorial8-depth/"class="sidebar-link">The Depth Buffer</a></li><li><ahref="/learn-wgpu/beginner/tutorial9-models/"class="sidebar-link">Model Loading</a></li></ul></section></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading"><span>Intermediate</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/intermediate/tutorial10-lighting/"class="sidebar-link">Working with Lights</a></li><li><ahref="/learn-wgpu/intermediate/tutorial11-normals/"class="sidebar-link">Normal Mapping</a></li><li><ahref="/learn-wgpu/intermediate/tutorial12-camera/"class="sidebar-link">A Better Camera</a></li></ul></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading open"><span>Showcase</span><spanclass="arrow down"></span></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/showcase/" aria-current="page" class="sidebar-link">Foreword</a></li><li><ahref="/learn-wgpu/showcase/windowless/"class="sidebar-link">Wgpu without a window</a></li><li><ahref="/learn-wgpu/showcase/gifs/"class="sidebar-link">Creating gifs</a></li><li><ahref="/learn-wgpu/showcase/pong/"class="sidebar-link">Pong</a></li><li><ahref="/learn-wgpu/showcase/compute/" aria-current="page" class="active sidebar-link">Compute Example: Tangents and Bitangents</a><ulclass="sidebar-sub-headers"><liclass="sidebar-sub-header"><ahref="/learn-wgpu/showcase/compute/#possible-improvements"class="sidebar-link">Possible Improvements</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/showcase/compute/#results"class="sidebar-link">Results</a></li></ul></li><li><ahref="/learn-wgpu/showcase/alignment/"class="sidebar-link">Memory Layout in WGSL</a></li></ul></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading"><span>News</span><spanclass="arrow right"></span></p><!----></section></li></ul></aside><mainclass="page"><divclass="theme-default-content content__default"><h1id="compute-example-tangents-and-bitangents"><ahref="#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 <ahref="/learn-wgpu/intermediate/tutorial11-normals/">normal mapping tutorial</a>.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token attribute attr-name">#[repr(C)]</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><h2id="results"><ahref="#results"class="header-anchor">#</a> Results</h2><p>The tangents and bitangents are now getting calculated correctly and on the GPU!</p><p><imgsrc="/learn-wgpu/assets/img/results.7918efc1.png"alt="./results.png"></p><divclass="auto-github-link"><ahref="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"><pathfill="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><polygonfill="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><footerclass="page-edit"><!----><divclass="last-updated"><spanclass="prefix">Last Updated: </span><spanclass="time">3/18/2022, 7:17:14 PM</span></div></footer><divclass="page-nav"><pclass="inner"><spanclass="prev">
</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><h2id="results"><ahref="#results"class="header-anchor">#</a> Results</h2><p>The tangents and bitangents are now getting calculated correctly and on the GPU!</p><p><imgsrc="/learn-wgpu/assets/img/results.7918efc1.png"alt="./results.png"></p><divclass="auto-github-link"><ahref="https://github.com/sotrh/learn-wgpu/tree/master/code/showcase/compute/"target="_blank"rel="noopener noreferrer">Check out the code!</a><span><svg xmlns="http://www.w3.org/2000/svg"aria-hidden="true" focusable="false" x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="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><polygonfill="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><spanclass="sr-only">(opens new window)</span></span></div></div><footerclass="page-edit"><!----><divclass="last-updated"><spanclass="prefix">Last Updated: </span><spanclass="time">3/26/2022, 12:15:11 AM</span></div></footer><divclass="page-nav"><pclass="inner"><spanclass="prev">
<divid="app"data-server-rendered="true"><divclass="theme-container"><headerclass="navbar"><divclass="inner"><divclass="sidebar-button"><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"role="img"viewBox="0 0 448 512"class="icon"><pathfill="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><ahref="/learn-wgpu/"class="home-link router-link-active"><!----><spanclass="site-name">Learn Wgpu</span></a><divclass="links"><!----><divclass="search-box"><inputaria-label="Search"autocomplete="off"spellcheck="false"value=""><!----></div></div></div></header><divclass="sidebar-mask"></div><divclass="docs-layout"><asideclass="sidebar"><!----><ulclass="sidebar-links"><li><ahref="/learn-wgpu/"class="sidebar-link">Introduction</a></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading"><span>Beginner</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/beginner/tutorial1-window/"class="sidebar-link">Dependencies and the window</a></li><li><ahref="/learn-wgpu/beginner/tutorial2-surface/"class="sidebar-link">The Surface</a></li><li><ahref="/learn-wgpu/beginner/tutorial3-pipeline/"class="sidebar-link">The Pipeline</a></li><li><ahref="/learn-wgpu/beginner/tutorial4-buffer/"class="sidebar-link">Buffers and Indices</a></li><li><ahref="/learn-wgpu/beginner/tutorial5-textures/"class="sidebar-link">Textures and bind groups</a></li><li><ahref="/learn-wgpu/beginner/tutorial6-uniforms/"class="sidebar-link">Uniform buffers and a 3d camera</a></li><li><ahref="/learn-wgpu/beginner/tutorial7-instancing/"class="sidebar-link">Instancing</a></li><li><ahref="/learn-wgpu/beginner/tutorial8-depth/"class="sidebar-link">The Depth Buffer</a></li><li><ahref="/learn-wgpu/beginner/tutorial9-models/"class="sidebar-link">Model Loading</a></li></ul></section></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading"><span>Intermediate</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/intermediate/tutorial10-lighting/"class="sidebar-link">Working with Lights</a></li><li><ahref="/learn-wgpu/intermediate/tutorial11-normals/"class="sidebar-link">Normal Mapping</a></li><li><ahref="/learn-wgpu/intermediate/tutorial12-camera/"class="sidebar-link">A Better Camera</a></li><li><ahref="/learn-wgpu/intermediate/tutorial13-threading/"class="sidebar-link">Multi-threading with Wgpu and Rayon</a></li></ul></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading open"><span>Showcase</span><spanclass="arrow down"></span></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/showcase/"class="active sidebar-link">Foreword</a></li><li><ahref="/learn-wgpu/showcase/windowless/"class="sidebar-link">Wgpu without a window</a></li><li><ahref="/learn-wgpu/showcase/gifs/"class="sidebar-link">Creating gifs</a></li><li><ahref="/learn-wgpu/showcase/pong/"class="sidebar-link">Pong</a></li><li><ahref="/learn-wgpu/showcase/compute/"class="sidebar-link">Compute Example: Tangents and Bitangents</a></li><li><ahref="/learn-wgpu/showcase/alignment/"class="sidebar-link">Memory Layout in WGSL</a></li></ul></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading"><span>News</span><spanclass="arrow right"></span></p><!----></section></li></ul></aside><mainclass="page"><divclass="theme-default-content content__default"><h1id="foreword"><ahref="#foreword"class="header-anchor">#</a> Foreword</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><footerclass="page-edit"><!----><divclass="last-updated"><spanclass="prefix">Last Updated: </span><spanclass="time">3/18/2022, 7:17:14 PM</span></div></footer><divclass="page-nav"><pclass="inner"><spanclass="prev">
<divid="app"data-server-rendered="true"><divclass="theme-container"><headerclass="navbar"><divclass="inner"><divclass="sidebar-button"><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"role="img"viewBox="0 0 448 512"class="icon"><pathfill="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><ahref="/learn-wgpu/"class="home-link router-link-active"><!----><spanclass="site-name">Learn Wgpu</span></a><divclass="links"><!----><divclass="search-box"><inputaria-label="Search"autocomplete="off"spellcheck="false"value=""><!----></div></div></div></header><divclass="sidebar-mask"></div><divclass="docs-layout"><asideclass="sidebar"><!----><ulclass="sidebar-links"><li><ahref="/learn-wgpu/"aria-current="page"class="sidebar-link">Introduction</a></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading"><span>Beginner</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/beginner/tutorial1-window/"class="sidebar-link">Dependencies and the window</a></li><li><ahref="/learn-wgpu/beginner/tutorial2-surface/"class="sidebar-link">The Surface</a></li><li><ahref="/learn-wgpu/beginner/tutorial3-pipeline/"class="sidebar-link">The Pipeline</a></li><li><ahref="/learn-wgpu/beginner/tutorial4-buffer/"class="sidebar-link">Buffers and Indices</a></li><li><ahref="/learn-wgpu/beginner/tutorial5-textures/"class="sidebar-link">Textures and bind groups</a></li><li><ahref="/learn-wgpu/beginner/tutorial6-uniforms/"class="sidebar-link">Uniform buffers and a 3d camera</a></li><li><ahref="/learn-wgpu/beginner/tutorial7-instancing/"class="sidebar-link">Instancing</a></li><li><ahref="/learn-wgpu/beginner/tutorial8-depth/"class="sidebar-link">The Depth Buffer</a></li><li><ahref="/learn-wgpu/beginner/tutorial9-models/"class="sidebar-link">Model Loading</a></li></ul></section></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading"><span>Intermediate</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/intermediate/tutorial10-lighting/"class="sidebar-link">Working with Lights</a></li><li><ahref="/learn-wgpu/intermediate/tutorial11-normals/"class="sidebar-link">Normal Mapping</a></li><li><ahref="/learn-wgpu/intermediate/tutorial12-camera/"class="sidebar-link">A Better Camera</a></li></ul></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading open"><span>Showcase</span><spanclass="arrow down"></span></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/showcase/" aria-current="page" class="active sidebar-link">Foreword</a></li><li><ahref="/learn-wgpu/showcase/windowless/"class="sidebar-link">Wgpu without a window</a></li><li><ahref="/learn-wgpu/showcase/gifs/"class="sidebar-link">Creating gifs</a></li><li><ahref="/learn-wgpu/showcase/pong/"class="sidebar-link">Pong</a></li><li><ahref="/learn-wgpu/showcase/compute/"class="sidebar-link">Compute Example: Tangents and Bitangents</a></li><li><ahref="/learn-wgpu/showcase/alignment/"class="sidebar-link">Memory Layout in WGSL</a></li></ul></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading"><span>News</span><spanclass="arrow right"></span></p><!----></section></li></ul></aside><mainclass="page"><divclass="theme-default-content content__default"><h1id="foreword"><ahref="#foreword"class="header-anchor">#</a> Foreword</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><footerclass="page-edit"><!----><divclass="last-updated"><spanclass="prefix">Last Updated: </span><spanclass="time">3/26/2022, 12:15:11 AM</span></div></footer><divclass="page-nav"><pclass="inner"><spanclass="prev">