Draw a Circle With C++ and Glm

Transformations

Getting-started/Transformations

We at present know how to create objects, color them and/or requite them a detailed appearance using textures, but they're still not that interesting since they're all static objects. We could effort and brand them move past changing their vertices and re-configuring their buffers each frame, simply that's cumbersome and costs quite some processing ability. There are much meliorate ways to transform an object and that'southward by using (multiple) matrix objects. This doesn't mean nosotros're going to talk well-nigh Kung Fu and a big digital bogus earth.

Matrices are very powerful mathematical constructs that seem scary at first, but once you'll abound accustomed to them they'll show extremely useful. When discussing matrices, we'll have to brand a small dive into some mathematics and for the more mathematically inclined readers I'll mail service boosted resource for further reading.

However, to fully understand transformations we first accept to delve a bit deeper into vectors before discussing matrices. The focus of this chapter is to requite y'all a basic mathematical background in topics we volition crave afterward on. If the subjects are difficult, attempt to sympathise them as much as you can and come up back to this chapter later to review the concepts whenever you need them.

Vectors

In its most bones definition, vectors are directions and nothing more. A vector has a direction and a magnitude (as well known as its strength or length). Yous can call back of vectors like directions on a treasure map: 'go left 10 steps, now go n 3 steps and become correct 5 steps'; hither 'left' is the direction and '10 steps' is the magnitude of the vector. The directions for the treasure map thus contains 3 vectors. Vectors can have whatever dimension, but we usually piece of work with dimensions of 2 to 4. If a vector has 2 dimensions information technology represents a management on a airplane (think of 2D graphs) and when it has 3 dimensions it tin represent any direction in a 3D globe.

Beneath y'all'll come across three vectors where each vector is represented with (x,y) every bit arrows in a 2D graph. Considering it is more than intuitive to display vectors in 2D (rather than 3D) you lot can think of the 2D vectors equally 3D vectors with a z coordinate of 0. Since vectors represent directions, the origin of the vector does non change its value. In the graph below we tin meet that the vectors \(\color{red}{\bar{v}}\) and \(\color{blueish}{\bar{w}}\) are equal fifty-fifty though their origin is different:

When describing vectors mathematicians generally prefer to depict vectors equally character symbols with a piddling bar over their head like \(\bar{5}\). Too, when displaying vectors in formulas they are generally displayed as follows: \[\bar{5} = \begin{pmatrix} \color{ruby-red}ten \\ \color{green}y \\ \color{blue}z \finish{pmatrix} \]

Because vectors are specified as directions it is sometimes hard to visualize them as positions. If we want to visualize vectors every bit positions we tin can imagine the origin of the management vector to exist (0,0,0) and then indicate towards a certain direction that specifies the point, making it a position vector (we could also specify a different origin and then say: 'this vector points to that point in space from this origin'). The position vector (three,5) would then point to (3,5) on the graph with an origin of (0,0). Using vectors nosotros tin thus describe directions and positions in 2D and 3D space.

Simply like with normal numbers nosotros can likewise define several operations on vectors (some of which y'all've already seen).

Scalar vector operations

A scalar is a single digit. When adding/subtracting/multiplying or dividing a vector with a scalar nosotros only add together/subtract/multiply or dissever each element of the vector by the scalar. For improver it would look like this: \[ \begin{pmatrix} \colour{cherry-red}1 \\ \color{green}2 \\ \color{blue}iii \end{pmatrix} + 10 \rightarrow \brainstorm{pmatrix} \color{red}1 \\ \color{dark-green}2 \\ \color{blue}iii \end{pmatrix} + \begin{pmatrix} 10 \\ x \\ 10 \end{pmatrix} = \begin{pmatrix} \color{cherry-red}one + x \\ \color{light-green}2 + x \\ \color{blue}three + x \end{pmatrix} \] Where \(+\) tin can be \(+\),\(-\),\(\cdot\) or \(\div\) where \(\cdot\) is the multiplication operator.

Vector negation

Negating a vector results in a vector in the reversed direction. A vector pointing north-east would point south-west afterwards negation. To negate a vector we add a minus-sign to each component (you lot can as well represent information technology as a scalar-vector multiplication with a scalar value of -1): \[-\bar{v} = -\begin{pmatrix} \color{cherry}{v_x} \\ \color{bluish}{v_y} \\ \color{greenish}{v_z} \stop{pmatrix} = \begin{pmatrix} -\color{carmine}{v_x} \\ -\color{blue}{v_y} \\ -\colour{green}{v_z} \end{pmatrix} \]

Addition and subtraction

Addition of two vectors is divers equally component-wise addition, that is each component of one vector is added to the same component of the other vector like and so: \[\bar{v} = \begin{pmatrix} \color{red}one \\ \colour{green}2 \\ \color{blue}3 \end{pmatrix}, \bar{k} = \brainstorm{pmatrix} \color{red}4 \\ \color{green}5 \\ \color{blue}half-dozen \end{pmatrix} \rightarrow \bar{5} + \bar{g} = \begin{pmatrix} \color{ruby}1 + \color{cherry}4 \\ \colour{light-green}two + \color{light-green}v \\ \colour{blue}iii + \colour{blue}half-dozen \cease{pmatrix} = \begin{pmatrix} \color{cherry-red}five \\ \color{green}7 \\ \colour{blueish}ix \end{pmatrix} \] Visually, information technology looks like this on vectors v=(4,2) and k=(1,2), where the second vector is added on pinnacle of the first vector's finish to find the end point of the resulting vector (caput-to-tail method):

Simply like normal addition and subtraction, vector subtraction is the aforementioned equally addition with a negated 2d vector: \[\bar{v} = \begin{pmatrix} \color{red}{one} \\ \color{light-green}{2} \\ \color{blue}{iii} \stop{pmatrix}, \bar{k} = \begin{pmatrix} \color{red}{four} \\ \color{dark-green}{five} \\ \color{blue}{6} \stop{pmatrix} \rightarrow \bar{v} + -\bar{k} = \begin{pmatrix} \color{red}{1} + (-\colour{red}{iv}) \\ \color{dark-green}{ii} + (-\color{light-green}{v}) \\ \color{blue}{3} + (-\color{blueish}{6}) \stop{pmatrix} = \begin{pmatrix} -\colour{carmine}{iii} \\ -\color{green}{3} \\ -\color{blue}{3} \end{pmatrix} \]

Subtracting two vectors from each other results in a vector that'southward the deviation of the positions both vectors are pointing at. This proves useful in sure cases where we need to call up a vector that's the divergence between two points.

Length

To retrieve the length/magnitude of a vector nosotros apply the Pythagoras theorem that you lot may call up from your math classes. A vector forms a triangle when you visualize its individual x and y component as ii sides of a triangle:

Since the length of the two sides (x, y) are known and we want to know the length of the tilted side \(\color{cherry}{\bar{v}}\) nosotros tin can calculate information technology using the Pythagoras theorem equally: \[||\color{ruddy}{\bar{v}}|| = \sqrt{\color{green}x^ii + \color{bluish}y^2} \] Where \(||\color{red}{\bar{v}}||\) is denoted as the length of vector \(\color{blood-red}{\bar{five}}\). This is easily extended to 3D by adding \(z^2\) to the equation.

In this case the length of vector (iv, two) equals: \[||\color{cherry}{\bar{v}}|| = \sqrt{\color{green}4^2 + \color{blueish}ii^2} = \sqrt{\color{light-green}16 + \color{blue}4} = \sqrt{20} = iv.47 \] Which is 4.47.

There is too a special type of vector that nosotros call a unit vector. A unit vector has one extra property and that is that its length is exactly 1. We can calculate a unit of measurement vector \(\hat{n}\) from any vector by dividing each of the vector'southward components past its length: \[\lid{n} = \frac{\bar{v}}{||\bar{5}||}\] We call this normalizing a vector. Unit vectors are displayed with a little roof over their caput and are mostly easier to work with, especially when we only care almost their directions (the direction does not change if we alter a vector'due south length).

Vector-vector multiplication

Multiplying two vectors is a scrap of a weird case. Normal multiplication isn't really defined on vectors since it has no visual meaning, but we have ii specific cases that nosotros could choose from when multiplying: one is the dot product denoted as \(\bar{v} \cdot \bar{k}\) and the other is the cross product denoted as \(\bar{5} \times \bar{chiliad}\).

Dot product

The dot production of two vectors is equal to the scalar product of their lengths times the cosine of the bending betwixt them. If this sounds confusing have a look at its formula: \[\bar{v} \cdot \bar{one thousand} = ||\bar{5}|| \cdot ||\bar{k}|| \cdot \cos \theta \] Where the angle between them is represented every bit theta (\(\theta\)). Why is this interesting? Well, imagine if \(\bar{v}\) and \(\bar{k}\) are unit of measurement vectors then their length would be equal to 1. This would effectively reduce the formula to: \[\hat{v} \cdot \lid{k} = 1 \cdot 1 \cdot \cos \theta = \cos \theta\] At present the dot product only defines the angle between both vectors. You lot may recollect that the cosine or cos part becomes 0 when the angle is 90 degrees or ane when the angle is 0. This allows us to easily exam if the ii vectors are orthogonal or parallel to each other using the dot product (orthogonal ways the vectors are at a right-angle to each other). In case y'all want to know more almost the sin or the cos functions I'd suggest the post-obit Khan Academy videos virtually basic trigonometry.

You tin also calculate the angle between two non-unit vectors, merely then you'd take to separate the lengths of both vectors from the result to exist left with \(cos \theta\).

So how do we calculate the dot product? The dot product is a component-wise multiplication where nosotros add the results together. It looks similar this with two unit vectors (y'all can verify that both their lengths are exactly 1): \[ \begin{pmatrix} \colour{blood-red}{0.half dozen} \\ -\colour{green}{0.8} \\ \color{blue}0 \terminate{pmatrix} \cdot \begin{pmatrix} \color{red}0 \\ \color{green}1 \\ \color{blue}0 \finish{pmatrix} = (\color{red}{0.half-dozen} * \color{carmine}0) + (-\colour{greenish}{0.8} * \color{dark-green}i) + (\color{blue}0 * \color{blue}0) = -0.8 \] To calculate the degree between both these unit vectors nosotros use the inverse of the cosine function \(cos^{-1}\) and this results in 143.one degrees. We now finer calculated the bending betwixt these 2 vectors. The dot production proves very useful when doing lighting calculations later on.

Cross production

The cross production is only defined in 3D infinite and takes 2 non-parallel vectors as input and produces a third vector that is orthogonal to both the input vectors. If both the input vectors are orthogonal to each other besides, a cross product would outcome in 3 orthogonal vectors; this will prove useful in the upcoming chapters. The following image shows what this looks like in 3D space:

Unlike the other operations, the cross product isn't really intuitive without delving into linear algebra so it'southward best to only memorize the formula and you'll exist fine (or don't, you'll probably be fine too). Beneath you lot'll see the cross product betwixt 2 orthogonal vectors A and B: \[\brainstorm{pmatrix} \color{cherry-red}{A_{10}} \\ \colour{greenish}{A_{y}} \\ \colour{blue}{A_{z}} \end{pmatrix} \times \begin{pmatrix} \color{ruddy}{B_{x}} \\ \color{greenish}{B_{y}} \\ \color{blueish}{B_{z}} \end{pmatrix} = \brainstorm{pmatrix} \color{green}{A_{y}} \cdot \color{blue}{B_{z}} - \color{blue}{A_{z}} \cdot \color{green}{B_{y}} \\ \color{blue}{A_{z}} \cdot \color{red}{B_{x}} - \colour{red}{A_{x}} \cdot \color{blue}{B_{z}} \\ \color{reddish}{A_{x}} \cdot \color{green}{B_{y}} - \color{green}{A_{y}} \cdot \color{ruddy}{B_{x}} \cease{pmatrix} \] As yous can run across, it doesn't really seem to make sense. However, if you merely follow these steps you lot'll get some other vector that is orthogonal to your input vectors.

Matrices

Now that we've discussed nearly all there is to vectors it is fourth dimension to enter the matrix! A matrix is a rectangular assortment of numbers, symbols and/or mathematical expressions. Each individual particular in a matrix is called an chemical element of the matrix. An example of a 2x3 matrix is shown below: \[\brainstorm{bmatrix} 1 & two & three \\ 4 & five & 6 \end{bmatrix}\] Matrices are indexed by (i,j) where i is the row and j is the column, that is why the above matrix is called a 2x3 matrix (three columns and 2 rows, also known as the dimensions of the matrix). This is the opposite of what you're used to when indexing second graphs as (x,y). To retrieve the value 4 nosotros would index it as (ii,one) (2d row, kickoff column).

Matrices are basically nix more that, but rectangular arrays of mathematical expressions. They do have a very nice set of mathematical backdrop and just like vectors we can define several operations on matrices, namely: add-on, subtraction and multiplication.

Addition and subtraction

Matrix addition and subtraction between two matrices is washed on a per-element basis. So the same general rules employ that we're familiar with for normal numbers, but done on the elements of both matrices with the same alphabetize. This does mean that add-on and subtraction is only defined for matrices of the same dimensions. A 3x2 matrix and a 2x3 matrix (or a 3x3 matrix and a 4x4 matrix) cannot be added or subtracted together. Permit'southward see how matrix addition works on 2 2x2 matrices: \[\begin{bmatrix} \color{red}1 & \color{carmine}2 \\ \color{green}3 & \colour{light-green}4 \terminate{bmatrix} + \begin{bmatrix} \color{red}five & \color{red}vi \\ \colour{green}vii & \colour{green}8 \cease{bmatrix} = \begin{bmatrix} \color{red}1 + \color{cherry}five & \color{red}2 + \color{red}6 \\ \color{dark-green}3 + \color{green}seven & \color{green}4 + \color{green}8 \end{bmatrix} = \brainstorm{bmatrix} \color{red}half-dozen & \color{red}8 \\ \color{dark-green}{10} & \color{green}{12} \end{bmatrix} \] The aforementioned rules apply for matrix subtraction: \[\brainstorm{bmatrix} \color{red}iv & \color{ruddy}2 \\ \color{dark-green}1 & \color{green}6 \end{bmatrix} - \begin{bmatrix} \color{ruby}2 & \color{red}4 \\ \color{dark-green}0 & \color{green}1 \end{bmatrix} = \begin{bmatrix} \color{red}four - \color{cerise}2 & \colour{cherry}2 - \color{red}4 \\ \color{green}1 - \color{green}0 & \colour{green}six - \color{light-green}1 \end{bmatrix} = \brainstorm{bmatrix} \colour{cerise}two & -\color{red}two \\ \color{green}1 & \color{light-green}5 \terminate{bmatrix} \]

Matrix-scalar products

A matrix-scalar production multiples each element of the matrix past a scalar. The post-obit case illustrates the multiplication: \[\color{green}2 \cdot \brainstorm{bmatrix} i & 2 \\ iii & 4 \finish{bmatrix} = \brainstorm{bmatrix} \color{green}ii \cdot 1 & \color{green}ii \cdot 2 \\ \color{green}two \cdot 3 & \color{green}ii \cdot 4 \terminate{bmatrix} = \begin{bmatrix} two & 4 \\ 6 & eight \end{bmatrix}\] At present it too makes sense as to why those single numbers are called scalars. A scalar basically scales all the elements of the matrix past its value. In the previous example, all elements were scaled by 2.

So far so skillful, all of our cases weren't really too complicated. That is, until we start on matrix-matrix multiplication.

Matrix-matrix multiplication

Multiplying matrices is not necessarily complex, but rather difficult to get comfortable with. Matrix multiplication basically means to follow a set of pre-defined rules when multiplying. There are a few restrictions though:

  1. Yous can merely multiply two matrices if the number of columns on the left-hand side matrix is equal to the number of rows on the correct-hand side matrix.
  2. Matrix multiplication is non commutative that is \(A \cdot B \neq B \cdot A\).

Let'due south get started with an example of a matrix multiplication of 2 2x2 matrices: \[ \brainstorm{bmatrix} \color{red}one & \colour{red}2 \\ \color{dark-green}three & \colour{dark-green}4 \end{bmatrix} \cdot \begin{bmatrix} \color{bluish}5 & \colour{majestic}6 \\ \color{blue}7 & \color{purple}eight \end{bmatrix} = \begin{bmatrix} \color{red}i \cdot \color{blue}5 + \colour{red}2 \cdot \colour{blue}7 & \color{red}i \cdot \color{purple}6 + \colour{red}2 \cdot \color{purple}8 \\ \color{greenish}iii \cdot \color{bluish}five + \color{green}4 \cdot \color{blue}7 & \color{green}3 \cdot \color{purple}6 + \color{green}4 \cdot \color{purple}8 \cease{bmatrix} = \brainstorm{bmatrix} 19 & 22 \\ 43 & 50 \cease{bmatrix} \] Right now you're probably trying to figure out what the hell just happened? Matrix multiplication is a combination of normal multiplication and improver using the left-matrix's rows with the right-matrix's columns. Allow'southward try discussing this with the post-obit image:

We offset take the upper row of the left matrix and then take a column from the right matrix. The row and column that we picked decides which output value of the resulting 2x2 matrix we're going to calculate. If we take the showtime row of the left matrix the resulting value will end up in the first row of the issue matrix, then we pick a column and if it's the first column the issue value volition end up in the first cavalcade of the result matrix. This is exactly the case of the ruby-red pathway. To calculate the bottom-right effect nosotros take the bottom row of the beginning matrix and the rightmost column of the 2nd matrix.

To summate the resulting value we multiply the commencement chemical element of the row and column together using normal multiplication, we do the same for the second elements, third, 4th etc. The results of the individual multiplications are so summed up and nosotros have our result. At present it also makes sense that one of the requirements is that the size of the left-matrix's columns and the right-matrix's rows are equal, otherwise we can't finish the operations!

The result is then a matrix that has dimensions of (north,grand) where n is equal to the number of rows of the left-hand side matrix and grand is equal to the columns of the correct-hand side matrix.

Don't worry if you take difficulties imagining the multiplications inside your head. Just go along trying to do the calculations by hand and render to this page whenever you take difficulties. Over time, matrix multiplication becomes second nature to yous.

Let'southward finish the discussion of matrix-matrix multiplication with a larger example. Attempt to visualize the design using the colors. Every bit a useful exercise, run across if y'all can come up with your own answer of the multiplication and and then compare them with the resulting matrix (once you effort to do a matrix multiplication by mitt yous'll chop-chop go the grasp of them). \[ \begin{bmatrix} \colour{red}4 & \colour{red}2 & \color{ruddy}0 \\ \color{light-green}0 & \color{green}8 & \color{green}1 \\ \color{blue}0 & \color{bluish}1 & \color{blue}0 \end{bmatrix} \cdot \begin{bmatrix} \color{red}iv & \colour{green}2 & \color{blue}1 \\ \color{reddish}two & \color{greenish}0 & \color{bluish}4 \\ \color{reddish}9 & \color{green}4 & \color{bluish}2 \end{bmatrix} = \brainstorm{bmatrix} \color{blood-red}4 \cdot \color{cherry}iv + \color{red}2 \cdot \color{red}two + \color{ruby}0 \cdot \color{scarlet}9 & \color{crimson}four \cdot \colour{green}2 + \color{red}2 \cdot \colour{green}0 + \color{red}0 \cdot \colour{green}4 & \color{blood-red}4 \cdot \color{bluish}1 + \color{cherry}2 \cdot \color{blue}4 + \color{reddish}0 \cdot \color{blue}two \\ \color{green}0 \cdot \color{cherry}4 + \color{green}viii \cdot \color{red}2 + \color{dark-green}one \cdot \color{red}9 & \color{green}0 \cdot \color{green}2 + \color{light-green}eight \cdot \color{light-green}0 + \color{green}1 \cdot \colour{green}4 & \colour{green}0 \cdot \color{bluish}ane + \colour{green}8 \cdot \color{blue}four + \color{green}1 \cdot \color{blueish}ii \\ \color{bluish}0 \cdot \color{crimson}four + \colour{blue}1 \cdot \color{cherry-red}2 + \color{bluish}0 \cdot \color{cherry}9 & \color{blue}0 \cdot \color{green}2 + \color{blue}1 \cdot \color{green}0 + \color{blueish}0 \cdot \colour{greenish}four & \color{bluish}0 \cdot \colour{blue}ane + \colour{blue}one \cdot \color{blue}4 + \color{blue}0 \cdot \color{blue}2 \terminate{bmatrix} \\ = \brainstorm{bmatrix} xx & viii & 12 \\ 25 & 4 & 34 \\ 2 & 0 & 4 \end{bmatrix}\]

Equally you tin can see, matrix-matrix multiplication is quite a cumbersome process and very prone to errors (which is why we unremarkably allow computers do this) and this gets problematic real quick when the matrices go larger. If y'all're still thirsty for more and you're curious virtually some more of the mathematical backdrop of matrices I strongly suggest you take a await at these Khan Academy videos virtually matrices.

Anyways, now that we know how to multiply matrices together, nosotros can showtime getting to the good stuff.

Matrix-Vector multiplication

Up until now we've had our fair share of vectors. We used them to stand for positions, colors and even texture coordinates. Let's move a fleck further downwardly the rabbit pigsty and tell you that a vector is basically a Nx1 matrix where N is the vector's number of components (also known every bit an N-dimensional vector). If you think about it, it makes a lot of sense. Vectors are but like matrices an array of numbers, but with only 1 cavalcade. So, how does this new slice of information assist us? Well, if we have a MxN matrix we can multiply this matrix with our Nx1 vector, since the columns of the matrix are equal to the number of rows of the vector, thus matrix multiplication is defined.

But why do nosotros care if we can multiply matrices with a vector? Well, it simply so happens that there are lots of interesting 2D/3D transformations we can identify within a matrix, and multiplying that matrix with a vector then transforms that vector. In case you're still a scrap confused, let's starting time with a few examples and you'll before long see what we mean.

Identity matrix

In OpenGL we usually work with 4x4 transformation matrices for several reasons and 1 of them is that most of the vectors are of size 4. The virtually simple transformation matrix that we can think of is the identity matrix. The identity matrix is an NxN matrix with only 0s except on its diagonal. As you'll see, this transformation matrix leaves a vector completely unharmed: \[ \begin{bmatrix} \colour{cerise}1 & \color{ruby}0 & \colour{red}0 & \color{cherry-red}0 \\ \colour{dark-green}0 & \color{green}i & \color{light-green}0 & \colour{green}0 \\ \colour{blueish}0 & \color{blue}0 & \color{blue}i & \color{bluish}0 \\ \color{majestic}0 & \colour{purple}0 & \colour{majestic}0 & \color{purple}1 \end{bmatrix} \cdot \begin{bmatrix} ane \\ 2 \\ iii \\ 4 \stop{bmatrix} = \brainstorm{bmatrix} \color{red}1 \cdot i \\ \colour{green}1 \cdot 2 \\ \colour{blue}1 \cdot 3 \\ \colour{purple}i \cdot 4 \terminate{bmatrix} = \begin{bmatrix} 1 \\ 2 \\ three \\ 4 \end{bmatrix} \] The vector is completely untouched. This becomes obvious from the rules of multiplication: the first effect chemical element is each individual chemical element of the offset row of the matrix multiplied with each element of the vector. Since each of the row'southward elements are 0 except the first one, we go: \(\color{cherry}one\cdot1 + \color{red}0\cdot2 + \color{red}0\cdot3 + \colour{cherry}0\cdot4 = one\) and the same applies for the other 3 elements of the vector.

You lot may exist wondering what the use is of a transformation matrix that does not transform? The identity matrix is usually a starting indicate for generating other transformation matrices and if we dig even deeper into linear algebra, a very useful matrix for proving theorems and solving linear equations.

Scaling

When we're scaling a vector we are increasing the length of the arrow by the corporeality we'd like to scale, keeping its direction the aforementioned. Since we're working in either two or 3 dimensions we can define scaling past a vector of 2 or iii scaling variables, each scaling one axis (x, y or z).

Let's endeavour scaling the vector \(\color{cherry}{\bar{v}} = (3,ii)\). We volition scale the vector along the 10-axis past 0.v, thus making it twice as narrow; and we'll scale the vector past two along the y-axis, making it twice as high. Let's see what it looks like if we scale the vector by (0.5,2) every bit \(\color{blueish}{\bar{s}}\):

Keep in mind that OpenGL usually operates in 3D space and so for this 2d example we could set the z-axis calibration to 1, leaving it unharmed. The scaling operation we simply performed is a non-uniform calibration, because the scaling factor is not the same for each centrality. If the scalar would exist equal on all axes it would be called a compatible scale.

Let's start edifice a transformation matrix that does the scaling for us. We saw from the identity matrix that each of the diagonal elements were multiplied with its corresponding vector element. What if we were to change the onesouthward in the identity matrix to 3south? In that example, nosotros would be multiplying each of the vector elements past a value of three and thus finer uniformly scale the vector by 3. If we correspond the scaling variables as \( (\color{ruby}{S_1}, \color{dark-green}{S_2}, \color{blue}{S_3}) \) nosotros can define a scaling matrix on whatever vector \((x,y,z)\) as: \[\begin{bmatrix} \color{cerise}{S_1} & \color{reddish}0 & \color{red}0 & \color{red}0 \\ \color{green}0 & \color{light-green}{S_2} & \color{green}0 & \color{light-green}0 \\ \color{blueish}0 & \color{blue}0 & \color{blue}{S_3} & \color{bluish}0 \\ \colour{majestic}0 & \color{purple}0 & \color{regal}0 & \color{purple}1 \end{bmatrix} \cdot \brainstorm{pmatrix} 10 \\ y \\ z \\ 1 \end{pmatrix} = \brainstorm{pmatrix} \color{cherry-red}{S_1} \cdot ten \\ \color{green}{S_2} \cdot y \\ \color{blue}{S_3} \cdot z \\ 1 \end{pmatrix} \] Annotation that nosotros proceed the fourth scaling value 1. The w component is used for other purposes as we'll run into afterwards on.

Translation

Translation is the process of calculation another vector on top of the original vector to render a new vector with a unlike position, thus moving the vector based on a translation vector. We've already discussed vector addition then this shouldn't be besides new.

Just like the scaling matrix there are several locations on a 4-by-iv matrix that we can utilise to perform certain operations and for translation those are the top-3 values of the quaternary column. If nosotros represent the translation vector as \((\color{blood-red}{T_x},\color{green}{T_y},\colour{blue}{T_z})\) we can define the translation matrix past: \[\begin{bmatrix} \color{cherry}i & \color{scarlet}0 & \colour{red}0 & \color{ruby-red}{T_x} \\ \colour{green}0 & \color{green}1 & \color{green}0 & \color{dark-green}{T_y} \\ \color{blue}0 & \colour{blue}0 & \color{blue}1 & \color{blue}{T_z} \\ \color{purple}0 & \color{purple}0 & \color{purple}0 & \color{purple}1 \end{bmatrix} \cdot \begin{pmatrix} x \\ y \\ z \\ 1 \end{pmatrix} = \begin{pmatrix} x + \color{red}{T_x} \\ y + \color{green}{T_y} \\ z + \color{bluish}{T_z} \\ 1 \end{pmatrix} \] This works because all of the translation values are multiplied by the vector'southward w cavalcade and added to the vector's original values (call back the matrix-multiplication rules). This wouldn't have been possible with a 3-by-3 matrix.

Homogeneous coordinates
The w component of a vector is likewise known as a homogeneous coordinate. To get the 3D vector from a homogeneous vector we divide the x, y and z coordinate by its due west coordinate. Nosotros usually do non notice this since the w component is 1.0 most of the time. Using homogeneous coordinates has several advantages: it allows the states to do matrix translations on 3D vectors (without a w component we tin can't interpret vectors) and in the next affiliate we'll use the w value to create 3D perspective.

Also, whenever the homogeneous coordinate is equal to 0, the vector is specifically known as a

management vector since a vector with a w coordinate of 0 cannot be translated.

With a translation matrix nosotros tin can motility objects in any of the iii axis directions (10, y, z), making it a very useful transformation matrix for our transformation toolkit.

Rotation

The last few transformations were relatively easy to understand and visualize in 2D or 3D space, but rotations are a bit trickier. If y'all want to know exactly how these matrices are constructed I'd recommend that y'all watch the rotation items of Khan University'south linear algebra videos.

Commencement let's define what a rotation of a vector actually is. A rotation in second or 3D is represented with an bending. An angle could be in degrees or radians where a whole circle has 360 degrees or 2 PI radians. I prefer explaining rotations using degrees as we're mostly more than accustomed to them. Most rotation functions crave an angle in radians, simply luckily degrees are hands converted to radians:
angle in degrees = angle in radians * (180 / PI)
angle in radians = angle in degrees * (PI / 180)
Where PI equals (rounded) three.14159265359.
Rotating half a circle rotates u.s. 360/ii = 180 degrees and rotating one/5th to the correct ways we rotate 360/five = 72 degrees to the correct. This is demonstrated for a basic 2D vector where \(\color{red}{\bar{v}}\) is rotated 72 degrees to the right, or clockwise, from \(\color{green}{\bar{k}}\):

Rotations in 3D are specified with an angle and a rotation axis. The angle specified will rotate the object forth the rotation axis given. Effort to visualize this by spinning your head a sure degree while continually looking down a single rotation centrality. When rotating 2D vectors in a 3D world for example, nosotros set the rotation axis to the z-centrality (endeavour to visualize this).

Using trigonometry information technology is possible to transform vectors to newly rotated vectors given an angle. This is usually done via a smart combination of the sine and cosine functions (ordinarily abbreviated to sin and cos). A discussion of how the rotation matrices are generated is out of the scope of this chapter.

A rotation matrix is defined for each unit of measurement axis in 3D space where the angle is represented every bit the theta symbol \(\theta\).

Rotation around the X-axis: \[\begin{bmatrix} \color{cherry}i & \color{red}0 & \color{crimson}0 & \color{red}0 \\ \color{green}0 & \color{dark-green}{\cos \theta} & - \color{light-green}{\sin \theta} & \colour{green}0 \\ \color{blueish}0 & \color{blue}{\sin \theta} & \color{blue}{\cos \theta} & \color{blue}0 \\ \color{purple}0 & \color{purple}0 & \color{purple}0 & \color{purple}one \end{bmatrix} \cdot \begin{pmatrix} 10 \\ y \\ z \\ ane \end{pmatrix} = \begin{pmatrix} 10 \\ \color{green}{\cos \theta} \cdot y - \color{green}{\sin \theta} \cdot z \\ \color{blue}{\sin \theta} \cdot y + \color{bluish}{\cos \theta} \cdot z \\ ane \end{pmatrix}\]

Rotation around the Y-axis: \[\begin{bmatrix} \color{ruby-red}{\cos \theta} & \colour{cherry}0 & \color{red}{\sin \theta} & \color{carmine}0 \\ \color{green}0 & \color{green}1 & \colour{green}0 & \color{green}0 \\ - \color{blue}{\sin \theta} & \color{bluish}0 & \colour{blue}{\cos \theta} & \color{bluish}0 \\ \color{royal}0 & \color{purple}0 & \colour{purple}0 & \color{purple}1 \cease{bmatrix} \cdot \begin{pmatrix} x \\ y \\ z \\ 1 \stop{pmatrix} = \begin{pmatrix} \color{red}{\cos \theta} \cdot x + \color{red}{\sin \theta} \cdot z \\ y \\ - \color{blueish}{\sin \theta} \cdot x + \color{blue}{\cos \theta} \cdot z \\ 1 \end{pmatrix} \]

Rotation effectually the Z-axis: \[\begin{bmatrix} \color{cherry-red}{\cos \theta} & - \color{red}{\sin \theta} & \color{red}0 & \colour{ruby-red}0 \\ \color{green}{\sin \theta} & \color{dark-green}{\cos \theta} & \colour{green}0 & \colour{green}0 \\ \color{blue}0 & \color{blue}0 & \color{blue}1 & \color{blueish}0 \\ \color{purple}0 & \color{purple}0 & \color{purple}0 & \colour{purple}1 \end{bmatrix} \cdot \brainstorm{pmatrix} x \\ y \\ z \\ 1 \stop{pmatrix} = \begin{pmatrix} \color{carmine}{\cos \theta} \cdot x - \color{red}{\sin \theta} \cdot y \\ \color{dark-green}{\sin \theta} \cdot x + \color{green}{\cos \theta} \cdot y \\ z \\ i \end{pmatrix} \]

Using the rotation matrices we can transform our position vectors effectually one of the iii unit axes. To rotate around an arbitrary 3D axis nosotros can combine all 3 them by first rotating around the X-axis, then Y and and then Z for case. Nonetheless, this apace introduces a trouble chosen Gimbal lock. We won't hash out the details, only a ameliorate solution is to rotate around an arbitrary unit axis eastward.thousand. (0.662,0.2,0.722) (note that this is a unit of measurement vector) right away instead of combining the rotation matrices. Such a (verbose) matrix exists and is given below with \((\color{red}{R_x}, \color{green}{R_y}, \color{bluish}{R_z})\) as the arbitrary rotation centrality: \[\begin{bmatrix} \cos \theta + \color{red}{R_x}^two(1 - \cos \theta) & \color{ruby-red}{R_x}\color{green}{R_y}(1 - \cos \theta) - \color{blueish}{R_z} \sin \theta & \color{ruddy}{R_x}\color{blue}{R_z}(1 - \cos \theta) + \color{light-green}{R_y} \sin \theta & 0 \\ \color{green}{R_y}\color{scarlet}{R_x} (1 - \cos \theta) + \color{blue}{R_z} \sin \theta & \cos \theta + \color{green}{R_y}^2(1 - \cos \theta) & \color{light-green}{R_y}\color{blueish}{R_z}(one - \cos \theta) - \color{cherry-red}{R_x} \sin \theta & 0 \\ \colour{blue}{R_z}\color{crimson}{R_x}(1 - \cos \theta) - \color{light-green}{R_y} \sin \theta & \color{blueish}{R_z}\color{greenish}{R_y}(1 - \cos \theta) + \color{red}{R_x} \sin \theta & \cos \theta + \color{blueish}{R_z}^ii(i - \cos \theta) & 0 \\ 0 & 0 & 0 & 1 \stop{bmatrix}\] A mathematical discussion of generating such a matrix is out of the scope of this chapter. Keep in mind that even this matrix does not completely forestall gimbal lock (although information technology gets a lot harder). To truly forbid Gimbal locks we have to represent rotations using quaternions, that are non only safer, but also more computationally friendly. However, a word of quaternions is out of this chapter's scope.

Combining matrices

The true ability from using matrices for transformations is that we can combine multiple transformations in a unmarried matrix thanks to matrix-matrix multiplication. Let's see if nosotros can generate a transformation matrix that combines several transformations. Say nosotros have a vector (x,y,z) and we desire to calibration it past 2 and so translate it by (ane,2,3). We need a translation and a scaling matrix for our required steps. The resulting transformation matrix would and then wait like: \[Trans . Scale = \begin{bmatrix} \color{red}i & \color{carmine}0 & \color{red}0 & \color{red}1 \\ \color{green}0 & \color{greenish}1 & \color{green}0 & \color{light-green}2 \\ \color{bluish}0 & \color{blueish}0 & \colour{blue}1 & \color{blue}three \\ \colour{purple}0 & \color{purple}0 & \color{purple}0 & \color{royal}1 \end{bmatrix} . \begin{bmatrix} \color{red}2 & \color{red}0 & \colour{red}0 & \color{ruddy}0 \\ \color{greenish}0 & \color{green}2 & \color{green}0 & \color{greenish}0 \\ \color{blue}0 & \colour{blueish}0 & \colour{blue}2 & \color{bluish}0 \\ \colour{majestic}0 & \color{majestic}0 & \color{regal}0 & \color{purple}1 \terminate{bmatrix} = \begin{bmatrix} \color{scarlet}two & \color{red}0 & \color{ruddy}0 & \color{red}1 \\ \colour{light-green}0 & \colour{green}2 & \color{dark-green}0 & \color{dark-green}2 \\ \colour{blue}0 & \color{blueish}0 & \color{blue}2 & \color{blueish}3 \\ \color{purple}0 & \color{majestic}0 & \color{purple}0 & \color{royal}one \stop{bmatrix} \] Notation that nosotros first do a translation and then a scale transformation when multiplying matrices. Matrix multiplication is non commutative, which means their order is important. When multiplying matrices the right-most matrix is first multiplied with the vector then you should read the multiplications from right to left. Information technology is advised to first do scaling operations, so rotations and lastly translations when combining matrices otherwise they may (negatively) affect each other. For example, if you lot would commencement exercise a translation then scale, the translation vector would also scale!

Running the final transformation matrix on our vector results in the following vector: \[\brainstorm{bmatrix} \color{blood-red}2 & \color{red}0 & \color{ruby}0 & \color{red}1 \\ \color{green}0 & \color{green}2 & \color{green}0 & \colour{dark-green}2 \\ \color{blue}0 & \color{blue}0 & \colour{bluish}ii & \colour{blue}3 \\ \colour{purple}0 & \color{purple}0 & \color{purple}0 & \color{majestic}one \end{bmatrix} . \brainstorm{bmatrix} x \\ y \\ z \\ 1 \end{bmatrix} = \begin{bmatrix} \colour{red}2x + \colour{crimson}ane \\ \color{green}2y + \color{dark-green}ii \\ \color{bluish}2z + \colour{blueish}3 \\ i \end{bmatrix} \] Great! The vector is first scaled by ii and so translated past (1,two,3).

In practice

At present that we've explained all the theory backside transformations, it's fourth dimension to run into how we tin actually use this knowledge to our advantage. OpenGL does not have any form of matrix or vector knowledge congenital in, then we take to ascertain our ain mathematics classes and functions. In this book we'd rather abstruse from all the tiny mathematical details and simply use pre-made mathematics libraries. Luckily, at that place is an easy-to-use and tailored-for-OpenGL mathematics library chosen GLM.

GLM

GLM stands for Open upGL Mathematics and is a header-only library, which means that we only take to include the proper header files and nosotros're done; no linking and compiling necessary. GLM can be downloaded from their website. Copy the root directory of the header files into your includes folder and let'south get rolling.

Nearly of GLM's functionality that nosotros need can be found in three headers files that we'll include as follows:

                      #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/type_ptr.hpp>                  

Allow's see if we can put our transformation knowledge to good use past translating a vector of (ane,0,0) past (1,1,0) (note that we define it as a glm::vec4 with its homogeneous coordinate set to 1.0:

                      glm::vec4 vec(i.0f, 0.0f, 0.0f, i.0f); glm::mat4 trans = glm::mat4(1.0f); trans =            glm::interpret(trans, glm::vec3(1.0f, 1.0f, 0.0f)); vec = trans * vec; std::cout << vec.ten << vec.y << vec.z << std::endl;                  

We first ascertain a vector named vec using GLM'due south built-in vector class. Side by side we ascertain a mat4 and explicitly initialize it to the identity matrix by initializing the matrix'southward diagonals to 1.0; if we practise not initialize it to the identity matrix the matrix would be a nil matrix (all elements 0) and all subsequent matrix operations would end upwards a null matrix every bit well.

The next step is to create a transformation matrix by passing our identity matrix to the glm::translate role, together with a translation vector (the given matrix is then multiplied with a translation matrix and the resulting matrix is returned).
So nosotros multiply our vector by the transformation matrix and output the result. If nosotros nonetheless remember how matrix translation works then the resulting vector should be (1+1,0+1,0+0) which is (ii,ane,0). This snippet of code outputs 210 and then the translation matrix did its task.

Let'due south do something more than interesting and scale and rotate the container object from the previous chapter:

                      glm::mat4 trans = glm::mat4(ane.0f); trans =            glm::rotate(trans,            glm::radians(90.0f), glm::vec3(0.0, 0.0, 1.0)); trans =            glm::scale(trans, glm::vec3(0.5, 0.five, 0.5));                  

First we scale the container by 0.5 on each axis and and then rotate the container 90 degrees effectually the Z-axis. GLM expects its angles in radians so we convert the degrees to radians using glm::radians . Note that the textured rectangle is on the XY plane and so we want to rotate effectually the Z-axis. Keep in mind that the axis that we rotate around should be a unit vector, and so be sure to normalize the vector offset if you're not rotating effectually the X, Y, or Z axis. Because we pass the matrix to each of GLM's functions, GLM automatically multiples the matrices together, resulting in a transformation matrix that combines all the transformations.

The next large question is: how practise we get the transformation matrix to the shaders? We before long mentioned before that GLSL also has a mat4 type. So nosotros'll adapt the vertex shader to accept a mat4 uniform variable and multiply the position vector by the matrix compatible:

                      #version 330 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec2 aTexCoord;  out vec2 TexCoord;    uniform mat4 transform;  void principal() {     gl_Position = transform * vec4(aPos, ane.0f);     TexCoord = vec2(aTexCoord.x, aTexCoord.y); }                  
GLSL also has mat2 and mat3 types that let for swizzling-like operations simply like vectors. All the aforementioned math operations (like scalar-matrix multiplication, matrix-vector multiplication and matrix-matrix multiplication) are immune on the matrix types. Wherever special matrix operations are used we'll be sure to explain what's happening.

Nosotros added the uniform and multiplied the position vector with the transformation matrix before passing it to gl_Position. Our container should now be twice as pocket-sized and rotated 90 degrees (tilted to the left). We still need to pass the transformation matrix to the shader though:

                      unsigned int transformLoc =            glGetUniformLocation(ourShader.ID, "transform");            glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans));                  

We first query the location of the uniform variable and so transport the matrix information to the shaders using glUniform with Matrix4fv as its postfix. The first argument should be familiar by now which is the uniform's location. The second argument tells OpenGL how many matrices we'd like to ship, which is 1. The third argument asks united states if we want to transpose our matrix, that is to swap the columns and rows. OpenGL developers ofttimes utilise an internal matrix layout called column-major ordering which is the default matrix layout in GLM then in that location is no need to transpose the matrices; we can proceed it at GL_FALSE. The terminal parameter is the bodily matrix data, but GLM stores their matrices' data in a style that doesn't e'er match OpenGL's expectations so we kickoff convert the information with GLM's built-in part value_ptr.

Nosotros created a transformation matrix, alleged a compatible in the vertex shader and sent the matrix to the shaders where nosotros transform our vertex coordinates. The result should look something like this:

Perfect! Our container is indeed tilted to the left and twice equally minor and then the transformation was successful. Let's get a petty more than funky and come across if we tin can rotate the container over time, and for fun nosotros'll too reposition the container at the bottom-correct side of the window. To rotate the container over time we accept to update the transformation matrix in the render loop considering information technology needs to update each frame. We employ GLFW's time function to get an angle over time:

                      glm::mat4 trans = glm::mat4(one.0f); trans =            glm::translate(trans, glm::vec3(0.5f, -0.5f, 0.0f)); trans =            glm::rotate(trans, (float)glfwGetTime(), glm::vec3(0.0f, 0.0f, 1.0f));                  

Continue in mind that in the previous case we could declare the transformation matrix anywhere, but at present we have to create information technology every iteration to continuously update the rotation. This means we have to re-create the transformation matrix in each iteration of the render loop. Usually when rendering scenes we have several transformation matrices that are re-created with new values each frame.

Here we offset rotate the container around the origin (0,0,0) and in one case it's rotated, we translate its rotated version to the bottom-right corner of the screen. Recollect that the bodily transformation lodge should be read in reverse: even though in code we first translate and then later rotate, the actual transformations showtime apply a rotation and then a translation. Understanding all these combinations of transformations and how they apply to objects is hard to empathise. Try and experiment with transformations like these and you'll quickly get a grasp of it.

If you lot did things right you should become the following effect:

And there you lot take it. A translated container that's rotated over time, all done by a single transformation matrix! Now you can see why matrices are such a powerful construct in graphics state. We can ascertain an infinite amount of transformations and combine them all in a single matrix that we tin re-use as frequently as we'd like. Using transformations like this in the vertex shader saves u.s.a. the effort of re-defining the vertex data and saves u.s.a. some processing time too, since we don't have to re-ship our information all the time (which is quite slow); all we need to do is update the transformation compatible.

If you lot didn't become the right result or you're stuck somewhere else, take a look at the source code and the updated shader form.

In the next chapter nosotros'll talk over how we can use matrices to define different coordinate spaces for our vertices. This will be our beginning step into 3D graphics!

Farther reading

  • Essence of Linear Algebra: great video tutorial series by Grant Sanderson nearly the underlying mathematics of transformations and linear algebra.

Exercises

  • Using the last transformation on the container, try switching the gild around by get-go rotating and and so translating. See what happens and attempt to reason why this happens: solution.
  • Try drawing a second container with another telephone call to glDrawElements just place it at a different position using transformations merely. Brand certain this 2nd container is placed at the summit-left of the window and instead of rotating, calibration it over time (using the sin function is useful here; annotation that using sin will crusade the object to invert as soon as a negative calibration is applied): solution.

craneboymor.blogspot.com

Source: https://learnopengl.com/Getting-started/Transformations

0 Response to "Draw a Circle With C++ and Glm"

ارسال یک نظر

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel