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

419 lines
110 KiB
HTML

<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Textures and bind groups | Learn Wgpu</title>
<meta name="generator" content="VuePress 1.9.10">
<meta name="description" content="">
<link rel="preload" href="/learn-wgpu/assets/css/0.styles.81cb5453.css" as="style"><link rel="preload" href="/learn-wgpu/assets/js/app.d7475ed3.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/2.1b0ff365.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/1.f95c152b.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/28.be489186.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/33.945dce62.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/37.5ecf7ce2.js" as="script"><link rel="prefetch" href="/learn-wgpu/assets/js/10.36ef5e8a.js"><link rel="prefetch" href="/learn-wgpu/assets/js/11.3010e736.js"><link rel="prefetch" href="/learn-wgpu/assets/js/12.19a759b4.js"><link rel="prefetch" href="/learn-wgpu/assets/js/13.d7132c58.js"><link rel="prefetch" href="/learn-wgpu/assets/js/14.f6c42706.js"><link rel="prefetch" href="/learn-wgpu/assets/js/15.f6153e55.js"><link rel="prefetch" href="/learn-wgpu/assets/js/16.a26961f5.js"><link rel="prefetch" href="/learn-wgpu/assets/js/17.57e285e4.js"><link rel="prefetch" href="/learn-wgpu/assets/js/18.8d6104d8.js"><link rel="prefetch" href="/learn-wgpu/assets/js/19.518847c0.js"><link rel="prefetch" href="/learn-wgpu/assets/js/20.06cc413d.js"><link rel="prefetch" href="/learn-wgpu/assets/js/21.f4f92d7d.js"><link rel="prefetch" href="/learn-wgpu/assets/js/22.b5f76915.js"><link rel="prefetch" href="/learn-wgpu/assets/js/23.ce651487.js"><link rel="prefetch" href="/learn-wgpu/assets/js/24.7afa389b.js"><link rel="prefetch" href="/learn-wgpu/assets/js/25.36df8817.js"><link rel="prefetch" href="/learn-wgpu/assets/js/26.173af306.js"><link rel="prefetch" href="/learn-wgpu/assets/js/27.d3569321.js"><link rel="prefetch" href="/learn-wgpu/assets/js/29.399c33dc.js"><link rel="prefetch" href="/learn-wgpu/assets/js/3.5ec857bc.js"><link rel="prefetch" href="/learn-wgpu/assets/js/30.12d50dcb.js"><link rel="prefetch" href="/learn-wgpu/assets/js/31.550259b2.js"><link rel="prefetch" href="/learn-wgpu/assets/js/32.e6627282.js"><link rel="prefetch" href="/learn-wgpu/assets/js/34.6d46e05a.js"><link rel="prefetch" href="/learn-wgpu/assets/js/35.dd9bb63f.js"><link rel="prefetch" href="/learn-wgpu/assets/js/36.aff12c07.js"><link rel="prefetch" href="/learn-wgpu/assets/js/38.b0253733.js"><link rel="prefetch" href="/learn-wgpu/assets/js/39.73123b03.js"><link rel="prefetch" href="/learn-wgpu/assets/js/4.ff267fdb.js"><link rel="prefetch" href="/learn-wgpu/assets/js/40.30864a0f.js"><link rel="prefetch" href="/learn-wgpu/assets/js/41.2442c18a.js"><link rel="prefetch" href="/learn-wgpu/assets/js/42.6f76d27e.js"><link rel="prefetch" href="/learn-wgpu/assets/js/43.ddac8e2c.js"><link rel="prefetch" href="/learn-wgpu/assets/js/44.ef88db2d.js"><link rel="prefetch" href="/learn-wgpu/assets/js/45.81bcfe17.js"><link rel="prefetch" href="/learn-wgpu/assets/js/46.fbe2131f.js"><link rel="prefetch" href="/learn-wgpu/assets/js/47.22e16c22.js"><link rel="prefetch" href="/learn-wgpu/assets/js/48.7d70df25.js"><link rel="prefetch" href="/learn-wgpu/assets/js/49.ad5a99aa.js"><link rel="prefetch" href="/learn-wgpu/assets/js/5.250d79d3.js"><link rel="prefetch" href="/learn-wgpu/assets/js/50.05fd19ce.js"><link rel="prefetch" href="/learn-wgpu/assets/js/51.47410096.js"><link rel="prefetch" href="/learn-wgpu/assets/js/52.09f16d08.js"><link rel="prefetch" href="/learn-wgpu/assets/js/53.8c976652.js"><link rel="prefetch" href="/learn-wgpu/assets/js/54.daee63ce.js"><link rel="prefetch" href="/learn-wgpu/assets/js/55.2dadff38.js"><link rel="prefetch" href="/learn-wgpu/assets/js/56.e9c45fb7.js"><link rel="prefetch" href="/learn-wgpu/assets/js/57.9cdfcb79.js"><link rel="prefetch" href="/learn-wgpu/assets/js/58.35b75a7b.js"><link rel="prefetch" href="/learn-wgpu/assets/js/59.302e302d.js"><link rel="prefetch" href="/learn-wgpu/assets/js/60.bca5b731.js"><link rel="prefetch" href="/learn-wgpu/assets/js/61.f10516d3.js"><link rel="prefetch" href="/learn-wgpu/assets/js/62.fc721fd9.js"><link rel="prefetch" href="/learn-wgpu/assets/js/63.68526f40.js"><link rel="prefetch" href="/learn-wgpu/assets/js/64.5fd53e01.js"><link rel="prefetch" href="/learn-wgpu/assets/js/65.362df98e.js"><link rel="prefetch" href="/learn-wgpu/assets/js/66.19a033d1.js"><link rel="prefetch" href="/learn-wgpu/assets/js/67.cf780dc9.js"><link rel="prefetch" href="/learn-wgpu/assets/js/68.d785413d.js"><link rel="prefetch" href="/learn-wgpu/assets/js/8.bd84af76.js"><link rel="prefetch" href="/learn-wgpu/assets/js/9.d183c6d6.js"><link rel="prefetch" href="/learn-wgpu/assets/js/vendors~docsearch.efa6f8ef.js">
<link rel="stylesheet" href="/learn-wgpu/assets/css/0.styles.81cb5453.css">
</head>
<body>
<div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="inner"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/learn-wgpu/" class="home-link router-link-active"><!----> <span class="site-name">Learn Wgpu</span></a> <div class="links"><!----> <div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div></div></div></header> <div class="sidebar-mask"></div> <div class="docs-layout"><aside class="sidebar"><!----> <ul class="sidebar-links"><li><a href="/learn-wgpu/" aria-current="page" class="sidebar-link">Introduction</a></li><li><section class="sidebar-group depth-0"><p class="sidebar-heading open"><span>Beginner</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/learn-wgpu/beginner/tutorial1-window/" class="sidebar-link">Dependencies and the window</a></li><li><a href="/learn-wgpu/beginner/tutorial2-surface/" class="sidebar-link">The Surface</a></li><li><a href="/learn-wgpu/beginner/tutorial3-pipeline/" class="sidebar-link">The Pipeline</a></li><li><a href="/learn-wgpu/beginner/tutorial4-buffer/" class="sidebar-link">Buffers and Indices</a></li><li><a href="/learn-wgpu/beginner/tutorial5-textures/" aria-current="page" class="active sidebar-link">Textures and bind groups</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/learn-wgpu/beginner/tutorial5-textures/#loading-an-image-from-a-file" class="sidebar-link">Loading an image from a file</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/beginner/tutorial5-textures/#getting-data-into-a-texture" class="sidebar-link">Getting data into a Texture</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/beginner/tutorial5-textures/#textureviews-and-samplers" class="sidebar-link">TextureViews and Samplers</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/beginner/tutorial5-textures/#the-bindgroup" class="sidebar-link">The BindGroup</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/beginner/tutorial5-textures/#pipelinelayout" class="sidebar-link">PipelineLayout</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/beginner/tutorial5-textures/#a-change-to-the-vertices" class="sidebar-link">A change to the VERTICES</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/beginner/tutorial5-textures/#shader-time" class="sidebar-link">Shader time</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/beginner/tutorial5-textures/#the-results" class="sidebar-link">The results</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/beginner/tutorial5-textures/#cleaning-things-up" class="sidebar-link">Cleaning things up</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/beginner/tutorial5-textures/#challenge" class="sidebar-link">Challenge</a></li></ul></li><li><a href="/learn-wgpu/beginner/tutorial6-uniforms/" class="sidebar-link">Uniform buffers and a 3d camera</a></li><li><a href="/learn-wgpu/beginner/tutorial7-instancing/" class="sidebar-link">Instancing</a></li><li><a href="/learn-wgpu/beginner/tutorial8-depth/" class="sidebar-link">The Depth Buffer</a></li><li><a href="/learn-wgpu/beginner/tutorial9-models/" class="sidebar-link">Model Loading</a></li></ul></section></li><li><section class="sidebar-group depth-0"><p class="sidebar-heading"><span>Intermediate</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/learn-wgpu/intermediate/tutorial10-lighting/" class="sidebar-link">Working with Lights</a></li><li><a href="/learn-wgpu/intermediate/tutorial11-normals/" class="sidebar-link">Normal Mapping</a></li><li><a href="/learn-wgpu/intermediate/tutorial12-camera/" class="sidebar-link">A Better Camera</a></li><li><a href="/learn-wgpu/intermediate/tutorial13-hdr/" class="sidebar-link">High Dynamic Range Rendering</a></li></ul></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>Showcase</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>News</span> <span class="arrow right"></span></p> <!----></section></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><h1 id="textures-and-bind-groups"><a href="#textures-and-bind-groups" class="header-anchor">#</a> Textures and bind groups</h1> <p>Up to this point, we have been drawing super simple shapes. While we can make a game with just triangles, trying to draw highly detailed objects would massively limit what devices could even run our game. However, we can get around this problem with <strong>textures</strong>.</p> <p>Textures are images overlaid on a triangle mesh to make it seem more detailed. There are multiple types of textures, such as normal maps, bump maps, specular maps, and diffuse maps. We're going to talk about diffuse maps or, more simply, the color texture.</p> <h2 id="loading-an-image-from-a-file"><a href="#loading-an-image-from-a-file" class="header-anchor">#</a> Loading an image from a file</h2> <p>If we want to map an image to our mesh, we first need an image. Let's use this happy little tree:</p> <p><img src="/learn-wgpu/assets/img/happy-tree.bdff8a19.png" alt="a happy tree"></p> <p>We'll use the <a href="https://docs.rs/image" target="_blank" rel="noopener noreferrer">image 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"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> to load our tree. Let's add it to our dependencies:</p> <div class="language-toml extra-class"><pre class="language-toml"><code><span class="token punctuation">[</span><span class="token table class-name">dependencies.image</span><span class="token punctuation">]</span>
<span class="token key property">version</span> <span class="token punctuation">=</span> <span class="token string">&quot;0.24&quot;</span>
<span class="token key property">default-features</span> <span class="token punctuation">=</span> <span class="token boolean">false</span>
<span class="token key property">features</span> <span class="token punctuation">=</span> <span class="token punctuation">[</span><span class="token string">&quot;png&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;jpeg&quot;</span><span class="token punctuation">]</span>
</code></pre></div><p>The jpeg decoder that <code>image</code> includes uses <a href="https://docs.rs/rayon" target="_blank" rel="noopener noreferrer">rayon<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> to speed up the decoding with threads. WASM doesn't support threads currently, so we need to disable this so our code won't crash when we try to load a jpeg on the web.</p> <div class="note"><p>Decoding jpegs in WASM isn't very performant. If you want to speed up image loading in general in WASM, you could opt to use the browser's built-in decoders instead of <code>image</code> when building with <code>wasm-bindgen</code>. This will involve creating an <code>&lt;img&gt;</code> tag in Rust to get the image and then a <code>&lt;canvas&gt;</code> to get the pixel data, but I'll leave this as an exercise for the reader.</p></div> <p>In <code>State</code>'s <code>new()</code> method, add the following just after configuring the <code>surface</code>:</p> <div class="language-rust extra-class"><pre class="language-rust"><code>surface<span class="token punctuation">.</span><span class="token function">configure</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>device<span class="token punctuation">,</span> <span class="token operator">&amp;</span>config<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// NEW!</span>
<span class="token keyword">let</span> diffuse_bytes <span class="token operator">=</span> <span class="token macro property">include_bytes!</span><span class="token punctuation">(</span><span class="token string">&quot;happy-tree.png&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> diffuse_image <span class="token operator">=</span> <span class="token namespace">image<span class="token punctuation">::</span></span><span class="token function">load_from_memory</span><span class="token punctuation">(</span>diffuse_bytes<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> diffuse_rgba <span class="token operator">=</span> diffuse_image<span class="token punctuation">.</span><span class="token function">to_rgba8</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token namespace">image<span class="token punctuation">::</span></span><span class="token class-name">GenericImageView</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> dimensions <span class="token operator">=</span> diffuse_image<span class="token punctuation">.</span><span class="token function">dimensions</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>Here, we grab the bytes from our image file and load them into an image, which is then converted into a <code>Vec</code> of RGBA bytes. We also save the image's dimensions for when we create the actual <code>Texture</code>.</p> <p>Now, let's create the <code>Texture</code>:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">let</span> texture_size <span class="token operator">=</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Extent3d</span> <span class="token punctuation">{</span>
width<span class="token punctuation">:</span> dimensions<span class="token number">.0</span><span class="token punctuation">,</span>
height<span class="token punctuation">:</span> dimensions<span class="token number">.1</span><span class="token punctuation">,</span>
depth_or_array_layers<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> diffuse_texture <span class="token operator">=</span> device<span class="token punctuation">.</span><span class="token function">create_texture</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">TextureDescriptor</span> <span class="token punctuation">{</span>
<span class="token comment">// All textures are stored as 3D, we represent our 2D texture</span>
<span class="token comment">// by setting depth to 1.</span>
size<span class="token punctuation">:</span> texture_size<span class="token punctuation">,</span>
mip_level_count<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token comment">// We'll talk about this a little later</span>
sample_count<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span>
dimension<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">TextureDimension</span><span class="token punctuation">::</span><span class="token constant">D2</span><span class="token punctuation">,</span>
<span class="token comment">// Most images are stored using sRGB, so we need to reflect that here.</span>
format<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">TextureFormat</span><span class="token punctuation">::</span><span class="token class-name">Rgba8UnormSrgb</span><span class="token punctuation">,</span>
<span class="token comment">// TEXTURE_BINDING tells wgpu that we want to use this texture in shaders</span>
<span class="token comment">// COPY_DST means that we want to copy data to this texture</span>
usage<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">TextureUsages</span><span class="token punctuation">::</span><span class="token constant">TEXTURE_BINDING</span> <span class="token operator">|</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">TextureUsages</span><span class="token punctuation">::</span><span class="token constant">COPY_DST</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;diffuse_texture&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token comment">// This is the same as with the SurfaceConfig. It</span>
<span class="token comment">// specifies what texture formats can be used to</span>
<span class="token comment">// create TextureViews for this texture. The base</span>
<span class="token comment">// texture format (Rgba8UnormSrgb in this case) is</span>
<span class="token comment">// always supported. Note that using a different</span>
<span class="token comment">// texture format is not supported on the WebGL2</span>
<span class="token comment">// backend.</span>
view_formats<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><h2 id="getting-data-into-a-texture"><a href="#getting-data-into-a-texture" class="header-anchor">#</a> Getting data into a Texture</h2> <p>The <code>Texture</code> struct has no methods to interact with the data directly. However, we can use a method on the <code>queue</code> we created earlier called <code>write_texture</code> to load in the texture. Let's take a look at how we do that:</p> <div class="language-rust extra-class"><pre class="language-rust"><code>queue<span class="token punctuation">.</span><span class="token function">write_texture</span><span class="token punctuation">(</span>
<span class="token comment">// Tells wgpu where to copy the pixel data</span>
<span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">ImageCopyTexture</span> <span class="token punctuation">{</span>
texture<span class="token punctuation">:</span> <span class="token operator">&amp;</span>diffuse_texture<span class="token punctuation">,</span>
mip_level<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
origin<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Origin3d</span><span class="token punctuation">::</span><span class="token constant">ZERO</span><span class="token punctuation">,</span>
aspect<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">TextureAspect</span><span class="token punctuation">::</span><span class="token class-name">All</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token comment">// The actual pixel data</span>
<span class="token operator">&amp;</span>diffuse_rgba<span class="token punctuation">,</span>
<span class="token comment">// The layout of the texture</span>
<span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">ImageDataLayout</span> <span class="token punctuation">{</span>
offset<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
bytes_per_row<span class="token punctuation">:</span> <span class="token class-name">Some</span><span class="token punctuation">(</span><span class="token number">4</span> <span class="token operator">*</span> dimensions<span class="token number">.0</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
rows_per_image<span class="token punctuation">:</span> <span class="token class-name">Some</span><span class="token punctuation">(</span>dimensions<span class="token number">.1</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
texture_size<span class="token punctuation">,</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><div class="note"><p>The old way of writing data to a texture was to copy the pixel data to a buffer and then copy it to the texture. Using <code>write_texture</code> is a bit more efficient as it uses one buffer less - I'll leave it here, though, in case you need it.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">let</span> 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;Temp Buffer&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
contents<span class="token punctuation">:</span> <span class="token operator">&amp;</span>diffuse_rgba<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">COPY_SRC</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> <span class="token keyword">mut</span> encoder <span class="token operator">=</span> device<span class="token punctuation">.</span><span class="token function">create_command_encoder</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">CommandEncoderDescriptor</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;texture_buffer_copy_encoder&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
encoder<span class="token punctuation">.</span><span class="token function">copy_buffer_to_texture</span><span class="token punctuation">(</span>
<span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">ImageCopyBuffer</span> <span class="token punctuation">{</span>
buffer<span class="token punctuation">:</span> <span class="token operator">&amp;</span>buffer<span class="token punctuation">,</span>
offset<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
bytes_per_row<span class="token punctuation">:</span> <span class="token number">4</span> <span class="token operator">*</span> dimensions<span class="token number">.0</span><span class="token punctuation">,</span>
rows_per_image<span class="token punctuation">:</span> dimensions<span class="token number">.1</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">ImageCopyTexture</span> <span class="token punctuation">{</span>
texture<span class="token punctuation">:</span> <span class="token operator">&amp;</span>diffuse_texture<span class="token punctuation">,</span>
mip_level<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
array_layer<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
origin<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Origin3d</span><span class="token punctuation">::</span><span class="token constant">ZERO</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
size<span class="token punctuation">,</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
queue<span class="token punctuation">.</span><span class="token function">submit</span><span class="token punctuation">(</span><span class="token namespace">std<span class="token punctuation">::</span>iter<span class="token punctuation">::</span></span><span class="token function">once</span><span class="token punctuation">(</span>encoder<span class="token punctuation">.</span><span class="token function">finish</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>The <code>bytes_per_row</code> field needs some consideration. This value needs to be a multiple of 256. Check out <a href="/learn-wgpu/showcase/gifs/#how-do-we-make-the-frames">the gif tutorial</a> for more details.</p></div> <h2 id="textureviews-and-samplers"><a href="#textureviews-and-samplers" class="header-anchor">#</a> TextureViews and Samplers</h2> <p>Now that our texture has data in it, we need a way to use it. This is where a <code>TextureView</code> and a <code>Sampler</code> come in. A <code>TextureView</code> offers us a <em>view</em> into our texture. A <code>Sampler</code> controls how the <code>Texture</code> is <em>sampled</em>. Sampling works similar to the eyedropper tool in GIMP/Photoshop. Our program supplies a coordinate on the texture (known as a <em>texture coordinate</em>), and the sampler then returns the corresponding color based on the texture and some internal parameters.</p> <p>Let's define our <code>diffuse_texture_view</code> and <code>diffuse_sampler</code> now:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token comment">// We don't need to configure the texture view much, so let's</span>
<span class="token comment">// let wgpu define it.</span>
<span class="token keyword">let</span> diffuse_texture_view <span class="token operator">=</span> diffuse_texture<span class="token punctuation">.</span><span class="token function">create_view</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">TextureViewDescriptor</span><span class="token punctuation">::</span><span class="token function">default</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> diffuse_sampler <span class="token operator">=</span> device<span class="token punctuation">.</span><span class="token function">create_sampler</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">SamplerDescriptor</span> <span class="token punctuation">{</span>
address_mode_u<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">AddressMode</span><span class="token punctuation">::</span><span class="token class-name">ClampToEdge</span><span class="token punctuation">,</span>
address_mode_v<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">AddressMode</span><span class="token punctuation">::</span><span class="token class-name">ClampToEdge</span><span class="token punctuation">,</span>
address_mode_w<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">AddressMode</span><span class="token punctuation">::</span><span class="token class-name">ClampToEdge</span><span class="token punctuation">,</span>
mag_filter<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">FilterMode</span><span class="token punctuation">::</span><span class="token class-name">Linear</span><span class="token punctuation">,</span>
min_filter<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">FilterMode</span><span class="token punctuation">::</span><span class="token class-name">Nearest</span><span class="token punctuation">,</span>
mipmap_filter<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">FilterMode</span><span class="token punctuation">::</span><span class="token class-name">Nearest</span><span class="token punctuation">,</span>
<span class="token punctuation">..</span><span class="token class-name">Default</span><span class="token punctuation">::</span><span class="token function">default</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>The <code>address_mode_*</code> parameters determine what to do if the sampler gets a texture coordinate that's outside the texture itself. We have a few options to choose from:</p> <ul><li><code>ClampToEdge</code>: Any texture coordinates outside the texture will return the color of the nearest pixel on the edges of the texture.</li> <li><code>Repeat</code>: The texture will repeat as texture coordinates exceed the texture's dimensions.</li> <li><code>MirrorRepeat</code>: Similar to <code>Repeat</code>, but the image will flip when going over boundaries.</li></ul> <p><img src="/learn-wgpu/assets/img/address_mode.66a7cd1a.png" alt="address_mode.png"></p> <p>The <code>mag_filter</code> and <code>min_filter</code> fields describe what to do when the sample footprint is smaller or larger than one texel. These two fields usually work when the mapping in the scene is far from or close to the camera.</p> <p>There are two options:</p> <ul><li><code>Linear</code>: Select two texels in each dimension and return a linear interpolation between their values.</li> <li><code>Nearest</code>: Return the texel value nearest to the texture coordinates. This creates an image that's crisper from far away but pixelated up close. This can be desirable, however, if your textures are designed to be pixelated, like in pixel art games or voxel games like Minecraft.</li></ul> <p>Mipmaps are a complex topic and will require their own section in the future. For now, we can say that <code>mipmap_filter</code> functions are similar to <code>(mag/min)_filter</code> as it tells the sampler how to blend between mipmaps.</p> <p>I'm using some defaults for the other fields. If you want to see what they are, check <a href="https://docs.rs/wgpu/latest/wgpu/struct.SamplerDescriptor.html" target="_blank" rel="noopener noreferrer">the wgpu 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"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>.</p> <p>All these different resources are nice and all, but they don't do us much good if we can't plug them in anywhere. This is where <code>BindGroup</code>s and <code>PipelineLayout</code>s come in.</p> <h2 id="the-bindgroup"><a href="#the-bindgroup" class="header-anchor">#</a> The BindGroup</h2> <p>A <code>BindGroup</code> describes a set of resources and how they can be accessed by a shader. We create a <code>BindGroup</code> using a <code>BindGroupLayout</code>. Let's make one of those first.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">let</span> texture_bind_group_layout <span class="token operator">=</span>
device<span class="token punctuation">.</span><span class="token function">create_bind_group_layout</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">BindGroupLayoutDescriptor</span> <span class="token punctuation">{</span>
entries<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token punctuation">[</span>
<span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BindGroupLayoutEntry</span> <span class="token punctuation">{</span>
binding<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
visibility<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">ShaderStages</span><span class="token punctuation">::</span><span class="token constant">FRAGMENT</span><span class="token punctuation">,</span>
ty<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BindingType</span><span class="token punctuation">::</span><span class="token class-name">Texture</span> <span class="token punctuation">{</span>
multisampled<span class="token punctuation">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
view_dimension<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">TextureViewDimension</span><span class="token punctuation">::</span><span class="token constant">D2</span><span class="token punctuation">,</span>
sample_type<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">TextureSampleType</span><span class="token punctuation">::</span><span class="token class-name">Float</span> <span class="token punctuation">{</span> filterable<span class="token punctuation">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
count<span class="token punctuation">:</span> <span class="token class-name">None</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BindGroupLayoutEntry</span> <span class="token punctuation">{</span>
binding<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span>
visibility<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">ShaderStages</span><span class="token punctuation">::</span><span class="token constant">FRAGMENT</span><span class="token punctuation">,</span>
<span class="token comment">// This should match the filterable field of the</span>
<span class="token comment">// corresponding Texture entry above.</span>
ty<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BindingType</span><span class="token punctuation">::</span><span class="token class-name">Sampler</span><span class="token punctuation">(</span><span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">SamplerBindingType</span><span class="token punctuation">::</span><span class="token class-name">Filtering</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
count<span class="token punctuation">:</span> <span class="token class-name">None</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><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;texture_bind_group_layout&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>Our <code>texture_bind_group_layout</code> has two entries: one for a sampled texture at binding 0 and one for a sampler at binding 1. Both of these bindings are visible only to the fragment shader as specified by <code>FRAGMENT</code>. The possible values for this field are any bitwise combination of <code>NONE</code>, <code>VERTEX</code>, <code>FRAGMENT</code>, or <code>COMPUTE</code>. Most of the time, we'll only use <code>FRAGMENT</code> for textures and samplers, but it's good to know what else is available.</p> <p>With <code>texture_bind_group_layout</code>, we can now create our <code>BindGroup</code>:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">let</span> diffuse_bind_group <span class="token operator">=</span> device<span class="token punctuation">.</span><span class="token function">create_bind_group</span><span class="token punctuation">(</span>
<span class="token operator">&amp;</span><span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BindGroupDescriptor</span> <span class="token punctuation">{</span>
layout<span class="token punctuation">:</span> <span class="token operator">&amp;</span>texture_bind_group_layout<span class="token punctuation">,</span>
entries<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token punctuation">[</span>
<span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BindGroupEntry</span> <span class="token punctuation">{</span>
binding<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
resource<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BindingResource</span><span class="token punctuation">::</span><span class="token class-name">TextureView</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>diffuse_texture_view<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BindGroupEntry</span> <span class="token punctuation">{</span>
binding<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span>
resource<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BindingResource</span><span class="token punctuation">::</span><span class="token class-name">Sampler</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>diffuse_sampler<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span>
label<span class="token punctuation">:</span> <span class="token class-name">Some</span><span class="token punctuation">(</span><span class="token string">&quot;diffuse_bind_group&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>Looking at this, you might get a bit of déjà vu! That's because a <code>BindGroup</code> is a more specific declaration of the <code>BindGroupLayout</code>. The reason they're separate is that it allows us to swap out <code>BindGroup</code>s on the fly, so long as they all share the same <code>BindGroupLayout</code>. Each texture and sampler we create will need to be added to a <code>BindGroup</code>. For our purposes, we'll create a new bind group for each texture.</p> <p>Now that we have our <code>diffuse_bind_group</code>, let's add it to our <code>State</code> struct:</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>
surface<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Surface</span><span class="token punctuation">,</span>
device<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Device</span><span class="token punctuation">,</span>
queue<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Queue</span><span class="token punctuation">,</span>
config<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">SurfaceConfiguration</span><span class="token punctuation">,</span>
size<span class="token punctuation">:</span> <span class="token namespace">winit<span class="token punctuation">::</span>dpi<span class="token punctuation">::</span></span><span class="token class-name">PhysicalSize</span><span class="token operator">&lt;</span><span class="token keyword">u32</span><span class="token operator">&gt;</span><span class="token punctuation">,</span>
render_pipeline<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">RenderPipeline</span><span class="token punctuation">,</span>
vertex_buffer<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Buffer</span><span class="token punctuation">,</span>
index_buffer<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Buffer</span><span class="token punctuation">,</span>
num_indices<span class="token punctuation">:</span> <span class="token keyword">u32</span><span class="token punctuation">,</span>
diffuse_bind_group<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BindGroup</span><span class="token punctuation">,</span> <span class="token comment">// NEW!</span>
<span class="token punctuation">}</span>
</code></pre></div><p>Make sure we return these fields in the <code>new</code> method:</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><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">Self</span> <span class="token punctuation">{</span>
surface<span class="token punctuation">,</span>
device<span class="token punctuation">,</span>
queue<span class="token punctuation">,</span>
config<span class="token punctuation">,</span>
size<span class="token punctuation">,</span>
render_pipeline<span class="token punctuation">,</span>
vertex_buffer<span class="token punctuation">,</span>
index_buffer<span class="token punctuation">,</span>
num_indices<span class="token punctuation">,</span>
<span class="token comment">// NEW!</span>
diffuse_bind_group<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 that we've got our <code>BindGroup</code>, we can use it in our <code>render()</code> function.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token comment">// render()</span>
<span class="token comment">// ...</span>
render_pass<span class="token punctuation">.</span><span class="token function">set_pipeline</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">.</span>render_pipeline<span class="token punctuation">)</span><span class="token punctuation">;</span>
render_pass<span class="token punctuation">.</span><span class="token function">set_bind_group</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">.</span>diffuse_bind_group<span class="token punctuation">,</span> <span class="token operator">&amp;</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <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">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>
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>
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 number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><h2 id="pipelinelayout"><a href="#pipelinelayout" class="header-anchor">#</a> PipelineLayout</h2> <p>Remember the <code>PipelineLayout</code> we created back in <a href="learn-wgpu/beginner/tutorial3-pipeline#how-do-we-use-the-shaders">the pipeline section</a>? Now, we finally get to use it! The <code>PipelineLayout</code> contains a list of <code>BindGroupLayout</code>s that the pipeline can use. Modify <code>render_pipeline_layout</code> to use our <code>texture_bind_group_layout</code>.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><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><span class="token punctuation">...</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
<span class="token keyword">let</span> render_pipeline_layout <span class="token operator">=</span> device<span class="token punctuation">.</span><span class="token function">create_pipeline_layout</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">PipelineLayoutDescriptor</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;Render Pipeline Layout&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
bind_group_layouts<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token punctuation">[</span><span class="token operator">&amp;</span>texture_bind_group_layout<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token comment">// NEW!</span>
push_constant_ranges<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// ...</span>
<span class="token punctuation">}</span>
</code></pre></div><h2 id="a-change-to-the-vertices"><a href="#a-change-to-the-vertices" class="header-anchor">#</a> A change to the VERTICES</h2> <p>There are a few things we need to change about our <code>Vertex</code> definition. Up to now, we've been using a <code>color</code> attribute to set the color of our mesh. Now that we're using a texture, we want to replace our <code>color</code> with <code>tex_coords</code>. These coordinates will then be passed to the <code>Sampler</code> to retrieve the appropriate color.</p> <p>Since our <code>tex_coords</code> are two-dimensional, we'll change the field to take two floats instead of three.</p> <p>First, we'll change the <code>Vertex</code> struct:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token attribute attr-name">#[repr(C)]</span>
<span class="token attribute attr-name">#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]</span>
<span class="token keyword">struct</span> <span class="token type-definition class-name">Vertex</span> <span class="token punctuation">{</span>
position<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token keyword">f32</span><span class="token punctuation">;</span> <span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
tex_coords<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token keyword">f32</span><span class="token punctuation">;</span> <span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token comment">// NEW!</span>
<span class="token punctuation">}</span>
</code></pre></div><p>And then reflect these changes in the <code>VertexBufferLayout</code>:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">impl</span> <span class="token class-name">Vertex</span> <span class="token punctuation">{</span>
<span class="token keyword">fn</span> <span class="token function-definition function">desc</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">VertexBufferLayout</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">'static</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span></span>mem<span class="token punctuation">;</span>
<span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">VertexBufferLayout</span> <span class="token punctuation">{</span>
array_stride<span class="token punctuation">:</span> <span class="token namespace">mem<span class="token punctuation">::</span></span><span class="token function">size_of</span><span class="token punctuation">::</span><span class="token operator">&lt;</span><span class="token class-name">Vertex</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">as</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BufferAddress</span><span class="token punctuation">,</span>
step_mode<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">VertexStepMode</span><span class="token punctuation">::</span><span class="token class-name">Vertex</span><span class="token punctuation">,</span>
attributes<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token punctuation">[</span>
<span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">VertexAttribute</span> <span class="token punctuation">{</span>
offset<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
shader_location<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
format<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">VertexFormat</span><span class="token punctuation">::</span><span class="token class-name">Float32x3</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">VertexAttribute</span> <span class="token punctuation">{</span>
offset<span class="token punctuation">:</span> <span class="token namespace">mem<span class="token punctuation">::</span></span><span class="token function">size_of</span><span class="token punctuation">::</span><span class="token operator">&lt;</span><span class="token punctuation">[</span><span class="token keyword">f32</span><span class="token punctuation">;</span> <span class="token number">3</span><span class="token punctuation">]</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">as</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BufferAddress</span><span class="token punctuation">,</span>
shader_location<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span>
format<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">VertexFormat</span><span class="token punctuation">::</span><span class="token class-name">Float32x2</span><span class="token punctuation">,</span> <span class="token comment">// NEW!</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>Lastly, we need to change <code>VERTICES</code> itself. Replace the existing definition with the following:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token comment">// Changed</span>
<span class="token keyword">const</span> <span class="token constant">VERTICES</span><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 operator">=</span> <span class="token operator">&amp;</span><span class="token punctuation">[</span>
<span class="token class-name">Vertex</span> <span class="token punctuation">{</span> position<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token operator">-</span><span class="token number">0.0868241</span><span class="token punctuation">,</span> <span class="token number">0.49240386</span><span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">]</span><span class="token punctuation">,</span> tex_coords<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token number">0.4131759</span><span class="token punctuation">,</span> <span class="token number">0.99240386</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">// A</span>
<span class="token class-name">Vertex</span> <span class="token punctuation">{</span> position<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token operator">-</span><span class="token number">0.49513406</span><span class="token punctuation">,</span> <span class="token number">0.06958647</span><span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">]</span><span class="token punctuation">,</span> tex_coords<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token number">0.0048659444</span><span class="token punctuation">,</span> <span class="token number">0.56958647</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">// B</span>
<span class="token class-name">Vertex</span> <span class="token punctuation">{</span> position<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token operator">-</span><span class="token number">0.21918549</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">0.44939706</span><span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">]</span><span class="token punctuation">,</span> tex_coords<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token number">0.28081453</span><span class="token punctuation">,</span> <span class="token number">0.05060294</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">// C</span>
<span class="token class-name">Vertex</span> <span class="token punctuation">{</span> position<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token number">0.35966998</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">0.3473291</span><span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">]</span><span class="token punctuation">,</span> tex_coords<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token number">0.85967</span><span class="token punctuation">,</span> <span class="token number">0.1526709</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">// D</span>
<span class="token class-name">Vertex</span> <span class="token punctuation">{</span> position<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token number">0.44147372</span><span class="token punctuation">,</span> <span class="token number">0.2347359</span><span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">]</span><span class="token punctuation">,</span> tex_coords<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token number">0.9414737</span><span class="token punctuation">,</span> <span class="token number">0.7347359</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">// E</span>
<span class="token punctuation">]</span><span class="token punctuation">;</span>
</code></pre></div><h2 id="shader-time"><a href="#shader-time" class="header-anchor">#</a> Shader time</h2> <p>With our new <code>Vertex</code> structure in place, it's time to update our shaders. We'll first need to pass our <code>tex_coords</code> into the vertex shader and then use them over to our fragment shader to get the final color from the <code>Sampler</code>. Let's start with the vertex shader:</p> <div class="language-wgsl extra-class"><pre class="language-wgsl"><code><span class="token comment">// Vertex shader</span>
<span class="token keyword">struct</span> <span class="token class-name">VertexInput</span> <span class="token punctuation">{</span>
<span class="token punctuation">@</span><span class="token attributes attr-name">location</span><span class="token punctuation">(</span><span class="token int-literal number">0</span><span class="token punctuation">)</span> position<span class="token punctuation">:</span> <span class="token builtin">vec3</span><span class="token punctuation">&lt;</span><span class="token builtin">f32</span><span class="token punctuation">&gt;</span><span class="token punctuation">,</span>
<span class="token punctuation">@</span><span class="token attributes attr-name">location</span><span class="token punctuation">(</span><span class="token int-literal number">1</span><span class="token punctuation">)</span> tex_coords<span class="token punctuation">:</span> <span class="token builtin">vec2</span><span class="token punctuation">&lt;</span><span class="token builtin">f32</span><span class="token punctuation">&gt;</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token keyword">struct</span> <span class="token class-name">VertexOutput</span> <span class="token punctuation">{</span>
<span class="token punctuation">@</span><span class="token builtin-attribute"><span class="token attribute attr-name">builtin</span><span class="token punctuation">(</span><span class="token built-in-values attr-value">position</span><span class="token punctuation">)</span></span> clip_position<span class="token punctuation">:</span> <span class="token builtin">vec4</span><span class="token punctuation">&lt;</span><span class="token builtin">f32</span><span class="token punctuation">&gt;</span><span class="token punctuation">,</span>
<span class="token punctuation">@</span><span class="token attributes attr-name">location</span><span class="token punctuation">(</span><span class="token int-literal number">0</span><span class="token punctuation">)</span> tex_coords<span class="token punctuation">:</span> <span class="token builtin">vec2</span><span class="token punctuation">&lt;</span><span class="token builtin">f32</span><span class="token punctuation">&gt;</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token punctuation">@</span><span class="token attributes attr-name">vertex</span>
<span class="token keyword">fn</span> <span class="token functions function">vs_main</span><span class="token punctuation">(</span>
model<span class="token punctuation">:</span> <span class="token class-name">VertexInput</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span> <span class="token operator">-&gt;</span> <span class="token class-name">VertexOutput</span> <span class="token punctuation">{</span>
<span class="token keyword">var</span> out<span class="token punctuation">:</span> <span class="token class-name">VertexOutput</span><span class="token punctuation">;</span>
out<span class="token punctuation">.</span>tex_coords <span class="token operator">=</span> model<span class="token punctuation">.</span>tex_coords<span class="token punctuation">;</span>
out<span class="token punctuation">.</span>clip_position <span class="token operator">=</span> <span class="token builtin">vec4</span><span class="token punctuation">&lt;</span><span class="token builtin">f32</span><span class="token punctuation">&gt;</span><span class="token punctuation">(</span>model<span class="token punctuation">.</span>position<span class="token punctuation">,</span> <span class="token decimal-float-literal number">1.0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> out<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>Now that we have our vertex shader outputting our <code>tex_coords</code>, we need to change the fragment shader to take them in. With these coordinates, we'll finally be able to use our sampler to get a color from our texture.</p> <div class="language-wgsl extra-class"><pre class="language-wgsl"><code><span class="token comment">// Fragment shader</span>
<span class="token punctuation">@</span><span class="token attributes attr-name">group</span><span class="token punctuation">(</span><span class="token int-literal number">0</span><span class="token punctuation">)</span> <span class="token punctuation">@</span><span class="token attributes attr-name">binding</span><span class="token punctuation">(</span><span class="token int-literal number">0</span><span class="token punctuation">)</span>
<span class="token keyword">var</span> t_diffuse<span class="token punctuation">:</span> <span class="token builtin">texture_2d</span><span class="token punctuation">&lt;</span><span class="token builtin">f32</span><span class="token punctuation">&gt;</span><span class="token punctuation">;</span>
<span class="token punctuation">@</span><span class="token attributes attr-name">group</span><span class="token punctuation">(</span><span class="token int-literal number">0</span><span class="token punctuation">)</span> <span class="token punctuation">@</span><span class="token attributes attr-name">binding</span><span class="token punctuation">(</span><span class="token int-literal number">1</span><span class="token punctuation">)</span>
<span class="token keyword">var</span> s_diffuse<span class="token punctuation">:</span> <span class="token builtin">sampler</span><span class="token punctuation">;</span>
<span class="token punctuation">@</span><span class="token attributes attr-name">fragment</span>
<span class="token keyword">fn</span> <span class="token functions function">fs_main</span><span class="token punctuation">(</span>in<span class="token punctuation">:</span> <span class="token class-name">VertexOutput</span><span class="token punctuation">)</span> <span class="token operator">-&gt;</span> <span class="token punctuation">@</span><span class="token attributes attr-name">location</span><span class="token punctuation">(</span><span class="token int-literal number">0</span><span class="token punctuation">)</span> <span class="token builtin">vec4</span><span class="token punctuation">&lt;</span><span class="token builtin">f32</span><span class="token punctuation">&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token builtin">textureSample</span><span class="token punctuation">(</span>t_diffuse<span class="token punctuation">,</span> s_diffuse<span class="token punctuation">,</span> in<span class="token punctuation">.</span>tex_coords<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>The variables <code>t_diffuse</code> and <code>s_diffuse</code> are what's known as uniforms. We'll go over uniforms more in the <a href="/learn-wgpu/beginner/tutorial6-uniforms/">cameras section</a>. For now, all we need to know is that <code>group()</code> corresponds to the 1st parameter in <code>set_bind_group()</code> and <code>binding()</code> relates to the <code>binding</code> specified when we created the <code>BindGroupLayout</code> and <code>BindGroup</code>.</p> <h2 id="the-results"><a href="#the-results" class="header-anchor">#</a> The results</h2> <p>If we run our program now, we should get the following result:</p> <p><img src="/learn-wgpu/assets/img/upside-down.d50c3643.png" alt="an upside down tree on a pentagon"></p> <p>That's weird. Our tree is upside down! This is because wgpu's world coordinates have the y-axis pointing up, while texture coordinates have the y-axis pointing down. In other words, (0, 0) in texture coordinates corresponds to the top-left of the image, while (1, 1) is the bottom right.</p> <p><img src="/learn-wgpu/assets/img/happy-tree-uv-coords.aa3b7d36.png" alt="happy-tree-uv-coords.png"></p> <p>We can get our triangle right-side up by replacing the y coordinate <code>y</code> of each texture coordinate with <code>1 - y</code>:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">const</span> <span class="token constant">VERTICES</span><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 operator">=</span> <span class="token operator">&amp;</span><span class="token punctuation">[</span>
<span class="token comment">// Changed</span>
<span class="token class-name">Vertex</span> <span class="token punctuation">{</span> position<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token operator">-</span><span class="token number">0.0868241</span><span class="token punctuation">,</span> <span class="token number">0.49240386</span><span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">]</span><span class="token punctuation">,</span> tex_coords<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token number">0.4131759</span><span class="token punctuation">,</span> <span class="token number">0.00759614</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">// A</span>
<span class="token class-name">Vertex</span> <span class="token punctuation">{</span> position<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token operator">-</span><span class="token number">0.49513406</span><span class="token punctuation">,</span> <span class="token number">0.06958647</span><span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">]</span><span class="token punctuation">,</span> tex_coords<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token number">0.0048659444</span><span class="token punctuation">,</span> <span class="token number">0.43041354</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">// B</span>
<span class="token class-name">Vertex</span> <span class="token punctuation">{</span> position<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token operator">-</span><span class="token number">0.21918549</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">0.44939706</span><span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">]</span><span class="token punctuation">,</span> tex_coords<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token number">0.28081453</span><span class="token punctuation">,</span> <span class="token number">0.949397</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">// C</span>
<span class="token class-name">Vertex</span> <span class="token punctuation">{</span> position<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token number">0.35966998</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">0.3473291</span><span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">]</span><span class="token punctuation">,</span> tex_coords<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token number">0.85967</span><span class="token punctuation">,</span> <span class="token number">0.84732914</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">// D</span>
<span class="token class-name">Vertex</span> <span class="token punctuation">{</span> position<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token number">0.44147372</span><span class="token punctuation">,</span> <span class="token number">0.2347359</span><span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">]</span><span class="token punctuation">,</span> tex_coords<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token number">0.9414737</span><span class="token punctuation">,</span> <span class="token number">0.2652641</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">// E</span>
<span class="token punctuation">]</span><span class="token punctuation">;</span>
</code></pre></div><p>With that in place, we now have our tree right-side up on our pentagon:</p> <p><img src="/learn-wgpu/assets/img/rightside-up.eb2186c8.png" alt="our happy tree as it should be"></p> <h2 id="cleaning-things-up"><a href="#cleaning-things-up" class="header-anchor">#</a> Cleaning things up</h2> <p>For convenience, let's pull our texture code into its own module. We'll first need to add the <a href="https://docs.rs/anyhow/" 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"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> crate to our <code>Cargo.toml</code> file to simplify error handling;</p> <div class="language-toml extra-class"><pre class="language-toml"><code><span class="token punctuation">[</span><span class="token table class-name">dependencies</span><span class="token punctuation">]</span>
<span class="token key property">image</span> <span class="token punctuation">=</span> <span class="token string">&quot;0.23&quot;</span>
<span class="token key property">cgmath</span> <span class="token punctuation">=</span> <span class="token string">&quot;0.18&quot;</span>
<span class="token key property">winit</span> <span class="token punctuation">=</span> <span class="token string">&quot;0.28&quot;</span>
<span class="token key property">env_logger</span> <span class="token punctuation">=</span> <span class="token string">&quot;0.10&quot;</span>
<span class="token key property">log</span> <span class="token punctuation">=</span> <span class="token string">&quot;0.4&quot;</span>
<span class="token key property">pollster</span> <span class="token punctuation">=</span> <span class="token string">&quot;0.3&quot;</span>
<span class="token key property">wgpu</span> <span class="token punctuation">=</span> <span class="token string">&quot;0.18&quot;</span>
<span class="token key property">bytemuck</span> <span class="token punctuation">=</span> <span class="token punctuation">{</span> <span class="token key property">version</span> <span class="token punctuation">=</span> <span class="token string">&quot;1.12&quot;</span><span class="token punctuation">,</span> <span class="token key property">features</span> <span class="token punctuation">=</span> <span class="token punctuation">[</span> <span class="token string">&quot;derive&quot;</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span>
<span class="token key property">anyhow</span> <span class="token punctuation">=</span> <span class="token string">&quot;1.0&quot;</span> <span class="token comment"># NEW!</span>
</code></pre></div><p>Then, in a new file called <code>src/texture.rs</code>, add the following:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">use</span> <span class="token namespace">image<span class="token punctuation">::</span></span><span class="token class-name">GenericImageView</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token namespace">anyhow<span class="token punctuation">::</span></span><span class="token operator">*</span><span class="token punctuation">;</span>
<span class="token keyword">pub</span> <span class="token keyword">struct</span> <span class="token type-definition class-name">Texture</span> <span class="token punctuation">{</span>
<span class="token keyword">pub</span> texture<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Texture</span><span class="token punctuation">,</span>
<span class="token keyword">pub</span> view<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">TextureView</span><span class="token punctuation">,</span>
<span class="token keyword">pub</span> sampler<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Sampler</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token keyword">impl</span> <span class="token class-name">Texture</span> <span class="token punctuation">{</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">from_bytes</span><span class="token punctuation">(</span>
device<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Device</span><span class="token punctuation">,</span>
queue<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Queue</span><span class="token punctuation">,</span>
bytes<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token punctuation">[</span><span class="token keyword">u8</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
label<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">str</span>
<span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">Result</span><span class="token operator">&lt;</span><span class="token keyword">Self</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">let</span> img <span class="token operator">=</span> <span class="token namespace">image<span class="token punctuation">::</span></span><span class="token function">load_from_memory</span><span class="token punctuation">(</span>bytes<span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">;</span>
<span class="token keyword">Self</span><span class="token punctuation">::</span><span class="token function">from_image</span><span class="token punctuation">(</span>device<span class="token punctuation">,</span> queue<span class="token punctuation">,</span> <span class="token operator">&amp;</span>img<span class="token punctuation">,</span> <span class="token class-name">Some</span><span class="token punctuation">(</span>label<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">from_image</span><span class="token punctuation">(</span>
device<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Device</span><span class="token punctuation">,</span>
queue<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Queue</span><span class="token punctuation">,</span>
img<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token namespace">image<span class="token punctuation">::</span></span><span class="token class-name">DynamicImage</span><span class="token punctuation">,</span>
label<span class="token punctuation">:</span> <span class="token class-name">Option</span><span class="token operator">&lt;</span><span class="token operator">&amp;</span><span class="token keyword">str</span><span class="token operator">&gt;</span>
<span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">Result</span><span class="token operator">&lt;</span><span class="token keyword">Self</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">let</span> rgba <span class="token operator">=</span> img<span class="token punctuation">.</span><span class="token function">to_rgba8</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> dimensions <span class="token operator">=</span> img<span class="token punctuation">.</span><span class="token function">dimensions</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> size <span class="token operator">=</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Extent3d</span> <span class="token punctuation">{</span>
width<span class="token punctuation">:</span> dimensions<span class="token number">.0</span><span class="token punctuation">,</span>
height<span class="token punctuation">:</span> dimensions<span class="token number">.1</span><span class="token punctuation">,</span>
depth_or_array_layers<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> texture <span class="token operator">=</span> device<span class="token punctuation">.</span><span class="token function">create_texture</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">TextureDescriptor</span> <span class="token punctuation">{</span>
label<span class="token punctuation">,</span>
size<span class="token punctuation">,</span>
mip_level_count<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span>
sample_count<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span>
dimension<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">TextureDimension</span><span class="token punctuation">::</span><span class="token constant">D2</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">TextureFormat</span><span class="token punctuation">::</span><span class="token class-name">Rgba8UnormSrgb</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">TextureUsages</span><span class="token punctuation">::</span><span class="token constant">TEXTURE_BINDING</span> <span class="token operator">|</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">TextureUsages</span><span class="token punctuation">::</span><span class="token constant">COPY_DST</span><span class="token punctuation">,</span>
view_formats<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
queue<span class="token punctuation">.</span><span class="token function">write_texture</span><span class="token punctuation">(</span>
<span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">ImageCopyTexture</span> <span class="token punctuation">{</span>
aspect<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">TextureAspect</span><span class="token punctuation">::</span><span class="token class-name">All</span><span class="token punctuation">,</span>
texture<span class="token punctuation">:</span> <span class="token operator">&amp;</span>texture<span class="token punctuation">,</span>
mip_level<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
origin<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Origin3d</span><span class="token punctuation">::</span><span class="token constant">ZERO</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token operator">&amp;</span>rgba<span class="token punctuation">,</span>
<span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">ImageDataLayout</span> <span class="token punctuation">{</span>
offset<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
bytes_per_row<span class="token punctuation">:</span> <span class="token class-name">Some</span><span class="token punctuation">(</span><span class="token number">4</span> <span class="token operator">*</span> dimensions<span class="token number">.0</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
rows_per_image<span class="token punctuation">:</span> <span class="token class-name">Some</span><span class="token punctuation">(</span>dimensions<span class="token number">.1</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
size<span class="token punctuation">,</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> view <span class="token operator">=</span> texture<span class="token punctuation">.</span><span class="token function">create_view</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">TextureViewDescriptor</span><span class="token punctuation">::</span><span class="token function">default</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> sampler <span class="token operator">=</span> device<span class="token punctuation">.</span><span class="token function">create_sampler</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">SamplerDescriptor</span> <span class="token punctuation">{</span>
address_mode_u<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">AddressMode</span><span class="token punctuation">::</span><span class="token class-name">ClampToEdge</span><span class="token punctuation">,</span>
address_mode_v<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">AddressMode</span><span class="token punctuation">::</span><span class="token class-name">ClampToEdge</span><span class="token punctuation">,</span>
address_mode_w<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">AddressMode</span><span class="token punctuation">::</span><span class="token class-name">ClampToEdge</span><span class="token punctuation">,</span>
mag_filter<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">FilterMode</span><span class="token punctuation">::</span><span class="token class-name">Linear</span><span class="token punctuation">,</span>
min_filter<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">FilterMode</span><span class="token punctuation">::</span><span class="token class-name">Nearest</span><span class="token punctuation">,</span>
mipmap_filter<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">FilterMode</span><span class="token punctuation">::</span><span class="token class-name">Nearest</span><span class="token punctuation">,</span>
<span class="token punctuation">..</span><span class="token class-name">Default</span><span class="token punctuation">::</span><span class="token function">default</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Ok</span><span class="token punctuation">(</span><span class="token keyword">Self</span> <span class="token punctuation">{</span> texture<span class="token punctuation">,</span> view<span class="token punctuation">,</span> sampler <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><div class="note"><p>Notice that we're using <code>to_rgba8()</code> instead of <code>as_rgba8()</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 an alpha channel even if the original image does not have one.</p></div> <p>We need to import <code>texture.rs</code> as a module, so at the top of <code>lib.rs</code> add the following.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">mod</span> <span class="token module-declaration namespace">texture</span><span class="token punctuation">;</span>
</code></pre></div><p>The texture creation code in <code>new()</code> now gets a lot simpler:</p> <div class="language-rust extra-class"><pre class="language-rust"><code>surface<span class="token punctuation">.</span><span class="token function">configure</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>device<span class="token punctuation">,</span> <span class="token operator">&amp;</span>config<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> diffuse_bytes <span class="token operator">=</span> <span class="token macro property">include_bytes!</span><span class="token punctuation">(</span><span class="token string">&quot;happy-tree.png&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// CHANGED!</span>
<span class="token keyword">let</span> diffuse_texture <span class="token operator">=</span> <span class="token namespace">texture<span class="token punctuation">::</span></span><span class="token class-name">Texture</span><span class="token punctuation">::</span><span class="token function">from_bytes</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>device<span class="token punctuation">,</span> <span class="token operator">&amp;</span>queue<span class="token punctuation">,</span> diffuse_bytes<span class="token punctuation">,</span> <span class="token string">&quot;happy-tree.png&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// CHANGED!</span>
<span class="token comment">// Everything up until `let texture_bind_group_layout = ...` can now be removed.</span>
</code></pre></div><p>We still need to store the bind group separately so that <code>Texture</code> doesn't need to know how the <code>BindGroup</code> is laid out. The creation of <code>diffuse_bind_group</code> slightly changes to use the <code>view</code> and <code>sampler</code> fields of <code>diffuse_texture</code>:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">let</span> diffuse_bind_group <span class="token operator">=</span> device<span class="token punctuation">.</span><span class="token function">create_bind_group</span><span class="token punctuation">(</span>
<span class="token operator">&amp;</span><span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BindGroupDescriptor</span> <span class="token punctuation">{</span>
layout<span class="token punctuation">:</span> <span class="token operator">&amp;</span>texture_bind_group_layout<span class="token punctuation">,</span>
entries<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token punctuation">[</span>
<span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BindGroupEntry</span> <span class="token punctuation">{</span>
binding<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
resource<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BindingResource</span><span class="token punctuation">::</span><span class="token class-name">TextureView</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>diffuse_texture<span class="token punctuation">.</span>view<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token comment">// CHANGED!</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BindGroupEntry</span> <span class="token punctuation">{</span>
binding<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span>
resource<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BindingResource</span><span class="token punctuation">::</span><span class="token class-name">Sampler</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>diffuse_texture<span class="token punctuation">.</span>sampler<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token comment">// CHANGED!</span>
<span class="token punctuation">}</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span>
label<span class="token punctuation">:</span> <span class="token class-name">Some</span><span class="token punctuation">(</span><span class="token string">&quot;diffuse_bind_group&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>Finally, let's update our <code>State</code> field to use our shiny new <code>Texture</code> struct, as we'll need it in future tutorials.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">struct</span> <span class="token type-definition class-name">State</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
diffuse_bind_group<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BindGroup</span><span class="token punctuation">,</span>
diffuse_texture<span class="token punctuation">:</span> <span class="token namespace">texture<span class="token punctuation">::</span></span><span class="token class-name">Texture</span><span class="token punctuation">,</span> <span class="token comment">// NEW</span>
<span class="token punctuation">}</span>
</code></pre></div><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><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">Self</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
num_indices<span class="token punctuation">,</span>
diffuse_bind_group<span class="token punctuation">,</span>
diffuse_texture<span class="token punctuation">,</span> <span class="token comment">// NEW</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>Phew!</p> <p>With these changes in place, the code should be working the same as before, but we now have a much easier way to create textures.</p> <h2 id="challenge"><a href="#challenge" class="header-anchor">#</a> Challenge</h2> <p>Create another texture and swap it out when you press the space key.</p> <div id="wasm-example"><!----> <button>Try Tutorial5_textures!</button></div> <div class="auto-github-link"><a href="https://github.com/sotrh/learn-wgpu/tree/master/code/beginner/tutorial5-textures/" target="_blank" rel="noopener noreferrer">Check out the code!</a> <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></div></div> <footer class="page-edit"><!----> <div class="last-updated"><span class="prefix">Last Updated: </span> <span class="time">1/20/2024, 10:13:50 PM</span></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
<a href="/learn-wgpu/beginner/tutorial4-buffer/" class="prev">
Buffers and Indices
</a></span> <span class="next"><a href="/learn-wgpu/beginner/tutorial6-uniforms/">
Uniform buffers and a 3d camera
</a>
</span></p></div> </main></div></div><div class="global-ui"><!----></div></div>
<script src="/learn-wgpu/assets/js/app.d7475ed3.js" defer></script><script src="/learn-wgpu/assets/js/2.1b0ff365.js" defer></script><script src="/learn-wgpu/assets/js/1.f95c152b.js" defer></script><script src="/learn-wgpu/assets/js/28.be489186.js" defer></script><script src="/learn-wgpu/assets/js/33.945dce62.js" defer></script><script src="/learn-wgpu/assets/js/37.5ecf7ce2.js" defer></script>
</body>
</html>