learn-wgpu/beginner/tutorial7-instancing/index.html

187 lines
48 KiB
HTML

<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Instancing | Learn Wgpu</title>
<meta name="description" content="">
<meta name="generator" content="VuePress 1.4.0">
<meta property="article:modified_time" content="2022-02-26T18:57:17.000Z"><meta property="og:site_name" content="Learn Wgpu"><meta property="og:title" content="Instancing"><meta property="og:type" content="website"><meta property="og:url" content="/beginner/tutorial7-instancing/"><meta name="twitter:title" content="Instancing"><meta name="twitter:url" content="/beginner/tutorial7-instancing/"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:label1" content="Written by"><meta name="twitter:data2" content="Benjamin Hansen"><meta name="twitter:creator" content="https://twitter.com/sotrh760">
<link rel="preload" href="/learn-wgpu/assets/css/0.styles.4fb695a1.css" as="style"><link rel="preload" href="/learn-wgpu/assets/js/app.15f3d3e1.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/4.c4741047.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/19.623df875.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/25.5a7a1f31.js" as="script"><link rel="prefetch" href="/learn-wgpu/assets/js/1.e1054b07.js"><link rel="prefetch" href="/learn-wgpu/assets/js/10.9b2446b9.js"><link rel="prefetch" href="/learn-wgpu/assets/js/11.918ac8f8.js"><link rel="prefetch" href="/learn-wgpu/assets/js/12.7e1fa0ed.js"><link rel="prefetch" href="/learn-wgpu/assets/js/13.c591e8de.js"><link rel="prefetch" href="/learn-wgpu/assets/js/14.87ade59d.js"><link rel="prefetch" href="/learn-wgpu/assets/js/15.4bada0b9.js"><link rel="prefetch" href="/learn-wgpu/assets/js/16.8b83d0ae.js"><link rel="prefetch" href="/learn-wgpu/assets/js/17.57f53ce3.js"><link rel="prefetch" href="/learn-wgpu/assets/js/18.2398c480.js"><link rel="prefetch" href="/learn-wgpu/assets/js/2.f626117a.js"><link rel="prefetch" href="/learn-wgpu/assets/js/20.140d2648.js"><link rel="prefetch" href="/learn-wgpu/assets/js/21.a801933f.js"><link rel="prefetch" href="/learn-wgpu/assets/js/22.d1c5beb9.js"><link rel="prefetch" href="/learn-wgpu/assets/js/23.ffb83767.js"><link rel="prefetch" href="/learn-wgpu/assets/js/24.6a0d1e12.js"><link rel="prefetch" href="/learn-wgpu/assets/js/26.a5048f3d.js"><link rel="prefetch" href="/learn-wgpu/assets/js/27.16add643.js"><link rel="prefetch" href="/learn-wgpu/assets/js/28.f4a55ac6.js"><link rel="prefetch" href="/learn-wgpu/assets/js/29.c45319b3.js"><link rel="prefetch" href="/learn-wgpu/assets/js/30.e1eaf249.js"><link rel="prefetch" href="/learn-wgpu/assets/js/31.ab88ef7b.js"><link rel="prefetch" href="/learn-wgpu/assets/js/32.21765d0f.js"><link rel="prefetch" href="/learn-wgpu/assets/js/33.4daba1cc.js"><link rel="prefetch" href="/learn-wgpu/assets/js/34.d664ca20.js"><link rel="prefetch" href="/learn-wgpu/assets/js/35.3955dae3.js"><link rel="prefetch" href="/learn-wgpu/assets/js/36.c0c5124a.js"><link rel="prefetch" href="/learn-wgpu/assets/js/5.a5d0b8f5.js"><link rel="prefetch" href="/learn-wgpu/assets/js/6.a264024c.js"><link rel="prefetch" href="/learn-wgpu/assets/js/7.88628e61.js"><link rel="prefetch" href="/learn-wgpu/assets/js/8.f80dcf4e.js"><link rel="prefetch" href="/learn-wgpu/assets/js/9.62cbd082.js">
<link rel="stylesheet" href="/learn-wgpu/assets/css/0.styles.4fb695a1.css">
</head>
<body>
<div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="inner"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/learn-wgpu/" class="home-link router-link-active"><!----> <span class="site-name">Learn Wgpu</span></a> <div class="links"><!----> <div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div></div></div></header> <div class="sidebar-mask"></div> <div class="docs-layout"><aside class="sidebar"><!----> <ul class="sidebar-links"><li><a href="/learn-wgpu/" class="sidebar-link">Introduction</a></li><li><section class="sidebar-group depth-0"><p class="sidebar-heading open"><span>Beginner</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/learn-wgpu/beginner/tutorial1-window/" class="sidebar-link">Dependencies and the window</a></li><li><a href="/learn-wgpu/beginner/tutorial2-surface/" class="sidebar-link">The Surface</a></li><li><a href="/learn-wgpu/beginner/tutorial3-pipeline/" class="sidebar-link">The Pipeline</a></li><li><a href="/learn-wgpu/beginner/tutorial4-buffer/" class="sidebar-link">Buffers and Indices</a></li><li><a href="/learn-wgpu/beginner/tutorial5-textures/" class="sidebar-link">Textures and bind groups</a></li><li><a href="/learn-wgpu/beginner/tutorial6-uniforms/" class="sidebar-link">Uniform buffers and a 3d camera</a></li><li><a href="/learn-wgpu/beginner/tutorial7-instancing/" class="active sidebar-link">Instancing</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/learn-wgpu/beginner/tutorial7-instancing/#the-instance-buffer" class="sidebar-link">The Instance Buffer</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/beginner/tutorial7-instancing/#challenge" class="sidebar-link">Challenge</a></li></ul></li><li><a href="/learn-wgpu/beginner/tutorial8-depth/" class="sidebar-link">The Depth Buffer</a></li><li><a href="/learn-wgpu/beginner/tutorial9-models/" class="sidebar-link">Model Loading</a></li></ul></section></li><li><section class="sidebar-group depth-0"><p class="sidebar-heading"><span>Intermediate</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/learn-wgpu/intermediate/tutorial10-lighting/" class="sidebar-link">Working with Lights</a></li><li><a href="/learn-wgpu/intermediate/tutorial11-normals/" class="sidebar-link">Normal Mapping</a></li><li><a href="/learn-wgpu/intermediate/tutorial12-camera/" class="sidebar-link">A Better Camera</a></li><li><a href="/learn-wgpu/intermediate/tutorial13-threading/" class="sidebar-link">Multi-threading with Wgpu and Rayon</a></li></ul></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>Showcase</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>News</span> <span class="arrow right"></span></p> <!----></section></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><h1 id="instancing"><a href="#instancing" class="header-anchor">#</a> Instancing</h1> <p>Our scene right now is very simple: we have one object centered at (0,0,0). What if we wanted more objects? This is where instancing comes in.</p> <p>Instancing allows us to draw the same object multiple times with different properties (position, orientation, size, color, etc.). There are multiple ways of doing instancing. One way would be to modify the uniform buffer to include these properties and then update it before we draw each instance of our object.</p> <p>We don't want to use this method for performance reasons. Updating the uniform buffer for each instance would require multiple buffer copies each frame. On top of that, our method to update the uniform buffer currently requires use to create a new buffer to store the updated data. That's a lot of time wasted between draw calls.</p> <p>If we look at the parameters for the <code>draw_indexed</code> function <a href="https://docs.rs/wgpu/0.12.0/wgpu/struct.RenderPass.html#method.draw_indexed" target="_blank" rel="noopener noreferrer">in the wgpu 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"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a>, we can see a solution to our problem.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">draw_indexed</span><span class="token punctuation">(</span>
<span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">,</span>
indices<span class="token punctuation">:</span> <span class="token class-name">Range</span><span class="token operator">&lt;</span><span class="token keyword">u32</span><span class="token operator">&gt;</span><span class="token punctuation">,</span>
base_vertex<span class="token punctuation">:</span> <span class="token keyword">i32</span><span class="token punctuation">,</span>
instances<span class="token punctuation">:</span> <span class="token class-name">Range</span><span class="token operator">&lt;</span><span class="token keyword">u32</span><span class="token operator">&gt;</span> <span class="token comment">// &lt;-- This right here</span>
<span class="token punctuation">)</span>
</code></pre></div><p>The <code>instances</code> parameter takes a <code>Range&lt;u32&gt;</code>. This parameter tells the GPU how many copies, or instances, of our model we want to draw. Currently we are specifying <code>0..1</code>, which instructs the GPU to draw our model once, and then stop. If we used <code>0..5</code>, our code would draw 5 instances.</p> <p>The fact that <code>instances</code> is a <code>Range&lt;u32&gt;</code> may seem weird as using <code>1..2</code> for instances would still draw 1 instance of our object. Seems like it would be simpler to just use a <code>u32</code> right? The reason it's a range is because sometimes we don't want to draw <strong>all</strong> of our objects. Sometimes we want to draw a selection of them, because others are not in frame, or we are debugging and want to look at a particular set of instances.</p> <p>Ok, now we know how to draw multiple instances of an object, how do we tell wgpu what particular instance to draw? We are going to use something known as an instance buffer.</p> <h2 id="the-instance-buffer"><a href="#the-instance-buffer" class="header-anchor">#</a> The Instance Buffer</h2> <p>We'll create an instance buffer in a similar way to how we create a uniform buffer. First we'll create a struct called <code>Instance</code>.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token comment">// main.rs</span>
<span class="token comment">// ...</span>
<span class="token comment">// NEW!</span>
<span class="token keyword">struct</span> <span class="token type-definition class-name">Instance</span> <span class="token punctuation">{</span>
position<span class="token punctuation">:</span> <span class="token namespace">cgmath<span class="token punctuation">::</span></span><span class="token class-name">Vector3</span><span class="token operator">&lt;</span><span class="token keyword">f32</span><span class="token operator">&gt;</span><span class="token punctuation">,</span>
rotation<span class="token punctuation">:</span> <span class="token namespace">cgmath<span class="token punctuation">::</span></span><span class="token class-name">Quaternion</span><span class="token operator">&lt;</span><span class="token keyword">f32</span><span class="token operator">&gt;</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
</code></pre></div><div class="note"><p>A <code>Quaternion</code> is a mathematical structure often used to represent rotation. The math behind them is beyond me (it involves imaginary numbers and 4D space) so I won't be covering them here. If you really want to dive into them <a href="https://mathworld.wolfram.com/Quaternion.html" target="_blank" rel="noopener noreferrer">here's a Wolfram Alpha article<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a>.</p></div> <p>Using these values directly in the shader would be a pain as quaternions don't have a WGSL analog. I don't feel like writing the math in the shader, so we'll convert the <code>Instance</code> data into a matrix and store it into a struct called <code>InstanceRaw</code>.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token comment">// NEW!</span>
<span class="token attribute attr-name">#[repr(C)]</span>
<span class="token attribute attr-name">#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]</span>
<span class="token keyword">struct</span> <span class="token type-definition class-name">InstanceRaw</span> <span class="token punctuation">{</span>
model<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">[</span><span class="token keyword">f32</span><span class="token punctuation">;</span> <span class="token number">4</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token number">4</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
</code></pre></div><p>This is the data that will go into the <code>wgpu::Buffer</code>. We keep these separate so that we can update the <code>Instance</code> as much as we want without needing to mess with matrices. We only need to update the raw data before we draw.</p> <p>Let's create a method on <code>Instance</code> to convert to <code>InstanceRaw</code>.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token comment">// NEW!</span>
<span class="token keyword">impl</span> <span class="token class-name">Instance</span> <span class="token punctuation">{</span>
<span class="token keyword">fn</span> <span class="token function-definition function">to_raw</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">InstanceRaw</span> <span class="token punctuation">{</span>
<span class="token class-name">InstanceRaw</span> <span class="token punctuation">{</span>
model<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token namespace">cgmath<span class="token punctuation">::</span></span><span class="token class-name">Matrix4</span><span class="token punctuation">::</span><span class="token function">from_translation</span><span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">.</span>position<span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token namespace">cgmath<span class="token punctuation">::</span></span><span class="token class-name">Matrix4</span><span class="token punctuation">::</span><span class="token function">from</span><span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">.</span>rotation<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">into</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>Now we need to add 2 fields to <code>State</code>: <code>instances</code>, and <code>instance_buffer</code>.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">struct</span> <span class="token type-definition class-name">State</span> <span class="token punctuation">{</span>
instances<span class="token punctuation">:</span> <span class="token class-name">Vec</span><span class="token operator">&lt;</span><span class="token class-name">Instance</span><span class="token operator">&gt;</span><span class="token punctuation">,</span>
instance_buffer<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Buffer</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
</code></pre></div><p>The <code>cgmath</code> crate uses traits to provide common mathematical methods across its structs such as <code>Vector3</code>, and these traits must be imported before these methods can be called. For convenience, the <code>prelude</code> module within the crate provides the most common of these extension crates when it is imported.</p> <p>To import this prelude module, put this line near the top of <code>main.rs</code>.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">use</span> <span class="token namespace">cgmath<span class="token punctuation">::</span>prelude<span class="token punctuation">::</span></span><span class="token operator">*</span><span class="token punctuation">;</span>
</code></pre></div><p>We'll create the instances in <code>new()</code>. We'll use some constants to simplify things. We'll display our instances in 10 rows of 10, and they'll be spaced evenly apart.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">const</span> <span class="token constant">NUM_INSTANCES_PER_ROW</span><span class="token punctuation">:</span> <span class="token keyword">u32</span> <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token constant">INSTANCE_DISPLACEMENT</span><span class="token punctuation">:</span> <span class="token namespace">cgmath<span class="token punctuation">::</span></span><span class="token class-name">Vector3</span><span class="token operator">&lt;</span><span class="token keyword">f32</span><span class="token operator">&gt;</span> <span class="token operator">=</span> <span class="token namespace">cgmath<span class="token punctuation">::</span></span><span class="token class-name">Vector3</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token constant">NUM_INSTANCES_PER_ROW</span> <span class="token keyword">as</span> <span class="token keyword">f32</span> <span class="token operator">*</span> <span class="token number">0.5</span><span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">,</span> <span class="token constant">NUM_INSTANCES_PER_ROW</span> <span class="token keyword">as</span> <span class="token keyword">f32</span> <span class="token operator">*</span> <span class="token number">0.5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>Now we can create the actual instances.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">impl</span> <span class="token class-name">State</span> <span class="token punctuation">{</span>
<span class="token keyword">async</span> <span class="token keyword">fn</span> <span class="token function-definition function">new</span><span class="token punctuation">(</span>window<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token class-name">Window</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">Self</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
<span class="token keyword">let</span> instances <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">..</span><span class="token constant">NUM_INSTANCES_PER_ROW</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">flat_map</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token closure-punctuation punctuation">|</span>z<span class="token closure-punctuation punctuation">|</span></span> <span class="token punctuation">{</span>
<span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">..</span><span class="token constant">NUM_INSTANCES_PER_ROW</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token keyword">move</span> <span class="token closure-params"><span class="token closure-punctuation punctuation">|</span>x<span class="token closure-punctuation punctuation">|</span></span> <span class="token punctuation">{</span>
<span class="token keyword">let</span> position <span class="token operator">=</span> <span class="token namespace">cgmath<span class="token punctuation">::</span></span><span class="token class-name">Vector3</span> <span class="token punctuation">{</span> x<span class="token punctuation">:</span> x <span class="token keyword">as</span> <span class="token keyword">f32</span><span class="token punctuation">,</span> y<span class="token punctuation">:</span> <span class="token number">0.0</span><span class="token punctuation">,</span> z<span class="token punctuation">:</span> z <span class="token keyword">as</span> <span class="token keyword">f32</span> <span class="token punctuation">}</span> <span class="token operator">-</span> <span class="token constant">INSTANCE_DISPLACEMENT</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> rotation <span class="token operator">=</span> <span class="token keyword">if</span> position<span class="token punctuation">.</span><span class="token function">is_zero</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// this is needed so an object at (0, 0, 0) won't get scaled to zero</span>
<span class="token comment">// as Quaternions can effect scale if they're not created correctly</span>
<span class="token namespace">cgmath<span class="token punctuation">::</span></span><span class="token class-name">Quaternion</span><span class="token punctuation">::</span><span class="token function">from_axis_angle</span><span class="token punctuation">(</span><span class="token namespace">cgmath<span class="token punctuation">::</span></span><span class="token class-name">Vector3</span><span class="token punctuation">::</span><span class="token function">unit_z</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token namespace">cgmath<span class="token punctuation">::</span></span><span class="token class-name">Deg</span><span class="token punctuation">(</span><span class="token number">0.0</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
<span class="token namespace">cgmath<span class="token punctuation">::</span></span><span class="token class-name">Quaternion</span><span class="token punctuation">::</span><span class="token function">from_axis_angle</span><span class="token punctuation">(</span>position<span class="token punctuation">.</span><span class="token function">normalize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token namespace">cgmath<span class="token punctuation">::</span></span><span class="token class-name">Deg</span><span class="token punctuation">(</span><span class="token number">45.0</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token class-name">Instance</span> <span class="token punctuation">{</span>
position<span class="token punctuation">,</span> rotation<span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">collect</span><span class="token punctuation">::</span><span class="token operator">&lt;</span><span class="token class-name">Vec</span><span class="token operator">&lt;</span>_<span class="token operator">&gt;&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// ...</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>Now that we have our data, we can create the actual <code>instance_buffer</code>.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">let</span> instance_data <span class="token operator">=</span> instances<span class="token punctuation">.</span><span class="token function">iter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token class-name">Instance</span><span class="token punctuation">::</span>to_raw<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">collect</span><span class="token punctuation">::</span><span class="token operator">&lt;</span><span class="token class-name">Vec</span><span class="token operator">&lt;</span>_<span class="token operator">&gt;&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> instance_buffer <span class="token operator">=</span> device<span class="token punctuation">.</span><span class="token function">create_buffer_init</span><span class="token punctuation">(</span>
<span class="token operator">&amp;</span><span class="token namespace">wgpu<span class="token punctuation">::</span>util<span class="token punctuation">::</span></span><span class="token class-name">BufferInitDescriptor</span> <span class="token punctuation">{</span>
label<span class="token punctuation">:</span> <span class="token class-name">Some</span><span class="token punctuation">(</span><span class="token string">&quot;Instance Buffer&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
contents<span class="token punctuation">:</span> <span class="token namespace">bytemuck<span class="token punctuation">::</span></span><span class="token function">cast_slice</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>instance_data<span class="token punctuation">)</span><span class="token punctuation">,</span>
usage<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BufferUsages</span><span class="token punctuation">::</span><span class="token constant">VERTEX</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>We're going to need to create a new <code>VertexBufferLayout</code> for <code>InstanceRaw</code>.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">impl</span> <span class="token class-name">InstanceRaw</span> <span class="token punctuation">{</span>
<span class="token keyword">fn</span> <span class="token function-definition function">desc</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">'a</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">VertexBufferLayout</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">'a</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span></span>mem<span class="token punctuation">;</span>
<span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">VertexBufferLayout</span> <span class="token punctuation">{</span>
array_stride<span class="token punctuation">:</span> <span class="token namespace">mem<span class="token punctuation">::</span></span><span class="token function">size_of</span><span class="token punctuation">::</span><span class="token operator">&lt;</span><span class="token class-name">InstanceRaw</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">as</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BufferAddress</span><span class="token punctuation">,</span>
<span class="token comment">// We need to switch from using a step mode of Vertex to Instance</span>
<span class="token comment">// This means that our shaders will only change to use the next</span>
<span class="token comment">// instance when the shader starts processing a new instance</span>
step_mode<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">VertexStepMode</span><span class="token punctuation">::</span><span class="token class-name">Instance</span><span class="token punctuation">,</span>
attributes<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token punctuation">[</span>
<span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">VertexAttribute</span> <span class="token punctuation">{</span>
offset<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
<span class="token comment">// While our vertex shader only uses locations 0, and 1 now, in later tutorials we'll</span>
<span class="token comment">// be using 2, 3, and 4, for Vertex. We'll start at slot 5 not conflict with them later</span>
shader_location<span class="token punctuation">:</span> <span class="token number">5</span><span class="token punctuation">,</span>
format<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">VertexFormat</span><span class="token punctuation">::</span><span class="token class-name">Float32x4</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token comment">// A mat4 takes up 4 vertex slots as it is technically 4 vec4s. We need to define a slot</span>
<span class="token comment">// for each vec4. We'll have to reassemble the mat4 in</span>
<span class="token comment">// the shader.</span>
<span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">VertexAttribute</span> <span class="token punctuation">{</span>
offset<span class="token punctuation">:</span> <span class="token namespace">mem<span class="token punctuation">::</span></span><span class="token function">size_of</span><span class="token punctuation">::</span><span class="token operator">&lt;</span><span class="token punctuation">[</span><span class="token keyword">f32</span><span class="token punctuation">;</span> <span class="token number">4</span><span class="token punctuation">]</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">as</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BufferAddress</span><span class="token punctuation">,</span>
shader_location<span class="token punctuation">:</span> <span class="token number">6</span><span class="token punctuation">,</span>
format<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">VertexFormat</span><span class="token punctuation">::</span><span class="token class-name">Float32x4</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">VertexAttribute</span> <span class="token punctuation">{</span>
offset<span class="token punctuation">:</span> <span class="token namespace">mem<span class="token punctuation">::</span></span><span class="token function">size_of</span><span class="token punctuation">::</span><span class="token operator">&lt;</span><span class="token punctuation">[</span><span class="token keyword">f32</span><span class="token punctuation">;</span> <span class="token number">8</span><span class="token punctuation">]</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">as</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BufferAddress</span><span class="token punctuation">,</span>
shader_location<span class="token punctuation">:</span> <span class="token number">7</span><span class="token punctuation">,</span>
format<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">VertexFormat</span><span class="token punctuation">::</span><span class="token class-name">Float32x4</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">VertexAttribute</span> <span class="token punctuation">{</span>
offset<span class="token punctuation">:</span> <span class="token namespace">mem<span class="token punctuation">::</span></span><span class="token function">size_of</span><span class="token punctuation">::</span><span class="token operator">&lt;</span><span class="token punctuation">[</span><span class="token keyword">f32</span><span class="token punctuation">;</span> <span class="token number">12</span><span class="token punctuation">]</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">as</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BufferAddress</span><span class="token punctuation">,</span>
shader_location<span class="token punctuation">:</span> <span class="token number">8</span><span class="token punctuation">,</span>
format<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">VertexFormat</span><span class="token punctuation">::</span><span class="token class-name">Float32x4</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>We need to add this descriptor to the render pipeline so that we can use it when we render.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">let</span> render_pipeline <span class="token operator">=</span> device<span class="token punctuation">.</span><span class="token function">create_render_pipeline</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">RenderPipelineDescriptor</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
vertex<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">VertexState</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
<span class="token comment">// UPDATED!</span>
buffers<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token punctuation">[</span><span class="token class-name">Vertex</span><span class="token punctuation">::</span><span class="token function">desc</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token class-name">InstanceRaw</span><span class="token punctuation">::</span><span class="token function">desc</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token comment">// ...</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>Don't forget to return our new variables!</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">Self</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
<span class="token comment">// NEW!</span>
instances<span class="token punctuation">,</span>
instance_buffer<span class="token punctuation">,</span>
<span class="token punctuation">}</span>
</code></pre></div><p>The last change we need to make is in the <code>render()</code> method. We need to bind our <code>instance_buffer</code> and we need to change the range we're using in <code>draw_indexed()</code> to include the number of instances.</p> <div class="language-rust extra-class"><pre class="language-rust"><code>render_pass<span class="token punctuation">.</span><span class="token function">set_pipeline</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">.</span>render_pipeline<span class="token punctuation">)</span><span class="token punctuation">;</span>
render_pass<span class="token punctuation">.</span><span class="token function">set_bind_group</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">.</span>diffuse_bind_group<span class="token punctuation">,</span> <span class="token operator">&amp;</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
render_pass<span class="token punctuation">.</span><span class="token function">set_bind_group</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">.</span>camera_bind_group<span class="token punctuation">,</span> <span class="token operator">&amp;</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
render_pass<span class="token punctuation">.</span><span class="token function">set_vertex_buffer</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token keyword">self</span><span class="token punctuation">.</span>vertex_buffer<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token punctuation">..</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// NEW!</span>
render_pass<span class="token punctuation">.</span><span class="token function">set_vertex_buffer</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token keyword">self</span><span class="token punctuation">.</span>instance_buffer<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token punctuation">..</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
render_pass<span class="token punctuation">.</span><span class="token function">set_index_buffer</span><span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">.</span>index_buffer<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token punctuation">..</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">IndexFormat</span><span class="token punctuation">::</span><span class="token class-name">Uint16</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// UPDATED!</span>
render_pass<span class="token punctuation">.</span><span class="token function">draw_indexed</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">..</span><span class="token keyword">self</span><span class="token punctuation">.</span>num_indices<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">..</span><span class="token keyword">self</span><span class="token punctuation">.</span>instances<span class="token punctuation">.</span><span class="token function">len</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">as</span> _<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><div class="warning"><p>Make sure if you add new instances to the <code>Vec</code>, that you recreate the <code>instance_buffer</code> and as well as <code>camera_bind_group</code>, otherwise your new instances won't show up correctly.</p></div> <p>We need to reference the parts of our new matrix in <code>shader.wgsl</code> so that we can use it for our instances. Add the following to the top of <code>shader.wgsl</code>.</p> <div class="language-wgsl extra-class"><pre class="language-text"><code>struct InstanceInput {
[[location(5)]] model_matrix_0: vec4&lt;f32&gt;;
[[location(6)]] model_matrix_1: vec4&lt;f32&gt;;
[[location(7)]] model_matrix_2: vec4&lt;f32&gt;;
[[location(8)]] model_matrix_3: vec4&lt;f32&gt;;
};
</code></pre></div><p>We need to reassemble the matrix before we can use it.</p> <div class="language-wgsl extra-class"><pre class="language-text"><code>[[stage(vertex)]]
fn vs_main(
model: VertexInput,
instance: InstanceInput,
) -&gt; VertexOutput {
let model_matrix = mat4x4&lt;f32&gt;(
instance.model_matrix_0,
instance.model_matrix_1,
instance.model_matrix_2,
instance.model_matrix_3,
);
// Continued...
}
</code></pre></div><p>We'll apply the <code>model_matrix</code> before we apply <code>camera_uniform.view_proj</code>. We do this because the <code>camera_uniform.view_proj</code> changes the coordinate system from <code>world space</code> to <code>camera space</code>. Our <code>model_matrix</code> is a <code>world space</code> transformation, so we don't want to be in <code>camera space</code> when using it.</p> <div class="language-wgsl extra-class"><pre class="language-text"><code>[[stage(vertex)]]
fn vs_main(
model: VertexInput,
instance: InstanceInput,
) -&gt; VertexOutput {
// ...
var out: VertexOutput;
out.tex_coords = model.tex_coords;
out.clip_position = camera.view_proj * model_matrix * vec4&lt;f32&gt;(model.position, 1.0);
return out;
}
</code></pre></div><p>With all that done, we should have a forest of trees!</p> <p><img src="/learn-wgpu/assets/img/forest.5c5cf3ad.png" alt="./forest.png"></p> <h2 id="challenge"><a href="#challenge" class="header-anchor">#</a> Challenge</h2> <p>Modify the position and/or rotation of the instances every frame.</p> <div class="auto-github-link"><a href="https://github.com/sotrh/learn-wgpu/tree/master/code/beginner/tutorial7-instancing/" target="_blank" rel="noopener noreferrer">Check out the code!</a> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></div></div> <footer class="page-edit"><!----> <div class="last-updated"><span class="prefix">Last Updated: </span> <span class="time">2/26/2022, 6:57:17 PM</span></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
<a href="/learn-wgpu/beginner/tutorial6-uniforms/" class="prev">
Uniform buffers and a 3d camera
</a></span> <span class="next"><a href="/learn-wgpu/beginner/tutorial8-depth/">
The Depth Buffer
</a>
</span></p></div> </main></div></div><div class="global-ui"><!----></div></div>
<script src="/learn-wgpu/assets/js/app.15f3d3e1.js" defer></script><script src="/learn-wgpu/assets/js/4.c4741047.js" defer></script><script src="/learn-wgpu/assets/js/19.623df875.js" defer></script><script src="/learn-wgpu/assets/js/25.5a7a1f31.js" defer></script>
</body>
</html>