About Social Code
summaryrefslogtreecommitdiff
path: root/html/notes
diff options
context:
space:
mode:
Diffstat (limited to 'html/notes')
-rw-r--r--html/notes/converting_from_3d_to_2d.html161
1 files changed, 161 insertions, 0 deletions
diff --git a/html/notes/converting_from_3d_to_2d.html b/html/notes/converting_from_3d_to_2d.html
new file mode 100644
index 0000000..547927d
--- /dev/null
+++ b/html/notes/converting_from_3d_to_2d.html
@@ -0,0 +1,161 @@
+<!doctype html>
+
+<html class="html-note-page" lang="en">
+<head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+
+ <title>Converting from 3D to 2D</title>
+ <meta name="dcterms.date" content="2023-09-25" />
+
+ <link rel="stylesheet" href="/assets/style.css">
+ <link rel="icon" type="image/x-icon" href="/assets/favicon.svg">
+ <link rel="alternate" type="application/atom+xml" title="Fryzek Concepts" href="/feed.xml">
+</head>
+
+<body>
+ <div class="header-bar">
+ <a href="/index.html">
+ <img src="/assets/favicon.svg" alt="frycon logo">
+ </a>
+ <div class="header-links">
+ <a href="/now.html" class="header-link">Now</a>
+ <a href="/about.html" class="header-link">About</a>
+ <a rel="me" href="https://mastodon.social/@hazematman">Social</a>
+ </div>
+ </div>
+ <main>
+<div class="page-title-header-container">
+ <h1 class="page-title-header">Converting from 3D to 2D</h1>
+ <div class="page-info-container">
+ <div class="plant-status">
+ <img src="/assets/budding.svg">
+ <div class="plant-status-text">
+ <p>budding</p>
+ </div>
+ </div>
+ <div class="page-info-date-container">
+ <p class="page-info-date">Published: 2023-09-25</p>
+ <p class="page-info-date">Last Edited: 2023-09-25</p>
+ </div>
+ </div>
+ </div>
+<div class="note-divider"></div>
+<div class="main-container">
+ <div class="note-body">
+<p>Recently I’ve been working on a project where I needed to convert an
+application written in OpenGL to a software renderer. The matrix
+transformation code in OpenGL made use of the GLM library for matrix
+math, and I needed to convert the 4x4 matrices to be 3x3 matrices to
+work with the software renderer. There was some existing code to do this
+that was broken, and looked something like this:</p>
+<pre><code>glm::mat3 mat3x3 = glm::mat3(mat4x4);</code></pre>
+<p>Don’t worry if you don’t see the problem already, I’m going to
+illustrate in more detail with the example of a translation matrix. In
+3D a standard translation matrix to translate by a vector
+<code>(x, y, z)</code> looks something like this:</p>
+<pre><code>[1 0 0 x]
+[0 1 0 y]
+[0 0 1 z]
+[0 0 0 1]</code></pre>
+<p>Then when we multiply this matrix by a vector like
+<code>(a, b, c, 1)</code> the result is
+<code>(a + x, b + y, c + z, 1)</code>. If you don’t understand why the
+matrix is 4x4 or why we have that extra 1 at the end don’t worry, I’ll
+explain that in more detail later.</p>
+<p>Now using the existing conversion code to get a 3x3 matrix will
+simply take the first 3 columns and first 3 rows of the matrix and
+produce a 3x3 matrix from those. Converting the translation matrix above
+using this code produces the following matrix:</p>
+<pre><code>[1 0 0]
+[0 1 0]
+[0 0 1]</code></pre>
+<p>See the problem now? The <code>(x, y, z)</code> values disappeared!
+In the conversion process we lost these critical values from the
+translation matrix, and now if we multiply by this matrix nothing will
+happen since we are just left with the identity matrix. So if we can’t
+use this simple “cast” function in GLM, what can we use?</p>
+<p>Well one thing we can do is preserve the last column and last row of
+the matrix. So assume we have a 4x4 matrix like this:</p>
+<pre><code>[a b c d]
+[e f g h]
+[i j k l]
+[m n o p]</code></pre>
+<p>Then preserving the last row and column we should get a matrix like
+this:</p>
+<pre><code>[a b d]
+[e f h]
+[m n p]</code></pre>
+<p>And if we use this conversion process for the same translation matrix
+we will get:</p>
+<pre><code>[1 0 x]
+[0 1 y]
+[0 0 1]</code></pre>
+<p>Now we see that the <code>(x, y)</code> part of the translation is
+preserved, and if we try to multiply this matrix by the vector
+<code>(a, b, 1)</code> the result will be
+<code>(a + x, b + y, 1)</code>. The translation is preserved in the
+conversion!</p>
+<h2 id="why-do-we-have-to-use-this-conversion">Why do we have to use
+this conversion?</h2>
+<p>The reason the conversion is more complicated is hidden in how we
+defined the translation matrix and vector we wanted to translate. The
+vector was actually a 4D vector with the final component set to 1. The
+reason we do this is that we actually want to represent an affine space
+instead of just a vector space. An affine space being a type of space
+where you can have both points and vectors. A point is exactly what you
+would expect it to be just a point in space from some origin, and vector
+is a direction with magnitude but no origin. This is important because
+strictly speaking translation isn’t actually defined for vectors in a
+normal vector space. Additionally if you try to construct a matrix to
+represent translation for a vector space you’ll find that its impossible
+to derive a matrix to do this and that operation is not a linear
+function. On the other hand operations like translation are well defined
+in an affine space and do what you would expect.</p>
+<p>To get around the problem of vector spaces, mathematicians more
+clever than I figured out you can implement an affine space in a normal
+vector space by increasing the dimension of the vector space by one, and
+by adding an extra row and column to the transformation matrices used.
+They called this a <strong>homogeneous coordinate system</strong>. This
+lets you say that a vector is actually just a point if the 4th component
+is 1, but if its 0 its just a vector. Using this abstraction one can
+implement all the well defined operations for an affine space (like
+translation!).</p>
+<p>So using the “homogeneous coordinate system” abstraction, translation
+is an operation that defined by taking a point and moving it by a
+vector. Lets look at how that works with the translation matrix I used
+as an example above. If you multiply that matrix by a 4D vector where
+the 4th component is 0, it will just return the same vector. Now if we
+multiply by a 4D vector where the 4th component is 1, it will return the
+point translated by the vector we used to construct that translation
+matrix. This implements the translation operation as its defined in an
+affine space!</p>
+<p>If you’re interested in understanding more about homogeneous
+coordinate spaces, (like how the translation matrix is derived in the
+first place) I would encourage you to look at resources like <a
+href="https://books.google.ca/books/about/Mathematics_for_Computer_Graphics_Applic.html?id=YmQy799flPkC&amp;redir_esc=y">“Mathematics
+for Computer Graphics Applications”</a>. They provide a much more
+detailed explanation than I am providing here. (The homogeneous
+coordinate system also has some benefits for representing projections
+which I won’t get into here, but are explained in that text book.)</p>
+<p>Now to finally answer the question about why we needed to preserve
+those final columns and vectors. Based on what we now know, we weren’t
+actually just converting from a “3D space” to a “2D space” we were
+converting from a “3D homogeneous space” to a “2D homogeneous space”.
+The process of converting from a higher dimension matrix to a lower
+dimensional matrix is lossy and some transformation details are going to
+be lost in process (like for example the translation along the z-axis).
+There is no way to tell what kind of space a given matrix is supposed to
+transform just by looking at the matrix itself. The matrix does not
+carry any information about about what space its operating in and any
+conversion function would need to know that information to properly
+convert that matrix. Therefore we need develop our own conversion
+function that preserves the transformations that are important to our
+application when moving from a “3D homogeneous space” to a “2D
+homogeneous space”.</p>
+<p>Hopefully this explanation helps if you are every working on
+converting 3D transformation code to 2D.</p>
+ </div>
+</div> </main>
+</body>
+</html>