3d Programming Basics: Vector addition/Subtraction

February 26, 2010 5 comments

 

In this post, we’re going to paint a picture in our minds of what goes on as we add or subtract vectors. Then were going to see an example of a couple uses for vector addition/subtraction in 3d programming. The math to add or subtract vectors is not that hard. And if you intend a career in game development, you will even eventually learn all about it and how to perform it with both hands tied behind your back. But for now, you can enjoy the benefits of vector addition and/or subtraction without doing a lick of the math yourself. But what you do need to understand, is why you add or subtract one vector from another. Once you get that down, the math is done behind the scenes for you with built in XNA methods. For example, this code snippet gets the developer the results he needs without needing to work with the math:

Vector3 myVector1 = new Vector3(?, ?, ?);//arbitrary vector

Vector3 myVector2 = new Vector3(?, ?, ?);//different arbitrary vector

Vector3 resultVector = myVector1 + myVector2;

XNA knows how to add the two vectors together behind the scenes using the proper vector math, you can relax and not worry about it. What you really need to concern yourself with is why we wanted to add them in the first place and what the resulting vector can do for your game. As it turns out, just about all motion in 3d programming involves adding or subtracting vectors which have had their length or direction adjusted in order to provide the motion desired.

First, let’s get a visualization foundation for you to use when visualizing vector addition, then we’ll get into examples of why you would add or subtract a vector in a game. In the graphic below are four arbitrary white vectors that will get added together to result in the vector colored in yellow. In code, it would look like this:

Vector3 yellowVector = whiteVec1 + whiteVec2 + whiteVec3 + whiteVec4;

So how do you visualize the four white vectors adding up to the yellow one? By viewing the graphic above, it’s not very intuitive how the yellow vector resulted from the white ones. But simply put, when adding these white vectors, you just line each of the white ones up nose to tail and you will end up in the correct spot, with the last white vector’s arrow-head matching the yellow vector’s arrow-head. Here is a video demonstrating this.

And it doesn’t matter what order you add them (line them up). It will still come out to the correct spot.

If you don’t see the difference between these two videos, run them both again and pause them both about 1 second from the end and you can see that we used a different order to line them up. Since it’s addition, it’s like saying 3+2+7 gets you the same result as 2+7+3.

For subtraction, you simply code it as:

Vector3 result = vector1 – vector2;

Duh, right? Showing the code there is easier than explaining the visualization of that. But here it goes. For visualization purposes, you simply add its opposite. for instance 3 -2 would be the equivalent of saying  3 + (-2). Subtracting 2 is the same as adding -2. Since you are still adding, you can still line the vectors up nose to tail, you just have to line up the opposite vector when subtracting. Here is a video of how the following code should play out in your mind’s eye. We’ll mix it up with some adding & some subtracting.

Vector3 yellowVector = white1 + white2 – white3 – white4;

Notice white3 & white4 get transformed into their opposites before applying (adding) them. That’s real important to see and understand. Also notice I got lazy and didn’t include the resulting yellow vector 😉 .

OK, now that you can ‘see’ what adding or subtracting looks like,  let’s see a couple practical applications of when you would add or subtract a vector. One that comes up often is when you have two game objects, let’s say they are tanks, and you want to figure out what direction a bullet would go if you shot it from tank1 to tank2. You want to create a vector that goes from tank1 to tank2. No math is required, no angles will be worked with.  Here is a graphic to set the scene.

Assume we are keeping track of each tank’s position in a Vector3s. 1 each for tank1Position & tank2Position. To calculate the direction a bullet would go if shot from tank1 to tank2 you would code it like this:

Vector3 bulletDirection = tank2Position – tank1Position; //vector subtraction  like we just went over.

Notice we are wanting the direction from tank number 1 to tank number 2 so we must list tank2 first in the subtraction equation. if you pause the following video as the direction vector appears and think about what would have happened if we had listed tank1 first, you would see that the result would have been backwards. So while adding vectors can be done in any order, if you subtract them, make sure you place them in the order you need them.

  

This resulting vector represents the direction & distance from tank1 to tank2.

In our next example, we’ll use vector addition to move the bullet from tank1 to tank2. Normally, you would move it each frame an amount that would be a factor of how much time has elapsed since the last time you moved it. For the sake of simplicity here and for focusing on the vector addition, let’s just make the bullet to go from tank1 to tanl2 in five frames. Lets take that bulletDirection vector and shorten it to 1/5 the distance to tank2. Then well add a bullet and set it’s position to that of tank1 and each frame well add the bullet velocity to it so it will move from tank1 to tank2.

Vector3 bulletVelocity = bulletDirection * 0.2f;

 //this doesn’t alter the direction the vector is pointing, it just makes it 1/5 the length.

//Then run this next line each frame

bulletPosition += bulletVelocity;

Here is a video demonstrating that the velocity gets added to the bulletPosition each frame. We’re not going to concern ourselves with the direction the turrets are pointing at the moment, we’ll just focus on the vectors representing the bulletPosition & velocityVector.

 

Remember from the previous section’s talk about visualizing a vector differently depending on what information it holds that you happen to need, well, that’s why we don’t visualize the bulletPosition as a ray/arrow. The only bit of information that we use from the bulletPosition vector is the position of its arrow-head (the position in world space that this vector represents). We think of it only as a point in space without care for its direction or length. On the other hand, we do care about the direction and length of the bulletVelocity vector so we vizualize it as an arrow, and since we are not as concerend with its actual position in space, we are free to move it around to any location that suits us.


Categories: 3d Programming

3d Programming basics: What is a vector

February 19, 2010 6 comments

So you probably already know what a vector is. and maybe you already have a way of visualizing them. I once saw a post on the forums where the poster asked “if a vector is like a line, and since a line has two end points, how could you describe a vector by just listing one point”. He asked if there was a universal understanding that the other end point is always supposed to be the origin. He was trying to draw the correct picture in his mind’s eye of what a vector should look like.

A vector can represent a position in your game world. Or it can represent a direction. Let’s take two examples

Vector3 myModelPosition = new Vector3( 1.5f, 1.5f, 1.5f);

Vector3 myModelVelocity = new Vector3(0, 0, -0.5f);

Here is a graphic displaying those two vectors

So other that the component values of these two vectors, they are represented here the same. Both look like black rays emanating from the world origin capped off with a little arrow-head. Yet, in a game, they would be used in a different manner. When you use them in a different manner, it might be useful to visualize them differently.

There at 3 items of information that each vector carries with it at all times. They are:

1.) The direction the vector is pointing.

2.) The length of the vector.

3.) The world space location of the arrowhead end of the vector.

When you use a vector in a game. You generally don’t need all three items of information for every vector. For instance, for the modelPosition vector above, I don’t care what direction the vector is pointing or how long it is. I only care bout the world space location that is represents. In the modelVelocity vector, I couldn’t give a hoot about the world space location. What I care about with that one is the direction it is pointing (because that’s the direction the model will go if I apply this velocity to it) and its length (because I will use the length to set the speed).

Generally speaking, the useful information you will want to extract from any given vector will fall into one of the following 3 categories.

Most common uses of vectors

1.) To hold location information only. Used for setting object positions.

2.) To hold direction and length information only. Used for velocities, forces, movements.

3.) To hold direction information only (a unit length vector). Useful for math calculations (physics, collision, AI… etc.).

When I’m using a vector to represent a location (such as the modelPosition vector above), I don’t visualize it as a ray (arrow). I simply think of it as a point in space. But when I use a vector for the other two purposes, I do think of it as a ray with the arrowhead. Since I’m using modelVelocity for just its direction and length and I don’t care about its location, I can place it any where and still retain its pertinent information.

So to re-draw the above graphic to eliminate the non-useful bits of information and re arrange it to be a more effective visualization, I would probably see this in my mind’s eye:

I colored modelPosition yellow so it could better differentiate itself here. So, in my mind’s eye only, the modelVelocity retained its direction and length (which I care about) but altered it’s location (which I don’t care about). The modelPosition lost it’s direction and length (which I don’t care about) but retained its location information (which I care about). So although we are visualizing two of the same things here (both are vectors) we can visualize them differently but in a way that makes practical sense. If you look back and forth between the two graphics, I hope you would agree that the second one makes it easier to visualize where your model is and which way & how fast it is going.

Categories: 3d Programming

3d Programming Basics: Working with and Visualizing Vectors

February 19, 2010 8 comments

One of the most useful tools in the XNA 3d programmer’s bag is the ability to effectively manipulate vectors. It may be more accurate than you think to say that “the vast majority of 3d programming lies in the effective manipulations of vectors”. Although there is an underlying need to utilize vector math to do this, learning the math itself is not as necessary as you might think. That’s because the Xna framework has so many built-in methods that perform the math for you and that shields you from much of the hard-core math. The thing you as a programmer do need to know is what the framework can do for you and how to use it. So, there won’t be much math going on in this post other than arithmetic but hopefully you can gain an understanding of how to work with vectors.

I seem to have an idea that to work with 3d programming concepts, you must be able to visualize in your mind’s eye what it is that you want to happen through code with a high level of accuracy. For instance, as you write a line of code that, say, transforms a Vector3, I believe it’s important to see it happen in thought. And not just see it, but see it accurately. A person brand new to 3d programming generally has a thick foggy mind’s eye view of these concepts for quite some time until experience slowly warms that conceptual landscape enough to burn off the fog and ‘see’  things happening. Often you read forum posts where the questioner posts some code and expresses frustration because it isn’t doing what they want it to. Someone who reads the posted code, and while doing so watches, in their mind’s eye, what is happening can generally identify the person’s problem. Often, the problem is with the way the OP visualizes their code running. They experience a difference between the visualization and the code. It could be a lack of understanding what the code does or a lack of visualization accuracy. The intent of this series of posts is to assist a beginner by helping them establish a visualization foundation for various vector manipulations while offering an overview of some of the common vector uses in game development. Hopefully it will burn off some of the fog for a beginner.

What were going to go over

The topics above are currently in progress but as they get completed, the above list will turn into links.

Categories: 3d Programming

Matrix Basics. How to step away from storing an orientation as ‘3 angles’

February 15, 2010 51 comments

While participating in the XNA forums over the last several years, I often see folks posting questions about how to get their rotations the way they want them. Most of the time they post a code snippet and it shows they are trying to store and manipulate their model’s orientation using ‘3 angles’, typically stored in a Vector3 for convenience. Usually there is much frustration involved. The ‘3 angles’ approach does not lend itself to concatenating (combining) rotations. It is also complex to resolve a rotation around a non-aligned axis in terms of getting the order and proportion correct.

I’ll go out on a limb here and say that eventually, anyone who continues on in XNA (or 3d programming in general) past the rock bottom beginner level, migrates away from this ‘3 angles’ approach. The sooner you give up the ‘3 angle’ approach (AKA Euler Angle Representation), the sooner (I believe) you will be effective as a 3d programmer. Although the ‘3 angles’ representation is a legitimate way of expressing an orientation and I guess there is a time & place for everything, I haven’t found a serious project that uses this method. Maybe there is some out there, but I’ll bet they are rare and unusual enough to deem them not exemplar of game programming anything more complex than beginner projects.

I’ll have to admit the ‘3 angles’ approach is initially intuative and possibly some beginner level tutorials use this approach for that reason. I have an opinion that that is a dis-service to the student since it seems lure them into the realm of 3d programming but in short order directs them right into a brick wall… But what good is expressing an opinion without offering also some possibility of an alternative. So this article is an attempt at offering an alternative. And, happily, no math will be required.

Amongst the other approaches that are out there to represent an orientation, in this article I am going to push the Matrix. I think others are good too but learning about and  using a matrix will facilitate 3d programming knowledge and get you ready to explore other approaches without turning you into any brick walls. Additionally, since you must ultimately pass the model’s orientation onto the shader in matrix form anyway, there is an added minor benefit in not having to convert to a matrix before doing so.

As intuitive as the ‘3 angle’ approach is, the Matrix approach might be that daunting to the beginner. But it doesn’t have to be. I believe that after learning the basics of a matrix and how to visualize a matrix in the mind’s eye while manipulating it, it will be very easy for the beginner to pick up. So for the cost of investing a little time to understand the Matrix, your effectiveness in 3d programming will increase dramatically and you can stop the insanity of banging your head against the ‘3 angles’ brick wall.

So what is a matrix, and how do I go from my understanding of ‘3 angles’ to an understanding and implementation of matrices? I believe the key is in the ability to visualize a matrix as you are coding changes to it. OK, let’s start by showing a sample demo code that utilizes a matrix approach instead of a ‘3 angles’ approach. All the supporting code necessary to render an object has been stripped away just so you could see how the matrix code fits in to a game class.

Class Game1 : Game

{

//Declare a matrix with sufficient scope to access it in the Update & Draw methods

Matrix modelOrientation;

void Initialize()

{

modelOrientation = Matrix.Identity; // initialize the matrix to a starting point

modelOrientation *= Matrix.CreateScale(?);//This is the place to apply scale if necessary

}

void Update()

{

//manipulate the matrix

modelOrientation *= Matrix.CreateFromAxisAngle( someVector, someAngle); 

//manipulate the matrix a second time if necessary

modelOrientation *= Matrix.CreateFromAxisAngle(differentVector, differentAngle);

//manipulate the matrix yet a third time, or as many times as you want

modelOrientation *= Matrix.CreateTranslation(yetAnotherVector);

}

void Draw()

{

effect.World = modelOrientation; // pass the matrix onto the effect for drawing

}

}

So if you implemented this, a model would be rotating and moving depending on what values you place for ‘someVector’, ‘someAngle’, …etc.

A very important thing to understand from the above example is the ease of how movements or rotations can be concatenated to each other (combined to each other). When working with matrices, you can break your movements/rotations down into a series of understandable operations and simply perform them one after another. That was one source of problems with the ‘3 angles’ approach, It was very very difficult to do the following: ” first I want to rotate it a little about this world axis, then a little around that world axis, then that 3rd axis, then that other world axis, etc… The ‘3 angles’ representation does not support that because after the first rotation, one of the subsequent rotations could produce an undesirable result, but the matrix representation does not have that problem. There is no limit to how many rotations you can combine and all rotation axis will work out just like you expect.

One thing to notice is how interchangeable the word “Matrix” is with the word “Model” during this discussion. If we say ‘I am rotating the matrix some angle about some axis’, we may as well say ‘I am rotating the model some angle about some axis’. The end result is identical and the same meaning is conveyed.

I know after seeing the code above you may want to jump right into examples of moving and rotating, like figuring out how to determine what ‘someVector’ and ‘someOtherVector’ should be.  But first I want to go over the basics of what the Matrix is and why it works and what it can do for you. Most importantly, I believe it will be most helpful for you to learn how to visualize a matrix in your mind’s eye. I keep repeating that, don’t I? I must think it’s important.

A Matrix in XNA is made up of 16 numbers, and mathematically, they fit into a 4 row by 4 column structure. Here is a matrix in textual form. It happens to be an Identity matrix:

1    0    0    0          row 1

0    1    0    0          row 2

0    0    1    0          row 3

0    0    0    1          row 4

So the first way you should think of a matrix is simply a group of four vectors. Each row is a like a Vector4 but you can disregard the 4th element of each row for the moment. They’re one of those things that when you get to the point that you need them, you will understand them. The first 3 elements of each row are all you need to understand to manipulate models in 3d space. So think of the first 3 columns as holding the X, Y, & Z components of each row’s vector.  The first 3 rows of the matrix are what sets the model’s orientation/rotation and the 4th row is the one that sets the position of the model.

An identity matrix is a matrix that applies an orientation to the model that has a specific alignment with the world axis (the X, Y, Z). It also places it’s position at the world origin. Generally, it should position and orient the model just as it was in your 3d modeling app. The textual matrix above is an Identity matrix. Here is a graphic of an Identity matrix.

In this graphic, each of the rows becomes a vector. The upper three vectors(rows) are depicted as the colored arrows. Whenever you visualize working with matrices, always try to visualize these three vectors. Not in terms of their X, Y, Z values but in terms of what direction these three vectors are pointing.  On the 1st row, for example, the st value is 1 so that vector’s X component is 1. The 2nd & 3rd values are 0, so the Y & Z components of that vector are 0. that makes a vector3 like this: (1, 0, 0) which point straight down the x axis just like the red vector/arrow in the graphic. One of the nice things about working with matrices is that you rarely need to know the actual numerical values of any of the 16 numbers.

Now, there are a couple things to learn about these vectors. When we use a matrix to represent an orientation or rotation, we always want these three vectors to be 90 degrees to each other. They will not always be aligned with the world axis like they are in this graphic, but they must always be 90 degrees to each other. Also, notice they all have a length of 1. This is important, if one of the three vectors had a length of, say, 2, the model would stretch in that direction when drawn. If all 3 vectors had a length of 2, the model would scale to be twice as long, wide, & tall as the original. That is actually the basis of a scaling transform. But for now, let’s keep visualizing the matrices we work with here as having a length of 1. When the 3 vectors are 90 degrees to each other, they are said to be orthogonal. When a vector has a length of 1, it is said to be normalized. When a matrix’s vectors meet these two criteria, the matrix is said to be orthonormal. If your matrix is not orthonormal, your model will be either skewed, distorted, or scaled. This may or may not be desirable depending on your project.

Another thing to notice on the graphic above is the way all three vectors meet at the world origin. Technically speaking, a vector always emanates from the world origin no matter what so for the life of the matrix, The these three vectors will stay put and simply rotate together around this origin. Here is a short video showing these three vectors rotating together.

Notice all three vectors rotate as if they were one assembly and always stay 90 degrees to each other.

So let’s introduce the 4th row’s vector into this mix. The 4th vector represents the position the model occupies in the game world. Say we added a line of code to add an arbitrary position to this Matrix.

modelOrientation *= Matrix.CreateTranslation(new Vector3(1.25f, 1.25f, -1.0f));

Here is a graphic to represent this:

If we were to draw a model using this matrix, the model would be drawn at the end of the translation vector; like this.

So just remember that the model is always drawn at the end of the translation vector (the 4th row vector). Let’s remove the model for a few moments and show some rotations. In the next video, we are going to place an arbitrary rotation axis vector to use to rotate the matrix around.

Vector3 someArbitraryRotationAxis = new Vector3(-0.8f, 0.8f, -0.4f);

float someArbitraryAngle = MathHelper.ToRadians(83);

modelMatrix *= Matrix.CreateFromAxisAngle(someArbitraryRotationAxis, someArbitraryAngle);

So in this video, the vector ‘someArbitraryRotationAxis’ is depicted by a yellow vector and you will see that ALL 4 vectors of modelMatrix rotate around that axis.

So the rotation angle was about 83 degrees around that arbitrary axis. Aren’t you happy you were able to do that without having to calculate how much should have been around the global X, global Y, & global Z axis and what order to perform the three rotations??  Good… The reason I emphasized the word ‘all 4’ is because often times we want an object to rotate in place rather than orbit the origin and we forget that the position of the model will be affected by rotations.Wanting a model to rotate in place would be like rotating the three Rotation vectors (the ones making the tripod) while keeping the translation vector (the 4th row vector) stationary.  That won’t happen though… all 4 vectors rotate when you apply a rotation to a matrix. But don’t worry, there is a way to make a model rotate in place. We’ll get to how to do that soon. But for now, just know that when a matrix rotates, all 4 vectors rotate and since the translation vector is one of them and is going to rotate, the model will be displaced.

Now I am going to throw you a curve ball. I’m going to do this in the name of ‘improved visualization’ technique. We’re going to move the 3 rotation vectors from the world origin to the end of the translation vector. Like this

This is not technically a correct depiction of reality because all vectors must emanate from the world origin. They can not be just sitting ‘out there’. But as long as we know that and account for that when needed, this viewing style can improve our ability to visualize what we need to do with the matrix while working with it. Consider these two pictures

Both of these pictures have the exact rotation applied to the 4 vectors. They are identical matrices. The only difference is how we are viewing them. The upper one is technically correct but the lower one is more visually helpful. Now, knowing that an aircraft pitches around it’s own lateral axis, which picture makes it more obvious that to pitch the nose of the aircraft up, we would need to rotate it around the matrix’s red vector. Hopefully, you would agree that the lower one makes it more obvious. I always tend to visualize a matrix as my model with the three vectors sticking out of it.

In the next video, I include both view styles to demonstrate that either style produces the same relationship between the model and the 3 rotation vectors. Check this out & pause it at different places to note that the 3 vectors at the origin are always parallel to the 3 vectors at the model.

So you can decide which of those two viewing styles you prefer when you are visualizing your matrices. A purest may want to keep the 3 rotation vectors at the origin, but a practical person may want to think of them as being at the model. Who knows, maybe there are times when you might find it convenient to go either way. No problem there. But for the remainder of this article, we’ll choose the style that places the vectors at the model.

Moving on from that point, there is another thing I want to reiterate from that video. It is important to know that the three vectors never move or rotate relative to the model. The three vectors are always pointing out the top/right/back of the model no matter how the matrix/model rotates. It is as if they are glued together. This is one of the reasons that matrices make it so easy to work with when doing rotations. Often, the rotation desired is one that pitches, rolls, or yaws (or a combination of) around these vectors. To pitch this aircraft up the rotation method would be as simple as:

modelMatrix *= Matrix.CreateFromAxisAngle(modelMatrix.Right, someAngle);

That’s it, absolutely no need to calculate any angles about global axis. This method simply takes that red vector, and rotates the whole matrix around it appropriately. I hope you are starting to see the ease of working with matrices instead of the ‘3 angles’ approach.

So that introduces a new term; ‘modelMatrix.Right‘. What’s this ‘Right‘ thing?  The XNA Matrix has seven properties which are these vectors we’ve been talking about (well, more than just the 4) and are readily available to you at any time. Here is a graphic showing these properties. Notice that the red vector, which is a matrix’s 1st row vector, is called Right. The green vector ( the matrix’s 2nd row), is called Up. The third row vector, the blue one, is called Backward.

The Forward, Left, & Down vectors are simply opposites of the three vectors that make up the matrix. When you access the Forward property, for example, the XNA framework will go to your matrix, grab the Backward Vector, Negate it, and make that the result of the Forward‘s getter. The 7th property is the Translation vector with, as you know by now, represent the world space location of your model.

Every time you apply a rotation or translation to a matrix, it automatically calculates and updates all the changed components that make up these 7 vectors (the X, Y, & Z components). It does this every time a rotation or translation method is called in every frame. This allows you accurate access to any of these vectors at any time. For instance, Let’s say the matrix has an arbitrary orientation to it, you could do a test like this:

If( modelMatrix.Forward.Y > 0.0f )

{

//the model is pointing somewhat upwards (inclined)

}

Now let’s bring the aircraft back in & touch on translating it. Hopefully, you should be able to imagine your model with the six vectors sticking out of it and know that your translation vector is going from the world origin to the model. So if you were told,  say, picture in your mind’s eye a model and it’s matrix in the world at some slight rotation, you should be able to see something like the following graphic in your mind’s eye:

So since this is an aircraft and aircraft generally go forward, let’s talk about how to move this matrix/model forward without rotating it. For now, we’ll just use that Matrix.Forward vector as our direction. We’ll choose a speed to go, and create a velocity vector to move our matrix.

float speed = 0.15f; // or whatever value suits your game

Vector3 velocity = modelMatrix.Forward * speed;

modelMatrix *= Matrix.CreateTranslation(velocity);

So if this was run, every frame the aircraft would go forward 0.15 units. That might look something like this. [Note, you must imagine the translation vector, my 3ds movie making skills are not sufficient to make it animate properly]

One last thing I want to go over before closing this article is the way to rotate a model in place. Remember that when you rotate a matrix, all 4 vectors rotate about whatever axis you are using (including the 4th row translation Vector) which can make the model orbit the axis. To rotate a model in place, you must separate the changes in position from the changes in rotation.  To do that, you must zero out the translation vector before applying any rotations. Look at this code here:

//assume the matrix’s translation vector is representing a position some distance from the origin

Vector3 position = modelMatrix.Translation;

modelMatrix *= Matrix.CreateFromAxisAngle(someAxis, someAngle);

//although the previous line rotated the 4th vector, we don’t care because…

modelMatrix.Translation = position;//we simply reset it to what it was before the rotation

So if you are beginning to visualize what the matrix is doing as you read/write your code, we might not need a video to show what’s happening.  As you read/write the above code, you would see it rotate a little bit around the appropriate axis, then because we noted the exact position that it was at when we started, we move only the translation vector back to where it was. It is now sitting in it’s same spot but rotated to some extent. Do this frame after frame after frame and you have a model spinning in place. So, if you don’t capture the Translation vector before rotating the matrix, then reset the translation vector after the rotation to what it was before, your model will orbit the axis instead of rotate in place.

So the main objective of this article has been to offer someone starting in XNA programming an introductory visualization technique to effectively work with matrices and to encourage that someone to store and represent your model’s orientation in matrix form. To be comfortable and effective with matrix representation, I feel that the ability to be able to realistically visualize what is happening as you contemplate your code is paramount. Hopefully, this article has assisted some folks down that path. Thanks for reading.

Categories: 3d Programming