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/intermediate/tutorial12-camera/index.html

385 lines
88 KiB
HTML

<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>A Better Camera | Learn Wgpu</title>
<meta name="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.a49faced.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/2.2ef7287a.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/1.eaeeb819.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/44.27513d85.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/33.945dce62.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/37.5ecf7ce2.js" as="script"><link rel="prefetch" href="/learn-wgpu/assets/js/10.baf5d1fe.js"><link rel="prefetch" href="/learn-wgpu/assets/js/11.b8633c49.js"><link rel="prefetch" href="/learn-wgpu/assets/js/12.0b8835f1.js"><link rel="prefetch" href="/learn-wgpu/assets/js/13.af1bbe85.js"><link rel="prefetch" href="/learn-wgpu/assets/js/14.626c7cb3.js"><link rel="prefetch" href="/learn-wgpu/assets/js/15.5a8ea302.js"><link rel="prefetch" href="/learn-wgpu/assets/js/16.f4e8226b.js"><link rel="prefetch" href="/learn-wgpu/assets/js/17.dd15c417.js"><link rel="prefetch" href="/learn-wgpu/assets/js/18.4eb59bb5.js"><link rel="prefetch" href="/learn-wgpu/assets/js/19.48960e96.js"><link rel="prefetch" href="/learn-wgpu/assets/js/20.a01dc53f.js"><link rel="prefetch" href="/learn-wgpu/assets/js/21.5e81f33c.js"><link rel="prefetch" href="/learn-wgpu/assets/js/22.caf73498.js"><link rel="prefetch" href="/learn-wgpu/assets/js/23.a01d50ae.js"><link rel="prefetch" href="/learn-wgpu/assets/js/24.9ed2104b.js"><link rel="prefetch" href="/learn-wgpu/assets/js/25.1676676b.js"><link rel="prefetch" href="/learn-wgpu/assets/js/26.fd4eb8d5.js"><link rel="prefetch" href="/learn-wgpu/assets/js/27.914a9a40.js"><link rel="prefetch" href="/learn-wgpu/assets/js/28.77f7d987.js"><link rel="prefetch" href="/learn-wgpu/assets/js/29.ea2d6bbf.js"><link rel="prefetch" href="/learn-wgpu/assets/js/3.80d94795.js"><link rel="prefetch" href="/learn-wgpu/assets/js/30.c58683af.js"><link rel="prefetch" href="/learn-wgpu/assets/js/31.74bc1dea.js"><link rel="prefetch" href="/learn-wgpu/assets/js/32.e6627282.js"><link rel="prefetch" href="/learn-wgpu/assets/js/34.0fe8e5e4.js"><link rel="prefetch" href="/learn-wgpu/assets/js/35.7c607f94.js"><link rel="prefetch" href="/learn-wgpu/assets/js/36.e6a8b391.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.47515217.js"><link rel="prefetch" href="/learn-wgpu/assets/js/42.4caac867.js"><link rel="prefetch" href="/learn-wgpu/assets/js/43.ac6fc643.js"><link rel="prefetch" href="/learn-wgpu/assets/js/45.2ea5b108.js"><link rel="prefetch" href="/learn-wgpu/assets/js/46.e591bcb9.js"><link rel="prefetch" href="/learn-wgpu/assets/js/47.3a7bf317.js"><link rel="prefetch" href="/learn-wgpu/assets/js/48.0a15e622.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.820d6108.js"><link rel="prefetch" href="/learn-wgpu/assets/js/52.48268452.js"><link rel="prefetch" href="/learn-wgpu/assets/js/53.8c976652.js"><link rel="prefetch" href="/learn-wgpu/assets/js/54.daee63ce.js"><link rel="prefetch" href="/learn-wgpu/assets/js/55.3799ddaa.js"><link rel="prefetch" href="/learn-wgpu/assets/js/56.a43d5d8e.js"><link rel="prefetch" href="/learn-wgpu/assets/js/57.9cdfcb79.js"><link rel="prefetch" href="/learn-wgpu/assets/js/58.35b75a7b.js"><link rel="prefetch" href="/learn-wgpu/assets/js/59.5dd82339.js"><link rel="prefetch" href="/learn-wgpu/assets/js/60.1ced8124.js"><link rel="prefetch" href="/learn-wgpu/assets/js/61.f10516d3.js"><link rel="prefetch" href="/learn-wgpu/assets/js/62.24bfa87e.js"><link rel="prefetch" href="/learn-wgpu/assets/js/63.90f94cac.js"><link rel="prefetch" href="/learn-wgpu/assets/js/64.b9a310af.js"><link rel="prefetch" href="/learn-wgpu/assets/js/65.362df98e.js"><link rel="prefetch" href="/learn-wgpu/assets/js/66.ef1e3716.js"><link rel="prefetch" href="/learn-wgpu/assets/js/67.ab338058.js"><link rel="prefetch" href="/learn-wgpu/assets/js/68.d785413d.js"><link rel="prefetch" href="/learn-wgpu/assets/js/8.2c0d831a.js"><link rel="prefetch" href="/learn-wgpu/assets/js/9.985bc61a.js"><link rel="prefetch" href="/learn-wgpu/assets/js/vendors~docsearch.efa6f8ef.js">
<link rel="stylesheet" href="/learn-wgpu/assets/css/0.styles.81cb5453.css">
</head>
<body>
<div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="inner"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/learn-wgpu/" class="home-link router-link-active"><!----> <span class="site-name">Learn Wgpu</span></a> <div class="links"><!----> <div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div></div></div></header> <div class="sidebar-mask"></div> <div class="docs-layout"><aside class="sidebar"><!----> <ul class="sidebar-links"><li><a href="/learn-wgpu/" aria-current="page" class="sidebar-link">Introduction</a></li><li><section class="sidebar-group depth-0"><p class="sidebar-heading"><span>Beginner</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/learn-wgpu/beginner/tutorial1-window/" class="sidebar-link">Dependencies and the window</a></li><li><a href="/learn-wgpu/beginner/tutorial2-surface/" class="sidebar-link">The Surface</a></li><li><a href="/learn-wgpu/beginner/tutorial3-pipeline/" class="sidebar-link">The Pipeline</a></li><li><a href="/learn-wgpu/beginner/tutorial4-buffer/" class="sidebar-link">Buffers and Indices</a></li><li><a href="/learn-wgpu/beginner/tutorial5-textures/" class="sidebar-link">Textures and bind groups</a></li><li><a href="/learn-wgpu/beginner/tutorial6-uniforms/" class="sidebar-link">Uniform buffers and a 3d camera</a></li><li><a href="/learn-wgpu/beginner/tutorial7-instancing/" class="sidebar-link">Instancing</a></li><li><a href="/learn-wgpu/beginner/tutorial8-depth/" class="sidebar-link">The Depth Buffer</a></li><li><a href="/learn-wgpu/beginner/tutorial9-models/" class="sidebar-link">Model Loading</a></li></ul></section></li><li><section class="sidebar-group depth-0"><p class="sidebar-heading open"><span>Intermediate</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/learn-wgpu/intermediate/tutorial10-lighting/" class="sidebar-link">Working with Lights</a></li><li><a href="/learn-wgpu/intermediate/tutorial11-normals/" class="sidebar-link">Normal Mapping</a></li><li><a href="/learn-wgpu/intermediate/tutorial12-camera/" aria-current="page" class="active sidebar-link">A Better Camera</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/learn-wgpu/intermediate/tutorial12-camera/#the-camera" class="sidebar-link">The Camera</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/intermediate/tutorial12-camera/#the-projection" class="sidebar-link">The Projection</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/intermediate/tutorial12-camera/#cleaning-up-lib-rs" class="sidebar-link">Cleaning up lib.rs</a></li></ul></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="a-better-camera"><a href="#a-better-camera" class="header-anchor">#</a> A Better Camera</h1> <p>I've been putting this off for a while. Implementing a camera isn't specifically related to using WGPU properly, but it's been bugging me so let's do it.</p> <p><code>lib.rs</code> is getting a little crowded, so let's create a <code>camera.rs</code> file to put our camera code. The first things we're going to put in it are some imports and our <code>OPENGL_TO_WGPU_MATRIX</code>.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">use</span> <span class="token namespace">cgmath<span class="token punctuation">::</span></span><span class="token operator">*</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token namespace">winit<span class="token punctuation">::</span>event<span class="token punctuation">::</span></span><span class="token operator">*</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token namespace">winit<span class="token punctuation">::</span>dpi<span class="token punctuation">::</span></span><span class="token class-name">PhysicalPosition</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token namespace">instant<span class="token punctuation">::</span></span><span class="token class-name">Duration</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span></span><span class="token keyword">f32</span><span class="token punctuation">::</span><span class="token namespace">consts<span class="token punctuation">::</span></span><span class="token constant">FRAC_PI_2</span><span class="token punctuation">;</span>
<span class="token attribute attr-name">#[rustfmt::skip]</span>
<span class="token keyword">pub</span> <span class="token keyword">const</span> <span class="token constant">OPENGL_TO_WGPU_MATRIX</span><span class="token punctuation">:</span> <span class="token namespace">cgmath<span class="token punctuation">::</span></span><span class="token class-name">Matrix4</span><span class="token operator">&lt;</span><span class="token keyword">f32</span><span class="token operator">&gt;</span> <span class="token operator">=</span> <span class="token namespace">cgmath<span class="token punctuation">::</span></span><span class="token class-name">Matrix4</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span>
<span class="token number">1.0</span><span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">,</span>
<span class="token number">0.0</span><span class="token punctuation">,</span> <span class="token number">1.0</span><span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">,</span>
<span class="token number">0.0</span><span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">,</span> <span class="token number">0.5</span><span class="token punctuation">,</span> <span class="token number">0.5</span><span class="token punctuation">,</span>
<span class="token number">0.0</span><span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">,</span> <span class="token number">1.0</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token constant">SAFE_FRAC_PI_2</span><span class="token punctuation">:</span> <span class="token keyword">f32</span> <span class="token operator">=</span> <span class="token constant">FRAC_PI_2</span> <span class="token operator">-</span> <span class="token number">0.0001</span><span class="token punctuation">;</span>
</code></pre></div><div class="note"><p><code>std::time::Instant</code> panics on WASM, so we'll use the <a href="https://docs.rs/instant" target="_blank" rel="noopener noreferrer">instant 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>. You'll want to include it in your <code>Cargo.toml</code>:</p> <div class="language-toml extra-class"><pre class="language-toml"><code><span class="token key property">instant</span> <span class="token punctuation">=</span> <span class="token string">&quot;0.1&quot;</span>
</code></pre></div></div> <h2 id="the-camera"><a href="#the-camera" class="header-anchor">#</a> The Camera</h2> <p>Next, we need to create a new <code>Camera</code> struct. We're going to be using an FPS-style camera, so we'll store the position and the yaw (horizontal rotation), and pitch (vertical rotation). We'll have a <code>calc_matrix</code> method to create our view matrix.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token attribute attr-name">#[derive(Debug)]</span>
<span class="token keyword">pub</span> <span class="token keyword">struct</span> <span class="token type-definition class-name">Camera</span> <span class="token punctuation">{</span>
<span class="token keyword">pub</span> position<span class="token punctuation">:</span> <span class="token class-name">Point3</span><span class="token operator">&lt;</span><span class="token keyword">f32</span><span class="token operator">&gt;</span><span class="token punctuation">,</span>
yaw<span class="token punctuation">:</span> <span class="token class-name">Rad</span><span class="token operator">&lt;</span><span class="token keyword">f32</span><span class="token operator">&gt;</span><span class="token punctuation">,</span>
pitch<span class="token punctuation">:</span> <span class="token class-name">Rad</span><span class="token operator">&lt;</span><span class="token keyword">f32</span><span class="token operator">&gt;</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token keyword">impl</span> <span class="token class-name">Camera</span> <span class="token punctuation">{</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">new</span><span class="token operator">&lt;</span>
<span class="token class-name">V</span><span class="token punctuation">:</span> <span class="token class-name">Into</span><span class="token operator">&lt;</span><span class="token class-name">Point3</span><span class="token operator">&lt;</span><span class="token keyword">f32</span><span class="token operator">&gt;&gt;</span><span class="token punctuation">,</span>
<span class="token class-name">Y</span><span class="token punctuation">:</span> <span class="token class-name">Into</span><span class="token operator">&lt;</span><span class="token class-name">Rad</span><span class="token operator">&lt;</span><span class="token keyword">f32</span><span class="token operator">&gt;&gt;</span><span class="token punctuation">,</span>
<span class="token class-name">P</span><span class="token punctuation">:</span> <span class="token class-name">Into</span><span class="token operator">&lt;</span><span class="token class-name">Rad</span><span class="token operator">&lt;</span><span class="token keyword">f32</span><span class="token operator">&gt;&gt;</span><span class="token punctuation">,</span>
<span class="token operator">&gt;</span><span class="token punctuation">(</span>
position<span class="token punctuation">:</span> <span class="token class-name">V</span><span class="token punctuation">,</span>
yaw<span class="token punctuation">:</span> <span class="token class-name">Y</span><span class="token punctuation">,</span>
pitch<span class="token punctuation">:</span> <span class="token class-name">P</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">Self</span> <span class="token punctuation">{</span>
<span class="token keyword">Self</span> <span class="token punctuation">{</span>
position<span class="token punctuation">:</span> position<span class="token punctuation">.</span><span class="token function">into</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
yaw<span class="token punctuation">:</span> yaw<span class="token punctuation">.</span><span class="token function">into</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
pitch<span class="token punctuation">:</span> pitch<span class="token punctuation">.</span><span class="token function">into</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">calc_matrix</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">Matrix4</span><span class="token operator">&lt;</span><span class="token keyword">f32</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">let</span> <span class="token punctuation">(</span>sin_pitch<span class="token punctuation">,</span> cos_pitch<span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token keyword">self</span><span class="token punctuation">.</span>pitch<span class="token number">.0</span><span class="token punctuation">.</span><span class="token function">sin_cos</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 punctuation">(</span>sin_yaw<span class="token punctuation">,</span> cos_yaw<span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token keyword">self</span><span class="token punctuation">.</span>yaw<span class="token number">.0</span><span class="token punctuation">.</span><span class="token function">sin_cos</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Matrix4</span><span class="token punctuation">::</span><span class="token function">look_to_rh</span><span class="token punctuation">(</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>position<span class="token punctuation">,</span>
<span class="token class-name">Vector3</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span>
cos_pitch <span class="token operator">*</span> cos_yaw<span class="token punctuation">,</span>
sin_pitch<span class="token punctuation">,</span>
cos_pitch <span class="token operator">*</span> sin_yaw
<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">normalize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token class-name">Vector3</span><span class="token punctuation">::</span><span class="token function">unit_y</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><h2 id="the-projection"><a href="#the-projection" class="header-anchor">#</a> The Projection</h2> <p>I've decided to split the projection from the camera. The projection only really needs to change if the window resizes, so let's create a <code>Projection</code> struct.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">pub</span> <span class="token keyword">struct</span> <span class="token type-definition class-name">Projection</span> <span class="token punctuation">{</span>
aspect<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
fovy<span class="token punctuation">:</span> <span class="token class-name">Rad</span><span class="token operator">&lt;</span><span class="token keyword">f32</span><span class="token operator">&gt;</span><span class="token punctuation">,</span>
znear<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
zfar<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token keyword">impl</span> <span class="token class-name">Projection</span> <span class="token punctuation">{</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">new</span><span class="token operator">&lt;</span><span class="token class-name">F</span><span class="token punctuation">:</span> <span class="token class-name">Into</span><span class="token operator">&lt;</span><span class="token class-name">Rad</span><span class="token operator">&lt;</span><span class="token keyword">f32</span><span class="token operator">&gt;&gt;</span><span class="token operator">&gt;</span><span class="token punctuation">(</span>
width<span class="token punctuation">:</span> <span class="token keyword">u32</span><span class="token punctuation">,</span>
height<span class="token punctuation">:</span> <span class="token keyword">u32</span><span class="token punctuation">,</span>
fovy<span class="token punctuation">:</span> <span class="token class-name">F</span><span class="token punctuation">,</span>
znear<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
zfar<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">Self</span> <span class="token punctuation">{</span>
<span class="token keyword">Self</span> <span class="token punctuation">{</span>
aspect<span class="token punctuation">:</span> width <span class="token keyword">as</span> <span class="token keyword">f32</span> <span class="token operator">/</span> height <span class="token keyword">as</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
fovy<span class="token punctuation">:</span> fovy<span class="token punctuation">.</span><span class="token function">into</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
znear<span class="token punctuation">,</span>
zfar<span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">resize</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">,</span> width<span class="token punctuation">:</span> <span class="token keyword">u32</span><span class="token punctuation">,</span> height<span class="token punctuation">:</span> <span class="token keyword">u32</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>aspect <span class="token operator">=</span> width <span class="token keyword">as</span> <span class="token keyword">f32</span> <span class="token operator">/</span> height <span class="token keyword">as</span> <span class="token keyword">f32</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">calc_matrix</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">Matrix4</span><span class="token operator">&lt;</span><span class="token keyword">f32</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
<span class="token constant">OPENGL_TO_WGPU_MATRIX</span> <span class="token operator">*</span> <span class="token function">perspective</span><span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">.</span>fovy<span class="token punctuation">,</span> <span class="token keyword">self</span><span class="token punctuation">.</span>aspect<span class="token punctuation">,</span> <span class="token keyword">self</span><span class="token punctuation">.</span>znear<span class="token punctuation">,</span> <span class="token keyword">self</span><span class="token punctuation">.</span>zfar<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>One thing to note: <code>cgmath</code> currently returns a right-handed projection matrix from the <code>perspective</code> function. This means that the z-axis points out of the screen. If you want the z-axis to be <em>into</em> the screen (aka. a left-handed projection matrix), you'll have to code your own.</p> <p>You can tell the difference between a right-handed coordinate system and a left-handed one by using your hands. Point your thumb to the right. This is the x-axis. Point your pointer finger up. This is the y-axis. Extend your middle finger. This is the z-axis. On your right hand, your middle finger should be pointing towards you. On your left hand, it should be pointing away.</p> <p><img src="/learn-wgpu/assets/img/left_right_hand.ccabf5d0.gif" alt="./left_right_hand.gif"></p> <h1 id="the-camera-controller"><a href="#the-camera-controller" class="header-anchor">#</a> The Camera Controller</h1> <p>Our camera is different, so we'll need a new camera controller. Add the following to <code>camera.rs</code>.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token attribute attr-name">#[derive(Debug)]</span>
<span class="token keyword">pub</span> <span class="token keyword">struct</span> <span class="token type-definition class-name">CameraController</span> <span class="token punctuation">{</span>
amount_left<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
amount_right<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
amount_forward<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
amount_backward<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
amount_up<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
amount_down<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
rotate_horizontal<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
rotate_vertical<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
scroll<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
speed<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
sensitivity<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token keyword">impl</span> <span class="token class-name">CameraController</span> <span class="token punctuation">{</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">new</span><span class="token punctuation">(</span>speed<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span> sensitivity<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">Self</span> <span class="token punctuation">{</span>
<span class="token keyword">Self</span> <span class="token punctuation">{</span>
amount_left<span class="token punctuation">:</span> <span class="token number">0.0</span><span class="token punctuation">,</span>
amount_right<span class="token punctuation">:</span> <span class="token number">0.0</span><span class="token punctuation">,</span>
amount_forward<span class="token punctuation">:</span> <span class="token number">0.0</span><span class="token punctuation">,</span>
amount_backward<span class="token punctuation">:</span> <span class="token number">0.0</span><span class="token punctuation">,</span>
amount_up<span class="token punctuation">:</span> <span class="token number">0.0</span><span class="token punctuation">,</span>
amount_down<span class="token punctuation">:</span> <span class="token number">0.0</span><span class="token punctuation">,</span>
rotate_horizontal<span class="token punctuation">:</span> <span class="token number">0.0</span><span class="token punctuation">,</span>
rotate_vertical<span class="token punctuation">:</span> <span class="token number">0.0</span><span class="token punctuation">,</span>
scroll<span class="token punctuation">:</span> <span class="token number">0.0</span><span class="token punctuation">,</span>
speed<span class="token punctuation">,</span>
sensitivity<span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">process_keyboard</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">,</span> key<span class="token punctuation">:</span> <span class="token class-name">VirtualKeyCode</span><span class="token punctuation">,</span> state<span class="token punctuation">:</span> <span class="token class-name">ElementState</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">bool</span><span class="token punctuation">{</span>
<span class="token keyword">let</span> amount <span class="token operator">=</span> <span class="token keyword">if</span> state <span class="token operator">==</span> <span class="token class-name">ElementState</span><span class="token punctuation">::</span><span class="token class-name">Pressed</span> <span class="token punctuation">{</span> <span class="token number">1.0</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token number">0.0</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">match</span> key <span class="token punctuation">{</span>
<span class="token class-name">VirtualKeyCode</span><span class="token punctuation">::</span><span class="token class-name">W</span> <span class="token operator">|</span> <span class="token class-name">VirtualKeyCode</span><span class="token punctuation">::</span><span class="token class-name">Up</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>amount_forward <span class="token operator">=</span> amount<span class="token punctuation">;</span>
<span class="token boolean">true</span>
<span class="token punctuation">}</span>
<span class="token class-name">VirtualKeyCode</span><span class="token punctuation">::</span><span class="token class-name">S</span> <span class="token operator">|</span> <span class="token class-name">VirtualKeyCode</span><span class="token punctuation">::</span><span class="token class-name">Down</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>amount_backward <span class="token operator">=</span> amount<span class="token punctuation">;</span>
<span class="token boolean">true</span>
<span class="token punctuation">}</span>
<span class="token class-name">VirtualKeyCode</span><span class="token punctuation">::</span><span class="token class-name">A</span> <span class="token operator">|</span> <span class="token class-name">VirtualKeyCode</span><span class="token punctuation">::</span><span class="token class-name">Left</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>amount_left <span class="token operator">=</span> amount<span class="token punctuation">;</span>
<span class="token boolean">true</span>
<span class="token punctuation">}</span>
<span class="token class-name">VirtualKeyCode</span><span class="token punctuation">::</span><span class="token class-name">D</span> <span class="token operator">|</span> <span class="token class-name">VirtualKeyCode</span><span class="token punctuation">::</span><span class="token class-name">Right</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>amount_right <span class="token operator">=</span> amount<span class="token punctuation">;</span>
<span class="token boolean">true</span>
<span class="token punctuation">}</span>
<span class="token class-name">VirtualKeyCode</span><span class="token punctuation">::</span><span class="token class-name">Space</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>amount_up <span class="token operator">=</span> amount<span class="token punctuation">;</span>
<span class="token boolean">true</span>
<span class="token punctuation">}</span>
<span class="token class-name">VirtualKeyCode</span><span class="token punctuation">::</span><span class="token class-name">LShift</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>amount_down <span class="token operator">=</span> amount<span class="token punctuation">;</span>
<span class="token boolean">true</span>
<span class="token punctuation">}</span>
_ <span class="token operator">=&gt;</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">process_mouse</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">,</span> mouse_dx<span class="token punctuation">:</span> <span class="token keyword">f64</span><span class="token punctuation">,</span> mouse_dy<span class="token punctuation">:</span> <span class="token keyword">f64</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>rotate_horizontal <span class="token operator">=</span> mouse_dx <span class="token keyword">as</span> <span class="token keyword">f32</span><span class="token punctuation">;</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>rotate_vertical <span class="token operator">=</span> mouse_dy <span class="token keyword">as</span> <span class="token keyword">f32</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">process_scroll</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">,</span> delta<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token class-name">MouseScrollDelta</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>scroll <span class="token operator">=</span> <span class="token operator">-</span><span class="token keyword">match</span> delta <span class="token punctuation">{</span>
<span class="token comment">// I'm assuming a line is about 100 pixels</span>
<span class="token class-name">MouseScrollDelta</span><span class="token punctuation">::</span><span class="token class-name">LineDelta</span><span class="token punctuation">(</span>_<span class="token punctuation">,</span> scroll<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> scroll <span class="token operator">*</span> <span class="token number">100.0</span><span class="token punctuation">,</span>
<span class="token class-name">MouseScrollDelta</span><span class="token punctuation">::</span><span class="token class-name">PixelDelta</span><span class="token punctuation">(</span><span class="token class-name">PhysicalPosition</span> <span class="token punctuation">{</span>
y<span class="token punctuation">:</span> scroll<span class="token punctuation">,</span>
<span class="token punctuation">..</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token operator">*</span>scroll <span class="token keyword">as</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">update_camera</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">,</span> camera<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token class-name">Camera</span><span class="token punctuation">,</span> dt<span class="token punctuation">:</span> <span class="token class-name">Duration</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">let</span> dt <span class="token operator">=</span> dt<span class="token punctuation">.</span><span class="token function">as_secs_f32</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Move forward/backward and left/right</span>
<span class="token keyword">let</span> <span class="token punctuation">(</span>yaw_sin<span class="token punctuation">,</span> yaw_cos<span class="token punctuation">)</span> <span class="token operator">=</span> camera<span class="token punctuation">.</span>yaw<span class="token number">.0</span><span class="token punctuation">.</span><span class="token function">sin_cos</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> forward <span class="token operator">=</span> <span class="token class-name">Vector3</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span>yaw_cos<span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">,</span> yaw_sin<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">normalize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> right <span class="token operator">=</span> <span class="token class-name">Vector3</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token operator">-</span>yaw_sin<span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">,</span> yaw_cos<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">normalize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
camera<span class="token punctuation">.</span>position <span class="token operator">+=</span> forward <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">.</span>amount_forward <span class="token operator">-</span> <span class="token keyword">self</span><span class="token punctuation">.</span>amount_backward<span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token keyword">self</span><span class="token punctuation">.</span>speed <span class="token operator">*</span> dt<span class="token punctuation">;</span>
camera<span class="token punctuation">.</span>position <span class="token operator">+=</span> right <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">.</span>amount_right <span class="token operator">-</span> <span class="token keyword">self</span><span class="token punctuation">.</span>amount_left<span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token keyword">self</span><span class="token punctuation">.</span>speed <span class="token operator">*</span> dt<span class="token punctuation">;</span>
<span class="token comment">// Move in/out (aka. &quot;zoom&quot;)</span>
<span class="token comment">// Note: this isn't an actual zoom. The camera's position</span>
<span class="token comment">// changes when zooming. I've added this to make it easier</span>
<span class="token comment">// to get closer to an object you want to focus on.</span>
<span class="token keyword">let</span> <span class="token punctuation">(</span>pitch_sin<span class="token punctuation">,</span> pitch_cos<span class="token punctuation">)</span> <span class="token operator">=</span> camera<span class="token punctuation">.</span>pitch<span class="token number">.0</span><span class="token punctuation">.</span><span class="token function">sin_cos</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> scrollward <span class="token operator">=</span> <span class="token class-name">Vector3</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span>pitch_cos <span class="token operator">*</span> yaw_cos<span class="token punctuation">,</span> pitch_sin<span class="token punctuation">,</span> pitch_cos <span class="token operator">*</span> yaw_sin<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">normalize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
camera<span class="token punctuation">.</span>position <span class="token operator">+=</span> scrollward <span class="token operator">*</span> <span class="token keyword">self</span><span class="token punctuation">.</span>scroll <span class="token operator">*</span> <span class="token keyword">self</span><span class="token punctuation">.</span>speed <span class="token operator">*</span> <span class="token keyword">self</span><span class="token punctuation">.</span>sensitivity <span class="token operator">*</span> dt<span class="token punctuation">;</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>scroll <span class="token operator">=</span> <span class="token number">0.0</span><span class="token punctuation">;</span>
<span class="token comment">// Move up/down. Since we don't use roll, we can just</span>
<span class="token comment">// modify the y coordinate directly.</span>
camera<span class="token punctuation">.</span>position<span class="token punctuation">.</span>y <span class="token operator">+=</span> <span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">.</span>amount_up <span class="token operator">-</span> <span class="token keyword">self</span><span class="token punctuation">.</span>amount_down<span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token keyword">self</span><span class="token punctuation">.</span>speed <span class="token operator">*</span> dt<span class="token punctuation">;</span>
<span class="token comment">// Rotate</span>
camera<span class="token punctuation">.</span>yaw <span class="token operator">+=</span> <span class="token class-name">Rad</span><span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">.</span>rotate_horizontal<span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token keyword">self</span><span class="token punctuation">.</span>sensitivity <span class="token operator">*</span> dt<span class="token punctuation">;</span>
camera<span class="token punctuation">.</span>pitch <span class="token operator">+=</span> <span class="token class-name">Rad</span><span class="token punctuation">(</span><span class="token operator">-</span><span class="token keyword">self</span><span class="token punctuation">.</span>rotate_vertical<span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token keyword">self</span><span class="token punctuation">.</span>sensitivity <span class="token operator">*</span> dt<span class="token punctuation">;</span>
<span class="token comment">// If process_mouse isn't called every frame, these values</span>
<span class="token comment">// will not get set to zero, and the camera will rotate</span>
<span class="token comment">// when moving in a non cardinal direction.</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>rotate_horizontal <span class="token operator">=</span> <span class="token number">0.0</span><span class="token punctuation">;</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>rotate_vertical <span class="token operator">=</span> <span class="token number">0.0</span><span class="token punctuation">;</span>
<span class="token comment">// Keep the camera's angle from going too high/low.</span>
<span class="token keyword">if</span> camera<span class="token punctuation">.</span>pitch <span class="token operator">&lt;</span> <span class="token operator">-</span><span class="token class-name">Rad</span><span class="token punctuation">(</span><span class="token constant">SAFE_FRAC_PI_2</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
camera<span class="token punctuation">.</span>pitch <span class="token operator">=</span> <span class="token operator">-</span><span class="token class-name">Rad</span><span class="token punctuation">(</span><span class="token constant">SAFE_FRAC_PI_2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> camera<span class="token punctuation">.</span>pitch <span class="token operator">&gt;</span> <span class="token class-name">Rad</span><span class="token punctuation">(</span><span class="token constant">SAFE_FRAC_PI_2</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
camera<span class="token punctuation">.</span>pitch <span class="token operator">=</span> <span class="token class-name">Rad</span><span class="token punctuation">(</span><span class="token constant">SAFE_FRAC_PI_2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><h2 id="cleaning-up-lib-rs"><a href="#cleaning-up-lib-rs" class="header-anchor">#</a> Cleaning up <code>lib.rs</code></h2> <p>First things first we need to delete <code>Camera</code> and <code>CameraController</code> as well as the extra <code>OPENGL_TO_WGPU_MATRIX</code> from <code>lib.rs</code>. Once you've done that import <code>camera.rs</code>.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">mod</span> <span class="token module-declaration namespace">model</span><span class="token punctuation">;</span>
<span class="token keyword">mod</span> <span class="token module-declaration namespace">texture</span><span class="token punctuation">;</span>
<span class="token keyword">mod</span> <span class="token module-declaration namespace">camera</span><span class="token punctuation">;</span> <span class="token comment">// NEW!</span>
</code></pre></div><p>We need to update <code>update_view_proj</code> to use our new <code>Camera</code> and <code>Projection</code>.</p> <div class="language-rust extra-class"><pre class="language-rust"><code>
<span class="token keyword">impl</span> <span class="token class-name">CameraUniform</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
<span class="token comment">// UPDATED!</span>
<span class="token keyword">fn</span> <span class="token function-definition function">update_view_proj</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">,</span> camera<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token namespace">camera<span class="token punctuation">::</span></span><span class="token class-name">Camera</span><span class="token punctuation">,</span> projection<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token namespace">camera<span class="token punctuation">::</span></span><span class="token class-name">Projection</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>view_position <span class="token operator">=</span> camera<span class="token punctuation">.</span>position<span class="token punctuation">.</span><span class="token function">to_homogeneous</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">into</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>view_proj <span class="token operator">=</span> <span class="token punctuation">(</span>projection<span class="token punctuation">.</span><span class="token function">calc_matrix</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">*</span> camera<span class="token punctuation">.</span><span class="token function">calc_matrix</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">into</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>We need to change our <code>State</code> to use our <code>Camera</code>, <code>CameraProjection</code> and <code>Projection</code> as well. We'll also add a <code>mouse_pressed</code> field to store whether the mouse was pressed.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">struct</span> <span class="token type-definition class-name">State</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
camera<span class="token punctuation">:</span> <span class="token namespace">camera<span class="token punctuation">::</span></span><span class="token class-name">Camera</span><span class="token punctuation">,</span> <span class="token comment">// UPDATED!</span>
projection<span class="token punctuation">:</span> <span class="token namespace">camera<span class="token punctuation">::</span></span><span class="token class-name">Projection</span><span class="token punctuation">,</span> <span class="token comment">// NEW!</span>
camera_controller<span class="token punctuation">:</span> <span class="token namespace">camera<span class="token punctuation">::</span></span><span class="token class-name">CameraController</span><span class="token punctuation">,</span> <span class="token comment">// UPDATED!</span>
<span class="token comment">// ...</span>
<span class="token comment">// NEW!</span>
mouse_pressed<span class="token punctuation">:</span> <span class="token keyword">bool</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
</code></pre></div><p>You'll need to import <code>winit::dpi::PhysicalPosition</code> if you haven't already.</p> <p>We need to update <code>new()</code> as well.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">impl</span> <span class="token class-name">State</span> <span class="token punctuation">{</span>
<span class="token keyword">async</span> <span class="token keyword">fn</span> <span class="token function-definition function">new</span><span class="token punctuation">(</span>window<span class="token punctuation">:</span> <span class="token class-name">Window</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">Self</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
<span class="token comment">// UPDATED!</span>
<span class="token keyword">let</span> camera <span class="token operator">=</span> <span class="token namespace">camera<span class="token punctuation">::</span></span><span class="token class-name">Camera</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token number">0.0</span><span class="token punctuation">,</span> <span class="token number">5.0</span><span class="token punctuation">,</span> <span class="token number">10.0</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token namespace">cgmath<span class="token punctuation">::</span></span><span class="token class-name">Deg</span><span class="token punctuation">(</span><span class="token operator">-</span><span class="token number">90.0</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token namespace">cgmath<span class="token punctuation">::</span></span><span class="token class-name">Deg</span><span class="token punctuation">(</span><span class="token operator">-</span><span class="token number">20.0</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> projection <span class="token operator">=</span> <span class="token namespace">camera<span class="token punctuation">::</span></span><span class="token class-name">Projection</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span>config<span class="token punctuation">.</span>width<span class="token punctuation">,</span> config<span class="token punctuation">.</span>height<span class="token punctuation">,</span> <span class="token namespace">cgmath<span class="token punctuation">::</span></span><span class="token class-name">Deg</span><span class="token punctuation">(</span><span class="token number">45.0</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">0.1</span><span class="token punctuation">,</span> <span class="token number">100.0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> camera_controller <span class="token operator">=</span> <span class="token namespace">camera<span class="token punctuation">::</span></span><span class="token class-name">CameraController</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token number">4.0</span><span class="token punctuation">,</span> <span class="token number">0.4</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// ...</span>
camera_uniform<span class="token punctuation">.</span><span class="token function">update_view_proj</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>camera<span class="token punctuation">,</span> <span class="token operator">&amp;</span>projection<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// UPDATED!</span>
<span class="token comment">// ...</span>
<span class="token keyword">Self</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
camera<span class="token punctuation">,</span>
projection<span class="token punctuation">,</span> <span class="token comment">// NEW!</span>
camera_controller<span class="token punctuation">,</span>
<span class="token comment">// ...</span>
mouse_pressed<span class="token punctuation">:</span> <span class="token boolean">false</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>
</code></pre></div><p>We need to change our <code>projection</code> in <code>resize</code> as well.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">fn</span> <span class="token function-definition function">resize</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">,</span> new_size<span class="token punctuation">:</span> <span class="token namespace">winit<span class="token punctuation">::</span>dpi<span class="token punctuation">::</span></span><span class="token class-name">PhysicalSize</span><span class="token operator">&lt;</span><span class="token keyword">u32</span><span class="token operator">&gt;</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// UPDATED!</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>projection<span class="token punctuation">.</span><span class="token function">resize</span><span class="token punctuation">(</span>new_size<span class="token punctuation">.</span>width<span class="token punctuation">,</span> new_size<span class="token punctuation">.</span>height<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// ...</span>
<span class="token punctuation">}</span>
</code></pre></div><p><code>input()</code> will need to be updated as well. Up to this point, we have been using <code>WindowEvent</code>s for our camera controls. While this works, it's not the best solution. The <a href="https://docs.rs/winit/0.24.0/winit/event/enum.WindowEvent.html?search=#variant.CursorMoved" target="_blank" rel="noopener noreferrer">winit docs<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><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> inform us that OS will often transform the data for the <code>CursorMoved</code> event to allow effects such as cursor acceleration.</p> <p>Now to fix this we could change the <code>input()</code> function to process <code>DeviceEvent</code> instead of <code>WindowEvent</code>, but keyboard and button presses don't get emitted as <code>DeviceEvent</code>s on MacOS and WASM. Instead, we'll just remove the <code>CursorMoved</code> check in <code>input()</code>, and a manual call to <code>camera_controller.process_mouse()</code> in the <code>run()</code> function.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token comment">// UPDATED!</span>
<span class="token keyword">fn</span> <span class="token function-definition function">input</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">,</span> event<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token class-name">WindowEvent</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">bool</span> <span class="token punctuation">{</span>
<span class="token keyword">match</span> event <span class="token punctuation">{</span>
<span class="token class-name">WindowEvent</span><span class="token punctuation">::</span><span class="token class-name">KeyboardInput</span> <span class="token punctuation">{</span>
input<span class="token punctuation">:</span>
<span class="token class-name">KeyboardInput</span> <span class="token punctuation">{</span>
virtual_keycode<span class="token punctuation">:</span> <span class="token class-name">Some</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span><span class="token punctuation">,</span>
state<span class="token punctuation">,</span>
<span class="token punctuation">..</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">..</span>
<span class="token punctuation">}</span> <span class="token operator">=&gt;</span> <span class="token keyword">self</span><span class="token punctuation">.</span>camera_controller<span class="token punctuation">.</span><span class="token function">process_keyboard</span><span class="token punctuation">(</span><span class="token operator">*</span>key<span class="token punctuation">,</span> <span class="token operator">*</span>state<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token class-name">WindowEvent</span><span class="token punctuation">::</span><span class="token class-name">MouseWheel</span> <span class="token punctuation">{</span> delta<span class="token punctuation">,</span> <span class="token punctuation">..</span> <span class="token punctuation">}</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>camera_controller<span class="token punctuation">.</span><span class="token function">process_scroll</span><span class="token punctuation">(</span>delta<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token boolean">true</span>
<span class="token punctuation">}</span>
<span class="token class-name">WindowEvent</span><span class="token punctuation">::</span><span class="token class-name">MouseInput</span> <span class="token punctuation">{</span>
button<span class="token punctuation">:</span> <span class="token class-name">MouseButton</span><span class="token punctuation">::</span><span class="token class-name">Left</span><span class="token punctuation">,</span>
state<span class="token punctuation">,</span>
<span class="token punctuation">..</span>
<span class="token punctuation">}</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>mouse_pressed <span class="token operator">=</span> <span class="token operator">*</span>state <span class="token operator">==</span> <span class="token class-name">ElementState</span><span class="token punctuation">::</span><span class="token class-name">Pressed</span><span class="token punctuation">;</span>
<span class="token boolean">true</span>
<span class="token punctuation">}</span>
_ <span class="token operator">=&gt;</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>Here are the changes to <code>run()</code>:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">fn</span> <span class="token function-definition function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
event_loop<span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token keyword">move</span> <span class="token closure-params"><span class="token closure-punctuation punctuation">|</span>event<span class="token punctuation">,</span> _<span class="token punctuation">,</span> control_flow<span class="token closure-punctuation punctuation">|</span></span> <span class="token punctuation">{</span>
<span class="token operator">*</span>control_flow <span class="token operator">=</span> <span class="token class-name">ControlFlow</span><span class="token punctuation">::</span><span class="token class-name">Poll</span><span class="token punctuation">;</span>
<span class="token keyword">match</span> event <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
<span class="token comment">// NEW!</span>
<span class="token class-name">Event</span><span class="token punctuation">::</span><span class="token class-name">DeviceEvent</span> <span class="token punctuation">{</span>
event<span class="token punctuation">:</span> <span class="token class-name">DeviceEvent</span><span class="token punctuation">::</span><span class="token class-name">MouseMotion</span><span class="token punctuation">{</span> delta<span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">..</span> <span class="token comment">// We're not using device_id currently</span>
<span class="token punctuation">}</span> <span class="token operator">=&gt;</span> <span class="token keyword">if</span> state<span class="token punctuation">.</span>mouse_pressed <span class="token punctuation">{</span>
state<span class="token punctuation">.</span>camera_controller<span class="token punctuation">.</span><span class="token function">process_mouse</span><span class="token punctuation">(</span>delta<span class="token number">.0</span><span class="token punctuation">,</span> delta<span class="token number">.1</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token comment">// UPDATED!</span>
<span class="token class-name">Event</span><span class="token punctuation">::</span><span class="token class-name">WindowEvent</span> <span class="token punctuation">{</span>
<span class="token keyword">ref</span> event<span class="token punctuation">,</span>
window_id<span class="token punctuation">,</span>
<span class="token punctuation">}</span> <span class="token keyword">if</span> window_id <span class="token operator">==</span> state<span class="token punctuation">.</span><span class="token function">window</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">id</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span>state<span class="token punctuation">.</span><span class="token function">input</span><span class="token punctuation">(</span>event<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">match</span> event <span class="token punctuation">{</span>
<span class="token attribute attr-name">#[cfg(not(target_arch=<span class="token string">&quot;wasm32&quot;</span>))]</span>
<span class="token class-name">WindowEvent</span><span class="token punctuation">::</span><span class="token class-name">CloseRequested</span>
<span class="token operator">|</span> <span class="token class-name">WindowEvent</span><span class="token punctuation">::</span><span class="token class-name">KeyboardInput</span> <span class="token punctuation">{</span>
input<span class="token punctuation">:</span>
<span class="token class-name">KeyboardInput</span> <span class="token punctuation">{</span>
state<span class="token punctuation">:</span> <span class="token class-name">ElementState</span><span class="token punctuation">::</span><span class="token class-name">Pressed</span><span class="token punctuation">,</span>
virtual_keycode<span class="token punctuation">:</span> <span class="token class-name">Some</span><span class="token punctuation">(</span><span class="token class-name">VirtualKeyCode</span><span class="token punctuation">::</span><span class="token class-name">Escape</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">..</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">..</span>
<span class="token punctuation">}</span> <span class="token operator">=&gt;</span> <span class="token operator">*</span>control_flow <span class="token operator">=</span> <span class="token class-name">ControlFlow</span><span class="token punctuation">::</span><span class="token class-name">Exit</span><span class="token punctuation">,</span>
<span class="token class-name">WindowEvent</span><span class="token punctuation">::</span><span class="token class-name">Resized</span><span class="token punctuation">(</span>physical_size<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
state<span class="token punctuation">.</span><span class="token function">resize</span><span class="token punctuation">(</span><span class="token operator">*</span>physical_size<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token class-name">WindowEvent</span><span class="token punctuation">::</span><span class="token class-name">ScaleFactorChanged</span> <span class="token punctuation">{</span> new_inner_size<span class="token punctuation">,</span> <span class="token punctuation">..</span> <span class="token punctuation">}</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
state<span class="token punctuation">.</span><span class="token function">resize</span><span class="token punctuation">(</span><span class="token operator">*</span><span class="token operator">*</span>new_inner_size<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
_ <span class="token operator">=&gt;</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token comment">// ...</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>The <code>update</code> function requires a bit more explanation. The <code>update_camera</code> function on the <code>CameraController</code> has a parameter <code>dt: Duration</code> which is the delta time or time between frames. This is to help smooth out the camera movement so that it's not locked by the framerate. Currently, we aren't calculating <code>dt</code>, so I decided to pass it into <code>update</code> as a parameter.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">fn</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">,</span> dt<span class="token punctuation">:</span> <span class="token namespace">instant<span class="token punctuation">::</span></span><span class="token class-name">Duration</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// UPDATED!</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>camera_controller<span class="token punctuation">.</span><span class="token function">update_camera</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">.</span>camera<span class="token punctuation">,</span> dt<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>camera_uniform<span class="token punctuation">.</span><span class="token function">update_view_proj</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">.</span>camera<span class="token punctuation">,</span> <span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">.</span>projection<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// ..</span>
<span class="token punctuation">}</span>
</code></pre></div><p>While we're at it, let's use <code>dt</code> for the light's rotation as well.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">self</span><span class="token punctuation">.</span>light_uniform<span class="token punctuation">.</span>position <span class="token operator">=</span>
<span class="token punctuation">(</span><span class="token namespace">cgmath<span class="token punctuation">::</span></span><span class="token class-name">Quaternion</span><span class="token punctuation">::</span><span class="token function">from_axis_angle</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token number">0.0</span><span class="token punctuation">,</span> <span class="token number">1.0</span><span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">into</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token namespace">cgmath<span class="token punctuation">::</span></span><span class="token class-name">Deg</span><span class="token punctuation">(</span><span class="token number">60.0</span> <span class="token operator">*</span> dt<span class="token punctuation">.</span><span class="token function">as_secs_f32</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token operator">*</span> old_position<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">into</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// UPDATED!</span>
</code></pre></div><p>We still need to calculate <code>dt</code>. Let's do that in the <code>main</code> function.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">fn</span> <span class="token function-definition function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
<span class="token keyword">let</span> <span class="token keyword">mut</span> state <span class="token operator">=</span> <span class="token class-name">State</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span>window<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token keyword">await</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> <span class="token keyword">mut</span> last_render_time <span class="token operator">=</span> <span class="token namespace">instant<span class="token punctuation">::</span></span><span class="token class-name">Instant</span><span class="token punctuation">::</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// NEW!</span>
event_loop<span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token keyword">move</span> <span class="token closure-params"><span class="token closure-punctuation punctuation">|</span>event<span class="token punctuation">,</span> _<span class="token punctuation">,</span> control_flow<span class="token closure-punctuation punctuation">|</span></span> <span class="token punctuation">{</span>
<span class="token operator">*</span>control_flow <span class="token operator">=</span> <span class="token class-name">ControlFlow</span><span class="token punctuation">::</span><span class="token class-name">Poll</span><span class="token punctuation">;</span>
<span class="token keyword">match</span> event <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
<span class="token comment">// UPDATED!</span>
<span class="token class-name">Event</span><span class="token punctuation">::</span><span class="token class-name">RedrawRequested</span><span class="token punctuation">(</span>window_id<span class="token punctuation">)</span> <span class="token keyword">if</span> window_id <span class="token operator">==</span> state<span class="token punctuation">.</span><span class="token function">window</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">id</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">let</span> now <span class="token operator">=</span> <span class="token namespace">instant<span class="token punctuation">::</span></span><span class="token class-name">Instant</span><span class="token punctuation">::</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> dt <span class="token operator">=</span> now <span class="token operator">-</span> last_render_time<span class="token punctuation">;</span>
last_render_time <span class="token operator">=</span> now<span class="token punctuation">;</span>
state<span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span>dt<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// ...</span>
<span class="token punctuation">}</span>
_ <span class="token operator">=&gt;</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>With that, we should be able to move our camera wherever we want.</p> <p><img src="/learn-wgpu/assets/img/screenshot.4f5740bc.png" alt="./screenshot.png"></p> <div id="wasm-example"><!----> <button>Try Tutorial12_camera!</button></div> <div class="auto-github-link"><a href="https://github.com/sotrh/learn-wgpu/tree/master/code/intermediate/tutorial12-camera/" target="_blank" rel="noopener noreferrer">Check out the code!</a> <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></div></div> <footer class="page-edit"><!----> <div class="last-updated"><span class="prefix">Last Updated: </span> <span class="time">11/28/2023, 12:41:28 AM</span></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
<a href="/learn-wgpu/intermediate/tutorial11-normals/" class="prev">
Normal Mapping
</a></span> <span class="next"><a href="/learn-wgpu/intermediate/tutorial13-hdr/">
High Dynamic Range Rendering
</a>
</span></p></div> </main></div></div><div class="global-ui"><!----></div></div>
<script src="/learn-wgpu/assets/js/app.a49faced.js" defer></script><script src="/learn-wgpu/assets/js/2.2ef7287a.js" defer></script><script src="/learn-wgpu/assets/js/1.eaeeb819.js" defer></script><script src="/learn-wgpu/assets/js/44.27513d85.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>