learn-wgpu/intermediate/tutorial12-camera/index.html
2020-12-21 04:07:41 +00:00

379 lines
82 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="description" content="">
<meta name="generator" content="VuePress 1.4.0">
<meta property="article:modified_time" content="2020-11-25T23:51:22.000Z"><meta property="og:site_name" content="Learn Wgpu"><meta property="og:title" content="A Better Camera"><meta property="og:type" content="website"><meta property="og:url" content="/intermediate/tutorial12-camera/"><meta name="twitter:title" content="A Better Camera"><meta name="twitter:url" content="/intermediate/tutorial12-camera/"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:label1" content="Written by"><meta name="twitter:data2" content="Benjamin R Hansen"><meta name="twitter:creator" content="https://twitter.com/sotrh760">
<link rel="preload" href="/learn-wgpu/assets/css/0.styles.7acc6ef6.css" as="style"><link rel="preload" href="/learn-wgpu/assets/js/app.8a1973b9.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/2.da3fd46f.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/14.f852c057.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/22.2132e362.js" as="script"><link rel="prefetch" href="/learn-wgpu/assets/js/10.de8cadfb.js"><link rel="prefetch" href="/learn-wgpu/assets/js/11.c7578bf2.js"><link rel="prefetch" href="/learn-wgpu/assets/js/12.ff5e5057.js"><link rel="prefetch" href="/learn-wgpu/assets/js/13.7bbdc3ca.js"><link rel="prefetch" href="/learn-wgpu/assets/js/15.2f129ccf.js"><link rel="prefetch" href="/learn-wgpu/assets/js/16.c7356fb1.js"><link rel="prefetch" href="/learn-wgpu/assets/js/17.8d0c6c00.js"><link rel="prefetch" href="/learn-wgpu/assets/js/18.bd274f60.js"><link rel="prefetch" href="/learn-wgpu/assets/js/19.1095b69a.js"><link rel="prefetch" href="/learn-wgpu/assets/js/20.70e640cc.js"><link rel="prefetch" href="/learn-wgpu/assets/js/21.e1893fb6.js"><link rel="prefetch" href="/learn-wgpu/assets/js/23.1a88f225.js"><link rel="prefetch" href="/learn-wgpu/assets/js/24.585372be.js"><link rel="prefetch" href="/learn-wgpu/assets/js/25.2166e585.js"><link rel="prefetch" href="/learn-wgpu/assets/js/26.462b84fd.js"><link rel="prefetch" href="/learn-wgpu/assets/js/27.04f788d9.js"><link rel="prefetch" href="/learn-wgpu/assets/js/28.a3ac06e2.js"><link rel="prefetch" href="/learn-wgpu/assets/js/29.281013fa.js"><link rel="prefetch" href="/learn-wgpu/assets/js/3.94d0aff7.js"><link rel="prefetch" href="/learn-wgpu/assets/js/30.dc887be9.js"><link rel="prefetch" href="/learn-wgpu/assets/js/4.1a5062fd.js"><link rel="prefetch" href="/learn-wgpu/assets/js/5.8c5056b6.js"><link rel="prefetch" href="/learn-wgpu/assets/js/6.395995ac.js"><link rel="prefetch" href="/learn-wgpu/assets/js/7.3b9d8029.js"><link rel="prefetch" href="/learn-wgpu/assets/js/8.635ef929.js"><link rel="prefetch" href="/learn-wgpu/assets/js/9.ecb6e79c.js">
<link rel="stylesheet" href="/learn-wgpu/assets/css/0.styles.7acc6ef6.css">
</head>
<body>
<div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="inner"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/learn-wgpu/" class="home-link router-link-active"><!----> <span class="site-name">Learn Wgpu</span></a> <div class="links"><!----> <div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div></div></div></header> <div class="sidebar-mask"></div> <div class="docs-layout"><aside class="sidebar"><!----> <ul class="sidebar-links"><li><a href="/learn-wgpu/" class="sidebar-link">Introduction</a></li><li><section class="sidebar-group depth-0"><p class="sidebar-heading"><span>Beginner</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/learn-wgpu/beginner/tutorial1-window/" class="sidebar-link">Dependencies and the window</a></li><li><a href="/learn-wgpu/beginner/tutorial2-swapchain/" class="sidebar-link">The Swapchain</a></li><li><a href="/learn-wgpu/beginner/tutorial3-pipeline/" class="sidebar-link">The Pipeline</a></li><li><a href="/learn-wgpu/beginner/tutorial4-buffer/" class="sidebar-link">Buffers and Indices</a></li><li><a href="/learn-wgpu/beginner/tutorial5-textures/" class="sidebar-link">Textures and bind groups</a></li><li><a href="/learn-wgpu/beginner/tutorial6-uniforms/" class="sidebar-link">Uniform buffers and a 3d camera</a></li><li><a href="/learn-wgpu/beginner/tutorial7-instancing/" class="sidebar-link">Instancing</a></li><li><a href="/learn-wgpu/beginner/tutorial8-depth/" class="sidebar-link">The Depth Buffer</a></li><li><a href="/learn-wgpu/beginner/tutorial9-models/" class="sidebar-link">Model Loading</a></li></ul></section></li><li><section class="sidebar-group depth-0"><p class="sidebar-heading open"><span>Intermediate</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/learn-wgpu/intermediate/tutorial10-lighting/" class="sidebar-link">Working with Lights</a></li><li><a href="/learn-wgpu/intermediate/tutorial11-normals/" class="sidebar-link">Normal Mapping</a></li><li><a href="/learn-wgpu/intermediate/tutorial12-camera/" class="active sidebar-link">A Better Camera</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/learn-wgpu/intermediate/tutorial12-camera/#the-camera" class="sidebar-link">The Camera</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/intermediate/tutorial12-camera/#the-projection" class="sidebar-link">The Projection</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/intermediate/tutorial12-camera/#cleaning-up-main-rs" class="sidebar-link">Cleaning up main.rs</a></li></ul></li><li><a href="/learn-wgpu/intermediate/tutorial13-threading/" class="sidebar-link">Multi-threading with Wgpu and Rayon</a></li></ul></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>Showcase</span> <span class="arrow right"></span></p> <!----></section></li><li><a href="/learn-wgpu/news/" class="sidebar-link">News</a></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><h1 id="a-better-camera"><a href="#a-better-camera" class="header-anchor">#</a> A Better Camera</h1> <p>I've been putting this off for a while. Implementing a camera isn't specifically related to using WGPU properly, but it's been bugging me so let's do it.</p> <p><code>main.rs</code> is getting a little crowded, so let's create a <code>camera.rs</code> file to put our camera code. The first thing we're going to put in it in is some imports and our <code>OPENGL_TO_WGPU_MATRIX</code>.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">use</span> <span class="token namespace">cgmath<span class="token punctuation">::</span></span><span class="token operator">*</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token namespace">winit<span class="token punctuation">::</span>event<span class="token punctuation">::</span></span><span class="token operator">*</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token namespace">winit<span class="token punctuation">::</span>dpi<span class="token punctuation">::</span></span><span class="token class-name">PhysicalPosition</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span>time<span class="token punctuation">::</span></span><span class="token class-name">Duration</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span></span><span class="token keyword">f32</span><span class="token punctuation">::</span><span class="token namespace">consts<span class="token punctuation">::</span></span><span class="token constant">FRAC_PI_2</span><span class="token punctuation">;</span>
<span class="token attribute attr-name">#[rustfmt::skip]</span>
<span class="token keyword">pub</span> <span class="token keyword">const</span> <span class="token constant">OPENGL_TO_WGPU_MATRIX</span><span class="token punctuation">:</span> <span class="token namespace">cgmath<span class="token punctuation">::</span></span><span class="token class-name">Matrix4</span><span class="token operator">&lt;</span><span class="token keyword">f32</span><span class="token operator">&gt;</span> <span class="token operator">=</span> <span class="token namespace">cgmath<span class="token punctuation">::</span></span><span class="token class-name">Matrix4</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span>
<span class="token number">1.0</span><span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">,</span>
<span class="token number">0.0</span><span class="token punctuation">,</span> <span class="token number">1.0</span><span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">,</span>
<span class="token number">0.0</span><span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">,</span> <span class="token number">0.5</span><span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">,</span>
<span class="token number">0.0</span><span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">,</span> <span class="token number">0.5</span><span class="token punctuation">,</span> <span class="token number">1.0</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><h2 id="the-camera"><a href="#the-camera" class="header-anchor">#</a> The Camera</h2> <p>Next we need create a new <code>Camera</code> struct. We're going to be using a FPS style camera, so we'll store the position and the yaw (horizontal rotation), and pitch (vertical rotation). We'll have a <code>calc_matrix</code> method to create our view matrix.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token attribute attr-name">#[derive(Debug)]</span>
<span class="token keyword">pub</span> <span class="token keyword">struct</span> <span class="token type-definition class-name">Camera</span> <span class="token punctuation">{</span>
<span class="token keyword">pub</span> position<span class="token punctuation">:</span> <span class="token class-name">Point3</span><span class="token operator">&lt;</span><span class="token keyword">f32</span><span class="token operator">&gt;</span><span class="token punctuation">,</span>
yaw<span class="token punctuation">:</span> <span class="token class-name">Rad</span><span class="token operator">&lt;</span><span class="token keyword">f32</span><span class="token operator">&gt;</span><span class="token punctuation">,</span>
pitch<span class="token punctuation">:</span> <span class="token class-name">Rad</span><span class="token operator">&lt;</span><span class="token keyword">f32</span><span class="token operator">&gt;</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token keyword">impl</span> <span class="token class-name">Camera</span> <span class="token punctuation">{</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">new</span><span class="token operator">&lt;</span>
<span class="token class-name">V</span><span class="token punctuation">:</span> <span class="token class-name">Into</span><span class="token operator">&lt;</span><span class="token class-name">Point3</span><span class="token operator">&lt;</span><span class="token keyword">f32</span><span class="token operator">&gt;&gt;</span><span class="token punctuation">,</span>
<span class="token class-name">Y</span><span class="token punctuation">:</span> <span class="token class-name">Into</span><span class="token operator">&lt;</span><span class="token class-name">Rad</span><span class="token operator">&lt;</span><span class="token keyword">f32</span><span class="token operator">&gt;&gt;</span><span class="token punctuation">,</span>
<span class="token class-name">P</span><span class="token punctuation">:</span> <span class="token class-name">Into</span><span class="token operator">&lt;</span><span class="token class-name">Rad</span><span class="token operator">&lt;</span><span class="token keyword">f32</span><span class="token operator">&gt;&gt;</span><span class="token punctuation">,</span>
<span class="token operator">&gt;</span><span class="token punctuation">(</span>
position<span class="token punctuation">:</span> <span class="token class-name">V</span><span class="token punctuation">,</span>
yaw<span class="token punctuation">:</span> <span class="token class-name">Y</span><span class="token punctuation">,</span>
pitch<span class="token punctuation">:</span> <span class="token class-name">P</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">Self</span> <span class="token punctuation">{</span>
<span class="token keyword">Self</span> <span class="token punctuation">{</span>
position<span class="token punctuation">:</span> position<span class="token punctuation">.</span><span class="token function">into</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
yaw<span class="token punctuation">:</span> yaw<span class="token punctuation">.</span><span class="token function">into</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
pitch<span class="token punctuation">:</span> pitch<span class="token punctuation">.</span><span class="token function">into</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">calc_matrix</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">Matrix4</span><span class="token operator">&lt;</span><span class="token keyword">f32</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
<span class="token class-name">Matrix4</span><span class="token punctuation">::</span><span class="token function">look_at_dir</span><span class="token punctuation">(</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>position<span class="token punctuation">,</span>
<span class="token class-name">Vector3</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>yaw<span class="token number">.0</span><span class="token punctuation">.</span><span class="token function">cos</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>pitch<span class="token number">.0</span><span class="token punctuation">.</span><span class="token function">sin</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>yaw<span class="token number">.0</span><span class="token punctuation">.</span><span class="token function">sin</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">normalize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token class-name">Vector3</span><span class="token punctuation">::</span><span class="token function">unit_y</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><h2 id="the-projection"><a href="#the-projection" class="header-anchor">#</a> The Projection</h2> <p>I've decided to split the projection from the camera. The projection only really needs to change if the window resizes, so let's create a <code>Projection</code> struct.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">pub</span> <span class="token keyword">struct</span> <span class="token type-definition class-name">Projection</span> <span class="token punctuation">{</span>
aspect<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
fovy<span class="token punctuation">:</span> <span class="token class-name">Rad</span><span class="token operator">&lt;</span><span class="token keyword">f32</span><span class="token operator">&gt;</span><span class="token punctuation">,</span>
znear<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
zfar<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token keyword">impl</span> <span class="token class-name">Projection</span> <span class="token punctuation">{</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">new</span><span class="token operator">&lt;</span><span class="token class-name">F</span><span class="token punctuation">:</span> <span class="token class-name">Into</span><span class="token operator">&lt;</span><span class="token class-name">Rad</span><span class="token operator">&lt;</span><span class="token keyword">f32</span><span class="token operator">&gt;&gt;</span><span class="token operator">&gt;</span><span class="token punctuation">(</span>
width<span class="token punctuation">:</span> <span class="token keyword">u32</span><span class="token punctuation">,</span>
height<span class="token punctuation">:</span> <span class="token keyword">u32</span><span class="token punctuation">,</span>
fovy<span class="token punctuation">:</span> <span class="token class-name">F</span><span class="token punctuation">,</span>
znear<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
zfar<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">Self</span> <span class="token punctuation">{</span>
<span class="token keyword">Self</span> <span class="token punctuation">{</span>
aspect<span class="token punctuation">:</span> width <span class="token keyword">as</span> <span class="token keyword">f32</span> <span class="token operator">/</span> height <span class="token keyword">as</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
fovy<span class="token punctuation">:</span> fovy<span class="token punctuation">.</span><span class="token function">into</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
znear<span class="token punctuation">,</span>
zfar<span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">resize</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">,</span> width<span class="token punctuation">:</span> <span class="token keyword">u32</span><span class="token punctuation">,</span> height<span class="token punctuation">:</span> <span class="token keyword">u32</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>aspect <span class="token operator">=</span> width <span class="token keyword">as</span> <span class="token keyword">f32</span> <span class="token operator">/</span> height <span class="token keyword">as</span> <span class="token keyword">f32</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">calc_matrix</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">Matrix4</span><span class="token operator">&lt;</span><span class="token keyword">f32</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
<span class="token constant">OPENGL_TO_WGPU_MATRIX</span> <span class="token operator">*</span> <span class="token function">perspective</span><span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">.</span>fovy<span class="token punctuation">,</span> <span class="token keyword">self</span><span class="token punctuation">.</span>aspect<span class="token punctuation">,</span> <span class="token keyword">self</span><span class="token punctuation">.</span>znear<span class="token punctuation">,</span> <span class="token keyword">self</span><span class="token punctuation">.</span>zfar<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>On thing to note: <code>cgmath</code> currently returns a right-handed projection matrix from the <code>perspective</code> function. This means that the z-axis points out of the screen. If you want the z-axis to be <em>into</em> the screen (aka. a left-handed projection matrix), you'll have to code your own.</p> <p>You can tell the difference between a right-handed coordinate system and a left-handed one by using your hands. Point your thumb to the right. This is the x-axis. Point your pointer finger up. This is the y-axis. Extend your middle finger. This is the z-axis. On your right hand your middle finger should be pointing towards you. On your left hand it should be pointing away.</p> <p><img src="/learn-wgpu/assets/img/left_right_hand.ccabf5d0.gif" alt="./left_right_hand.gif"></p> <h1 id="the-camera-controller"><a href="#the-camera-controller" class="header-anchor">#</a> The Camera Controller</h1> <p>As our camera is different, so we'll need a new camera controller. Add the following to <code>camera.rs</code>.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token attribute attr-name">#[derive(Debug)]</span>
<span class="token keyword">pub</span> <span class="token keyword">struct</span> <span class="token type-definition class-name">CameraController</span> <span class="token punctuation">{</span>
amount_left<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
amount_right<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
amount_forward<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
amount_backward<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
amount_up<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
amount_down<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
rotate_horizontal<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
rotate_vertical<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
scroll<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
speed<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
sensitivity<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token keyword">impl</span> <span class="token class-name">CameraController</span> <span class="token punctuation">{</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">new</span><span class="token punctuation">(</span>speed<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span> sensitivity<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">Self</span> <span class="token punctuation">{</span>
<span class="token keyword">Self</span> <span class="token punctuation">{</span>
amount_left<span class="token punctuation">:</span> <span class="token number">0.0</span><span class="token punctuation">,</span>
amount_right<span class="token punctuation">:</span> <span class="token number">0.0</span><span class="token punctuation">,</span>
amount_forward<span class="token punctuation">:</span> <span class="token number">0.0</span><span class="token punctuation">,</span>
amount_backward<span class="token punctuation">:</span> <span class="token number">0.0</span><span class="token punctuation">,</span>
amount_up<span class="token punctuation">:</span> <span class="token number">0.0</span><span class="token punctuation">,</span>
amount_down<span class="token punctuation">:</span> <span class="token number">0.0</span><span class="token punctuation">,</span>
rotate_horizontal<span class="token punctuation">:</span> <span class="token number">0.0</span><span class="token punctuation">,</span>
rotate_vertical<span class="token punctuation">:</span> <span class="token number">0.0</span><span class="token punctuation">,</span>
scroll<span class="token punctuation">:</span> <span class="token number">0.0</span><span class="token punctuation">,</span>
speed<span class="token punctuation">,</span>
sensitivity<span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">process_keyboard</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">,</span> key<span class="token punctuation">:</span> <span class="token class-name">VirtualKeyCode</span><span class="token punctuation">,</span> state<span class="token punctuation">:</span> <span class="token class-name">ElementState</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">bool</span><span class="token punctuation">{</span>
<span class="token keyword">let</span> amount <span class="token operator">=</span> <span class="token keyword">if</span> state <span class="token operator">==</span> <span class="token class-name">ElementState</span><span class="token punctuation">::</span><span class="token class-name">Pressed</span> <span class="token punctuation">{</span> <span class="token number">1.0</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token number">0.0</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">match</span> key <span class="token punctuation">{</span>
<span class="token class-name">VirtualKeyCode</span><span class="token punctuation">::</span><span class="token class-name">W</span> <span class="token operator">|</span> <span class="token class-name">VirtualKeyCode</span><span class="token punctuation">::</span><span class="token class-name">Up</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>amount_forward <span class="token operator">=</span> amount<span class="token punctuation">;</span>
<span class="token boolean">true</span>
<span class="token punctuation">}</span>
<span class="token class-name">VirtualKeyCode</span><span class="token punctuation">::</span><span class="token class-name">S</span> <span class="token operator">|</span> <span class="token class-name">VirtualKeyCode</span><span class="token punctuation">::</span><span class="token class-name">Down</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>amount_backward <span class="token operator">=</span> amount<span class="token punctuation">;</span>
<span class="token boolean">true</span>
<span class="token punctuation">}</span>
<span class="token class-name">VirtualKeyCode</span><span class="token punctuation">::</span><span class="token class-name">A</span> <span class="token operator">|</span> <span class="token class-name">VirtualKeyCode</span><span class="token punctuation">::</span><span class="token class-name">Left</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>amount_left <span class="token operator">=</span> amount<span class="token punctuation">;</span>
<span class="token boolean">true</span>
<span class="token punctuation">}</span>
<span class="token class-name">VirtualKeyCode</span><span class="token punctuation">::</span><span class="token class-name">D</span> <span class="token operator">|</span> <span class="token class-name">VirtualKeyCode</span><span class="token punctuation">::</span><span class="token class-name">Right</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>amount_right <span class="token operator">=</span> amount<span class="token punctuation">;</span>
<span class="token boolean">true</span>
<span class="token punctuation">}</span>
<span class="token class-name">VirtualKeyCode</span><span class="token punctuation">::</span><span class="token class-name">Space</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>amount_up <span class="token operator">=</span> amount<span class="token punctuation">;</span>
<span class="token boolean">true</span>
<span class="token punctuation">}</span>
<span class="token class-name">VirtualKeyCode</span><span class="token punctuation">::</span><span class="token class-name">LShift</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>amount_down <span class="token operator">=</span> amount<span class="token punctuation">;</span>
<span class="token boolean">true</span>
<span class="token punctuation">}</span>
_ <span class="token operator">=&gt;</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">process_mouse</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">,</span> mouse_dx<span class="token punctuation">:</span> <span class="token keyword">f64</span><span class="token punctuation">,</span> mouse_dy<span class="token punctuation">:</span> <span class="token keyword">f64</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>rotate_horizontal <span class="token operator">=</span> mouse_dx <span class="token keyword">as</span> <span class="token keyword">f32</span><span class="token punctuation">;</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>rotate_vertical <span class="token operator">=</span> mouse_dy <span class="token keyword">as</span> <span class="token keyword">f32</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">process_scroll</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">,</span> delta<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token class-name">MouseScrollDelta</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>scroll <span class="token operator">=</span> <span class="token operator">-</span><span class="token keyword">match</span> delta <span class="token punctuation">{</span>
<span class="token comment">// I'm assuming a line is about 100 pixels</span>
<span class="token class-name">MouseScrollDelta</span><span class="token punctuation">::</span><span class="token class-name">LineDelta</span><span class="token punctuation">(</span>_<span class="token punctuation">,</span> scroll<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> scroll <span class="token operator">*</span> <span class="token number">100.0</span><span class="token punctuation">,</span>
<span class="token class-name">MouseScrollDelta</span><span class="token punctuation">::</span><span class="token class-name">PixelDelta</span><span class="token punctuation">(</span><span class="token class-name">PhysicalPosition</span> <span class="token punctuation">{</span>
y<span class="token punctuation">:</span> scroll<span class="token punctuation">,</span>
<span class="token punctuation">..</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token operator">*</span>scroll <span class="token keyword">as</span> <span class="token keyword">f32</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">update_camera</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">,</span> camera<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token class-name">Camera</span><span class="token punctuation">,</span> dt<span class="token punctuation">:</span> <span class="token class-name">Duration</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">let</span> dt <span class="token operator">=</span> dt<span class="token punctuation">.</span><span class="token function">as_secs_f32</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Move forward/backward and left/right</span>
<span class="token keyword">let</span> <span class="token punctuation">(</span>yaw_sin<span class="token punctuation">,</span> yaw_cos<span class="token punctuation">)</span> <span class="token operator">=</span> camera<span class="token punctuation">.</span>yaw<span class="token number">.0</span><span class="token punctuation">.</span><span class="token function">sin_cos</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> forward <span class="token operator">=</span> <span class="token class-name">Vector3</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span>yaw_cos<span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">,</span> yaw_sin<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">normalize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> right <span class="token operator">=</span> <span class="token class-name">Vector3</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token operator">-</span>yaw_sin<span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">,</span> yaw_cos<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">normalize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
camera<span class="token punctuation">.</span>position <span class="token operator">+=</span> forward <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">.</span>amount_forward <span class="token operator">-</span> <span class="token keyword">self</span><span class="token punctuation">.</span>amount_backward<span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token keyword">self</span><span class="token punctuation">.</span>speed <span class="token operator">*</span> dt<span class="token punctuation">;</span>
camera<span class="token punctuation">.</span>position <span class="token operator">+=</span> right <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">.</span>amount_right <span class="token operator">-</span> <span class="token keyword">self</span><span class="token punctuation">.</span>amount_left<span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token keyword">self</span><span class="token punctuation">.</span>speed <span class="token operator">*</span> dt<span class="token punctuation">;</span>
<span class="token comment">// Move in/out (aka. &quot;zoom&quot;)</span>
<span class="token comment">// Note: this isn't an actual zoom. The camera's position</span>
<span class="token comment">// changes when zooming. I've added this to make it easier</span>
<span class="token comment">// to get closer to an object you want to focus on.</span>
<span class="token keyword">let</span> <span class="token punctuation">(</span>pitch_sin<span class="token punctuation">,</span> pitch_cos<span class="token punctuation">)</span> <span class="token operator">=</span> camera<span class="token punctuation">.</span>pitch<span class="token number">.0</span><span class="token punctuation">.</span><span class="token function">sin_cos</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> scrollward <span class="token operator">=</span> <span class="token class-name">Vector3</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span>pitch_cos <span class="token operator">*</span> yaw_cos<span class="token punctuation">,</span> pitch_sin<span class="token punctuation">,</span> pitch_cos <span class="token operator">*</span> yaw_sin<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">normalize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
camera<span class="token punctuation">.</span>position <span class="token operator">+=</span> scrollward <span class="token operator">*</span> <span class="token keyword">self</span><span class="token punctuation">.</span>scroll <span class="token operator">*</span> <span class="token keyword">self</span><span class="token punctuation">.</span>speed <span class="token operator">*</span> <span class="token keyword">self</span><span class="token punctuation">.</span>sensitivity <span class="token operator">*</span> dt<span class="token punctuation">;</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>scroll <span class="token operator">=</span> <span class="token number">0.0</span><span class="token punctuation">;</span>
<span class="token comment">// Move up/down. Since we don't use roll, we can just</span>
<span class="token comment">// modify the y coordinate directly.</span>
camera<span class="token punctuation">.</span>position<span class="token punctuation">.</span>y <span class="token operator">+=</span> <span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">.</span>amount_up <span class="token operator">-</span> <span class="token keyword">self</span><span class="token punctuation">.</span>amount_down<span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token keyword">self</span><span class="token punctuation">.</span>speed <span class="token operator">*</span> dt<span class="token punctuation">;</span>
<span class="token comment">// Rotate</span>
camera<span class="token punctuation">.</span>yaw <span class="token operator">+=</span> <span class="token class-name">Rad</span><span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">.</span>rotate_horizontal<span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token keyword">self</span><span class="token punctuation">.</span>sensitivity <span class="token operator">*</span> dt<span class="token punctuation">;</span>
camera<span class="token punctuation">.</span>pitch <span class="token operator">+=</span> <span class="token class-name">Rad</span><span class="token punctuation">(</span><span class="token operator">-</span><span class="token keyword">self</span><span class="token punctuation">.</span>rotate_vertical<span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token keyword">self</span><span class="token punctuation">.</span>sensitivity <span class="token operator">*</span> dt<span class="token punctuation">;</span>
<span class="token comment">// If process_mouse isn't called every frame, these values</span>
<span class="token comment">// will not get set to zero, and the camera will rotate</span>
<span class="token comment">// when moving in a non cardinal direction.</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>rotate_horizontal <span class="token operator">=</span> <span class="token number">0.0</span><span class="token punctuation">;</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>rotate_vertical <span class="token operator">=</span> <span class="token number">0.0</span><span class="token punctuation">;</span>
<span class="token comment">// Keep the camera's angle from going too high/low.</span>
<span class="token keyword">if</span> camera<span class="token punctuation">.</span>pitch <span class="token operator">&lt;</span> <span class="token operator">-</span><span class="token class-name">Rad</span><span class="token punctuation">(</span><span class="token constant">FRAC_PI_2</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
camera<span class="token punctuation">.</span>pitch <span class="token operator">=</span> <span class="token operator">-</span><span class="token class-name">Rad</span><span class="token punctuation">(</span><span class="token constant">FRAC_PI_2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> camera<span class="token punctuation">.</span>pitch <span class="token operator">&gt;</span> <span class="token class-name">Rad</span><span class="token punctuation">(</span><span class="token constant">FRAC_PI_2</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
camera<span class="token punctuation">.</span>pitch <span class="token operator">=</span> <span class="token class-name">Rad</span><span class="token punctuation">(</span><span class="token constant">FRAC_PI_2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><h2 id="cleaning-up-main-rs"><a href="#cleaning-up-main-rs" class="header-anchor">#</a> Cleaning up <code>main.rs</code></h2> <p>First things first we need to delete <code>Camera</code> and <code>CameraController</code> as well as the extra <code>OPENGL_TO_WGPU_MATRIX</code> from <code>main.rs</code>. Once you've done that import <code>camera.rs</code>.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">mod</span> <span class="token module-declaration namespace">model</span><span class="token punctuation">;</span>
<span class="token keyword">mod</span> <span class="token module-declaration namespace">texture</span><span class="token punctuation">;</span>
<span class="token keyword">mod</span> <span class="token module-declaration namespace">camera</span><span class="token punctuation">;</span> <span class="token comment">// NEW!</span>
</code></pre></div><p>We need to update <code>update_view_proj</code> to use our new <code>Camera</code> and <code>Projection</code>.</p> <div class="language-rust extra-class"><pre class="language-rust"><code>
<span class="token keyword">impl</span> <span class="token class-name">Uniforms</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
<span class="token comment">// UPDATED!</span>
<span class="token keyword">fn</span> <span class="token function-definition function">update_view_proj</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">,</span> camera<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token namespace">camera<span class="token punctuation">::</span></span><span class="token class-name">Camera</span><span class="token punctuation">,</span> projection<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token namespace">camera<span class="token punctuation">::</span></span><span class="token class-name">Projection</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>view_position <span class="token operator">=</span> camera<span class="token punctuation">.</span>position<span class="token punctuation">.</span><span class="token function">to_homogeneous</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>view_proj <span class="token operator">=</span> projection<span class="token punctuation">.</span><span class="token function">calc_matrix</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">*</span> camera<span class="token punctuation">.</span><span class="token function">calc_matrix</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>We need to change our <code>State</code> to use our <code>Camera</code>, <code>CameraProjection</code> and <code>Projection</code> as well. We'll also add 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 operator">&amp;</span><span class="token class-name">Window</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">Self</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
<span class="token comment">// UPDATED!</span>
<span class="token keyword">let</span> camera <span class="token operator">=</span> <span class="token namespace">camera<span class="token punctuation">::</span></span><span class="token class-name">Camera</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token number">0.0</span><span class="token punctuation">,</span> <span class="token number">5.0</span><span class="token punctuation">,</span> <span class="token number">10.0</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token namespace">cgmath<span class="token punctuation">::</span></span><span class="token class-name">Deg</span><span class="token punctuation">(</span><span class="token operator">-</span><span class="token number">90.0</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token namespace">cgmath<span class="token punctuation">::</span></span><span class="token class-name">Deg</span><span class="token punctuation">(</span><span class="token operator">-</span><span class="token number">20.0</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> projection <span class="token operator">=</span> <span class="token namespace">camera<span class="token punctuation">::</span></span><span class="token class-name">Projection</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span>sc_desc<span class="token punctuation">.</span>width<span class="token punctuation">,</span> sc_desc<span class="token punctuation">.</span>height<span class="token punctuation">,</span> <span class="token namespace">cgmath<span class="token punctuation">::</span></span><span class="token class-name">Deg</span><span class="token punctuation">(</span><span class="token number">45.0</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">0.1</span><span class="token punctuation">,</span> <span class="token number">100.0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> camera_controller <span class="token operator">=</span> <span class="token namespace">camera<span class="token punctuation">::</span></span><span class="token class-name">CameraController</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token number">4.0</span><span class="token punctuation">,</span> <span class="token number">0.4</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// ...</span>
<span class="token keyword">Self</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
camera<span class="token punctuation">,</span>
projection<span class="token punctuation">,</span>
camera_controller<span class="token punctuation">,</span>
<span class="token comment">// ...</span>
<span class="token comment">// NEW!</span>
mouse_pressed<span class="token punctuation">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>We need to change our <code>projection</code> in <code>resize</code> as well.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">fn</span> <span class="token function-definition function">resize</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">,</span> new_size<span class="token punctuation">:</span> <span class="token namespace">winit<span class="token punctuation">::</span>dpi<span class="token punctuation">::</span></span><span class="token class-name">PhysicalSize</span><span class="token operator">&lt;</span><span class="token keyword">u32</span><span class="token operator">&gt;</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// UPDATED!</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>projection<span class="token punctuation">.</span><span class="token function">resize</span><span class="token punctuation">(</span>new_size<span class="token punctuation">.</span>width<span class="token punctuation">,</span> new_size<span class="token punctuation">.</span>height<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// ...</span>
<span class="token punctuation">}</span>
</code></pre></div><p><code>input()</code> will need to be updated as well. 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.23.0/winit/event/enum.WindowEvent.html?search=#variant.CursorMoved" target="_blank" rel="noopener noreferrer">winit docs<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a> inform us that OS will often transform the data for the <code>CursorMoved</code> event to allow effects such as cursor acceleration. Because of this, we're going to change our <code>input()</code> function to use <code>DeviceEvent</code> instead of <code>WindowEvent</code>.</p> <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">DeviceEvent</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">DeviceEvent</span><span class="token punctuation">::</span><span class="token class-name">Key</span><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 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">DeviceEvent</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">DeviceEvent</span><span class="token punctuation">::</span><span class="token class-name">Button</span> <span class="token punctuation">{</span>
button<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token comment">// Left Mouse Button</span>
state<span class="token punctuation">,</span>
<span class="token punctuation">}</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>mouse_pressed <span class="token operator">=</span> <span class="token operator">*</span>state <span class="token operator">==</span> <span class="token class-name">ElementState</span><span class="token punctuation">::</span><span class="token class-name">Pressed</span><span class="token punctuation">;</span>
<span class="token boolean">true</span>
<span class="token punctuation">}</span>
<span class="token class-name">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 operator">=&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token keyword">self</span><span class="token punctuation">.</span>mouse_pressed <span class="token punctuation">{</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>camera_controller<span class="token punctuation">.</span><span class="token function">process_mouse</span><span class="token punctuation">(</span>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 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>This change means will have to modify the event loop in <code>main()</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">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>
<span class="token keyword">ref</span> event<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 punctuation">{</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 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> window<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">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">CloseRequested</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">KeyboardInput</span> <span class="token punctuation">{</span> input<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">match</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 operator">=&gt;</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">Exit</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 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 be the framerate. Currently we aren't calculating <code>dt</code>, so I decided to pass it into <code>update</code> as a parameter.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">fn</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">,</span> dt<span class="token punctuation">:</span> <span class="token namespace">std<span class="token punctuation">::</span>time<span class="token punctuation">::</span></span><span class="token class-name">Duration</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// UPDATED!</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>camera_controller<span class="token punctuation">.</span><span class="token function">update_camera</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">.</span>camera<span class="token punctuation">,</span> dt<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">self</span><span class="token punctuation">.</span>uniforms<span class="token punctuation">.</span><span class="token function">update_view_proj</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">.</span>camera<span class="token punctuation">,</span> <span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">.</span>projection<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// ..</span>
<span class="token punctuation">}</span>
</code></pre></div><p>While we're at it, let's use <code>dt</code> for the light's rotation as well.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">self</span><span class="token punctuation">.</span>light<span class="token punctuation">.</span>position <span class="token operator">=</span>
<span class="token namespace">cgmath<span class="token punctuation">::</span></span><span class="token class-name">Quaternion</span><span class="token punctuation">::</span><span class="token function">from_axis_angle</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token number">0.0</span><span class="token punctuation">,</span> <span class="token number">1.0</span><span class="token punctuation">,</span> <span class="token number">0.0</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">into</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token namespace">cgmath<span class="token punctuation">::</span></span><span class="token class-name">Deg</span><span class="token punctuation">(</span><span class="token number">60.0</span> <span class="token operator">*</span> dt<span class="token punctuation">.</span><span class="token function">as_secs_f32</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token operator">*</span> old_position<span class="token punctuation">;</span> <span class="token comment">// UPDATED!</span>
</code></pre></div><p>We still need to calculate <code>dt</code>. Let's do that in the <code>main</code> function.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">fn</span> <span class="token function-definition function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
<span class="token keyword">let</span> <span class="token keyword">mut</span> state <span class="token operator">=</span> <span class="token function">block_on</span><span class="token punctuation">(</span><span class="token class-name">State</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>window<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> <span class="token keyword">mut</span> last_render_time <span class="token operator">=</span> <span class="token namespace">std<span class="token punctuation">::</span>time<span class="token punctuation">::</span></span><span class="token class-name">Instant</span><span class="token punctuation">::</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
event_loop<span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token keyword">move</span> <span class="token closure-params"><span class="token closure-punctuation punctuation">|</span>event<span class="token punctuation">,</span> _<span class="token punctuation">,</span> control_flow<span class="token closure-punctuation punctuation">|</span></span> <span class="token punctuation">{</span>
<span class="token operator">*</span>control_flow <span class="token operator">=</span> <span class="token class-name">ControlFlow</span><span class="token punctuation">::</span><span class="token class-name">Poll</span><span class="token punctuation">;</span>
<span class="token keyword">match</span> event <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
<span class="token comment">// UPDATED!</span>
<span class="token class-name">Event</span><span class="token punctuation">::</span><span class="token class-name">RedrawRequested</span><span class="token punctuation">(</span>_<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">let</span> now <span class="token operator">=</span> <span class="token namespace">std<span class="token punctuation">::</span>time<span class="token punctuation">::</span></span><span class="token class-name">Instant</span><span class="token punctuation">::</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> dt <span class="token operator">=</span> now <span class="token operator">-</span> last_render_time<span class="token punctuation">;</span>
last_render_time <span class="token operator">=</span> now<span class="token punctuation">;</span>
state<span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span>dt<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// ...</span>
<span class="token punctuation">}</span>
_ <span class="token operator">=&gt;</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>With that we should be able to move our camera wherever we want.</p> <p><img src="/learn-wgpu/assets/img/screenshot.4f5740bc.png" alt="./screenshot.png"></p> <div class="auto-github-link"><a href="https://github.com/sotrh/learn-wgpu/tree/master/code/intermediate/tutorial12-camera/" target="_blank" rel="noopener noreferrer">Check out the code!</a> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></div></div> <footer class="page-edit"><!----> <div class="last-updated"><span class="prefix">Last Updated: </span> <span class="time">11/25/2020, 11:51:22 PM</span></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
<a href="/learn-wgpu/intermediate/tutorial11-normals/" class="prev">
Normal Mapping
</a></span> <span class="next"><a href="/learn-wgpu/intermediate/tutorial13-threading/">
Multi-threading with Wgpu and Rayon
</a>
</span></p></div> </main></div></div><div class="global-ui"><!----></div></div>
<script src="/learn-wgpu/assets/js/app.8a1973b9.js" defer></script><script src="/learn-wgpu/assets/js/2.da3fd46f.js" defer></script><script src="/learn-wgpu/assets/js/14.f852c057.js" defer></script><script src="/learn-wgpu/assets/js/22.2132e362.js" defer></script>
</body>
</html>