Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
shi-yan committed Aug 1, 2024
1 parent e98e16c commit 9cc97bf
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 10 deletions.
28 changes: 21 additions & 7 deletions 2D_Techniques/orthogonal_cameras.html
Original file line number Diff line number Diff line change
Expand Up @@ -144,13 +144,27 @@

<div id="article-container">
<article>
<h2 >2.1 Orthogonal Cameras</h2><p>In this section, we'll discuss orthogonal cameras. Previously, we explored perspective cameras, which mimic real-life pinhole cameras where objects farther away appear smaller on the screen. This perspective effect mimics our natural visual experience. In contrast, orthogonal cameras don't introduce any perspective. They project objects onto the screen in their original size, regardless of their distance from the camera.</p><p>So, why are orthogonal cameras useful? Well, consider scenarios where we want to create 2D applications using a 3D API, such as image processing applications. In these cases, we don't want images to appear distorted due to perspective. Orthogonal projection is ideal in such situations. It's also commonly employed in 45-degree top-view video games.</p><p>let's try to derive the orthogonal projection matrix. remember before projection, we have converted the coordinate system to the view coordinates. in this coordinates, we should have the xy plane parallel to the screen plane and the z-axis pointing towards us.</p><p>Imagine if we have a screen aligned bounding box enclosing the 3d scene, our goal of projection is to project the bounding box to the ndc coordinates in the range of [-1,-1,-1] to [1,1,1] for both x, y and z.</p><p>this is actually a simpler calculation than the perspective projection.</p><p>let the right of the screen coordinates is <code class="language-math math-inline">r</code> and the left is <code class="language-math math-inline">l</code>. given a point <code class="language-math math-inline">p</code> at <code class="language-math math-inline">(x,y)</code> in the view coordinates, we have</p><p class="katex-display-counter"><code class="language-math math-block">\begin{multline}
l \leq x \leq r \\
0 \leq x \leq r-l \\
0 \leq \frac{x-l}{r-l} \leq 1
\end{multline}</code></p><pre><code class="language-javascript code-block">...
let orthProjMatrix = glMatrix.mat4.ortho(glMatrix.mat4.create(), -320.0, 320.0, 240.0, -240.0, -1000.0, 1000.0);
...</code></pre><p>Using an orthogonal camera is straightforward. There are no changes to the shader code or most of the JavaScript logic, so I'll focus on the key elements. The orthogonal projection matrix closely resembles the perspective projection matrix. We can easily generate this projection matrix using the glMatrix library. By specifying the width and height of the viewport, as well as the near and far planes of the view frustum, we obtain the orthogonal projection matrix.</p><p>Unlike the perspective projection, the view frustum for orthogonal projection is not a cone; it's a simple 3D rectangle. The image below illustrates the difference between these two projections.</p>
<h2 >2.1 Orthogonal Cameras</h2><p>In this section, we'll explore orthogonal cameras. Previously, we examined perspective cameras, which emulate real-life pinhole cameras where distant objects appear smaller on screen. This perspective effect mirrors our natural visual experience. In contrast, orthogonal cameras maintain objects' original sizes on screen, regardless of their distance from the camera, eliminating perspective distortion.</p><a href="https://shi-yan.github.io/WebGPUUnleashed/code/code.html#2_01_orthogonal_cameras" target="_blank" class="comment"><svg style="margin-right:10px;vertical-align: middle;" xmlns="http://www.w3.org/2000/svg" height="32"
width="32" fill="#dadadb" viewBox="0 -960 960 960"><path d="M189-160q-60 0-102.5-43T42-307q0-9 1-18t3-18l84-336q14-54 57-87.5t98-33.5h390q55 0 98 33.5t57 87.5l84 336q2 9 3.5 18.5T919-306q0 61-43.5 103.5T771-160q-42 0-78-22t-54-60l-28-58q-5-10-15-15t-21-5H385q-11 0-21 5t-15 15l-28 58q-18 38-54 60t-78 22Zm3-80q19 0 34.5-10t23.5-27l28-57q15-31 44-48.5t63-17.5h190q34 0 63 18t45 48l28 57q8 17 23.5 27t34.5 10q28 0 48-18.5t21-46.5q0 1-2-19l-84-335q-7-27-28-44t-49-17H285q-28 0-49.5 17T208-659l-84 335q-2 6-2 18 0 28 20.5 47t49.5 19Zm348-280q17 0 28.5-11.5T580-560q0-17-11.5-28.5T540-600q-17 0-28.5 11.5T500-560q0 17 11.5 28.5T540-520Zm80-80q17 0 28.5-11.5T660-640q0-17-11.5-28.5T620-680q-17 0-28.5 11.5T580-640q0 17 11.5 28.5T620-600Zm0 160q17 0 28.5-11.5T660-480q0-17-11.5-28.5T620-520q-17 0-28.5 11.5T580-480q0 17 11.5 28.5T620-440Zm80-80q17 0 28.5-11.5T740-560q0-17-11.5-28.5T700-600q-17 0-28.5 11.5T660-560q0 17 11.5 28.5T700-520Zm-360 60q13 0 21.5-8.5T370-490v-40h40q13 0 21.5-8.5T440-560q0-13-8.5-21.5T410-590h-40v-40q0-13-8.5-21.5T340-660q-13 0-21.5 8.5T310-630v40h-40q-13 0-21.5 8.5T240-560q0 13 8.5 21.5T270-530h40v40q0 13 8.5 21.5T340-460Zm140-20Z"/></svg>Launch Playground - 2_01_orthogonal_cameras</a><p>Orthogonal cameras prove useful in various scenarios, particularly when creating 2D applications using a 3D API, such as image processing tools. In these cases, we want to avoid image distortion due to perspective effects. Orthogonal projection excels in such situations and is also frequently employed in 45-degree top-view video games.</p><p>Let's derive the orthogonal projection matrix. Recall that before projection, we convert the coordinate system to view coordinates. In this system, the xy plane is parallel to the screen plane, with the z-axis pointing towards us.</p><p>Imagine a screen-aligned bounding box enclosing the 3D scene. Our projection goal is to map this bounding box to NDC (Normalized Device Coordinates) in the range <code class="language-math math-inline">[-1,-1,-1]</code> to <code class="language-math math-inline">[1,1,1]</code> for x, y, and z.</p><p>This calculation is simpler than perspective projection. Let the right edge of the screen coordinates be <code class="language-math math-inline">r</code> and the left edge be <code class="language-math math-inline">l</code>. Given a point <code class="language-math math-inline">p</code> at <code class="language-math math-inline">(x,y)</code> in view coordinates, we have:</p><p class="katex-display-counter"><code class="language-math math-block">\begin{aligned}
& l \leq x \leq r \\
& 0 \leq x \leq r-l \\
& 0 \leq \frac{x-l}{r-l} \leq 1 \\
& 0 \leq 2 \times \frac{x-l}{r-l} \leq 2 \\
& -1 \leq 2 \times \frac{x-l}{r-l} -1 \leq 1
\end{aligned}</code></p><p>We've successfully converted the x-coordinate to the range <code class="language-math math-inline">[-1,1]</code>. Now, we'll refine the calculation to the form <code class="language-math math-inline">Ax + B</code>, allowing us to express it as matrix multiplication:</p><p class="katex-display-counter"><code class="language-math math-block">\begin{aligned}
& -1 \leq \frac{2x-2l-r+l}{r-l} \leq 1 \\
& -1 \leq \frac{2x}{r-l} - \frac{r+l}{r-l} \leq 1
\end{aligned}</code></p><p>We can derive similar equations for <code class="language-math math-inline">y</code> and <code class="language-math math-inline">z</code>. Note that NDC uses a left-handed coordinate system, so we need to flip the <code class="language-math math-inline">z</code> axis:</p><p class="katex-display-counter"><code class="language-math math-block">\begin{aligned}
x^\prime &= \frac{2x}{r-l} - \frac{r+l}{r-l} \\
y^\prime &= \frac{2y}{t-b} - \frac{t+b}{t-b} \\
z^\prime &= \frac{-2z}{f-n}-\frac{f+n}{f-n}
\end{aligned}</code></p><p>Where <code class="language-math math-inline">t</code> and <code class="language-math math-inline">b</code> are the top and bottom of the screen coordinates, and <code class="language-math math-inline">n</code> and <code class="language-math math-inline">f</code> are the near and far plane. Now, we can express these calculations as a matrix multiplication:</p><p class="katex-display-counter"><code class="language-math math-block">\begin{pmatrix}
\frac{2}{r-l} & 0 & 0 & 0 \\
0 & \frac{2}{t-b} & 0 & 0 \\
0 & 0 & \frac{-2}{f-n} & 0 \\
-\frac{r+l}{r-l} & - \frac{t+b}{t-b} & -\frac{f+n}{f-n} & 0
\end{pmatrix} </code></p><p>Implementing an orthogonal camera is straightforward. The shader code and most JavaScript logic remain unchanged, so we'll focus on the key elements:</p><div class="code-fragments"><pre><code class="language-javascript code-block" startNumber=131>let orthProjMatrix = glMatrix.mat4.ortho(glMatrix.mat4.create(), -320.0, 320.0, 240.0, -240.0, -1000.0, 1000.0);
</pre></code><div class="code-fragments-caption"><a target="_blank" href="https://shi-yan.github.io/WebGPUUnleashed/code/code.html?highlight=130:130#2_01_orthogonal_cameras">2_01_orthogonal_cameras/index.html:131-131 Generate the Orthogonal Matrix Using glMatrix</a></div></div><p>The orthogonal projection matrix closely resembles the perspective projection matrix. We can easily generate this projection matrix using the glMatrix library. By specifying the viewport's width and height, along with the near and far planes of the view frustum, we obtain the orthogonal projection matrix.</p><p>Unlike perspective projection, the view frustum for orthogonal projection is a simple 3D rectangle rather than a cone. The rest of the code remains identical to the perspective projection program.</p>
</article>

<div class="older_newer_link_section">
Expand Down
3 changes: 2 additions & 1 deletion 2D_Techniques/rendering_to_textures.html
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,8 @@

<div id="article-container">
<article>
<h2 >2.0 Rendering to Textures</h2><p>In this chapter, we will explore 2D techniques. You might wonder why we're focusing on 2D using a 3D API. As it turns out, WebGPU is also highly effective for accelerating 2D processing. Applications include image and video processing, user interfaces, and more. Therefore, we aim to cover some fundamental 2D-related topics.</p><p>In this tutorial, we'll discuss the "render to texture" technique, a concept you may find similarity from our previous discussion on mipmaps. This technique involves two rendering passes. In the first pass, we use a texture map as the render target, and render a 3D scene onto that texture map. In the second pass, we render again using that texture map. This approach is useful in creating mirrors or dynamic reflections in 3D scenes, among other applications.</p><p>Now, let's examine the code. In this example, we'll work with two shaders: the <code>teapot_shader</code> and the <code>box_shader</code>. Our objective is to render a rotating teapot onto a texture map during the first pass, then apply that texture to a cube in the second rendering pass.</p><p>We'll organize these objects into two separate classes: Teapot and Box. You've encountered these classes in previous examples. For simplicity, we'll render only the teapot's normals instead of applying full Phong shading.</p><div class="code-fragments"><pre><code class="language-javascript code-block" startNumber=455>const teapotTextureSize = 512;
<h2 >2.0 Rendering to Textures</h2><p>In this chapter, we will explore 2D techniques. You might wonder why we're focusing on 2D using a 3D API. As it turns out, WebGPU is also highly effective for accelerating 2D processing. Applications include image and video processing, user interfaces, and more. Therefore, we aim to cover some fundamental 2D-related topics.</p><a href="https://shi-yan.github.io/WebGPUUnleashed/code/code.html#2_00_render_to_textures" target="_blank" class="comment"><svg style="margin-right:10px;vertical-align: middle;" xmlns="http://www.w3.org/2000/svg" height="32"
width="32" fill="#dadadb" viewBox="0 -960 960 960"><path d="M189-160q-60 0-102.5-43T42-307q0-9 1-18t3-18l84-336q14-54 57-87.5t98-33.5h390q55 0 98 33.5t57 87.5l84 336q2 9 3.5 18.5T919-306q0 61-43.5 103.5T771-160q-42 0-78-22t-54-60l-28-58q-5-10-15-15t-21-5H385q-11 0-21 5t-15 15l-28 58q-18 38-54 60t-78 22Zm3-80q19 0 34.5-10t23.5-27l28-57q15-31 44-48.5t63-17.5h190q34 0 63 18t45 48l28 57q8 17 23.5 27t34.5 10q28 0 48-18.5t21-46.5q0 1-2-19l-84-335q-7-27-28-44t-49-17H285q-28 0-49.5 17T208-659l-84 335q-2 6-2 18 0 28 20.5 47t49.5 19Zm348-280q17 0 28.5-11.5T580-560q0-17-11.5-28.5T540-600q-17 0-28.5 11.5T500-560q0 17 11.5 28.5T540-520Zm80-80q17 0 28.5-11.5T660-640q0-17-11.5-28.5T620-680q-17 0-28.5 11.5T580-640q0 17 11.5 28.5T620-600Zm0 160q17 0 28.5-11.5T660-480q0-17-11.5-28.5T620-520q-17 0-28.5 11.5T580-480q0 17 11.5 28.5T620-440Zm80-80q17 0 28.5-11.5T740-560q0-17-11.5-28.5T700-600q-17 0-28.5 11.5T660-560q0 17 11.5 28.5T700-520Zm-360 60q13 0 21.5-8.5T370-490v-40h40q13 0 21.5-8.5T440-560q0-13-8.5-21.5T410-590h-40v-40q0-13-8.5-21.5T340-660q-13 0-21.5 8.5T310-630v40h-40q-13 0-21.5 8.5T240-560q0 13 8.5 21.5T270-530h40v40q0 13 8.5 21.5T340-460Zm140-20Z"/></svg>Launch Playground - 2_00_render_to_textures</a><p>In this tutorial, we'll discuss the "render to texture" technique, a concept you may find similarity from our previous discussion on mipmaps. This technique involves two rendering passes. In the first pass, we use a texture map as the render target, and render a 3D scene onto that texture map. In the second pass, we render again using that texture map. This approach is useful in creating mirrors or dynamic reflections in 3D scenes, among other applications.</p><p>Now, let's examine the code. In this example, we'll work with two shaders: the <code>teapot_shader</code> and the <code>box_shader</code>. Our objective is to render a rotating teapot onto a texture map during the first pass, then apply that texture to a cube in the second rendering pass.</p><p>We'll organize these objects into two separate classes: Teapot and Box. You've encountered these classes in previous examples. For simplicity, we'll render only the teapot's normals instead of applying full Phong shading.</p><div class="code-fragments"><pre><code class="language-javascript code-block" startNumber=455>const teapotTextureSize = 512;

const depthTextureForTeapotDesc = {
size: [teapotTextureSize, teapotTextureSize, 1],
Expand Down
2 changes: 0 additions & 2 deletions code/2_01_orthogonal_cameras/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,7 @@

let translateMatrix = glMatrix.mat4.lookAt(glMatrix.mat4.create(),
glMatrix.vec3.fromValues(0, 0, 10), glMatrix.vec3.fromValues(0, 0, 0), glMatrix.vec3.fromValues(0.0, 1.0, 0.0));

let orthProjMatrix = glMatrix.mat4.ortho(glMatrix.mat4.create(), -320.0, 320.0, 240.0, -240.0, -1000.0, 1000.0);

let translateMatrixUniformBuffer = createGPUBuffer(device, translateMatrix, GPUBufferUsage.UNIFORM);

let projectionMatrixUniformBuffer = createGPUBuffer(device, orthProjMatrix, GPUBufferUsage.UNIFORM);
Expand Down

0 comments on commit 9cc97bf

Please sign in to comment.