//****************************************************************************// //************** Matrix Stack (cont.) - January 16th, 2019 ******************// //**************************************************************************// - Project 1, where art thou? Whence hast thy form fled from the sullen coves of earth? ------------------------------------------------ - Alright - last class, in our Frankensteinien hubris, we were creating a person - a tiny homunculus within our digital light-flashy boxes - As discussed, we can use the matrix stack to persistently transform the stuff we're drawing - but we only got around to creating a lonely hand - Today, let's continue right along with our arm-drawing method void drawArm() { push() translate(6, 0); //position the hand at the end of the arm hand() pop(); //"Fuh-git-abowt-it" armExtent(); //draw the actual arm } void armExtent() { push() scale(3, 5); square(); pop(); } - Now for the torso, and the rest of our headless horseless man! void person() { push(); //copy a 2nd "I" onto the top of the stack scale(4, 5); square(); //draws the torso pop(); push(); translate(4, 4.5); //move the arm from the origin to the top-right of the torso arm(); pop(); push(); scale(-1, 1); //flip the x-direction, to draw the arm the other way translate(-4, 4.5); arm(); pop(); } - Notice that, as we were writing this, we didn't have to think too hard about what was inside the arm() method - we could just let the matrix stack and our previous transformations handle that for us! - Each "matrix push" is like going level down the dependency tree for these objects, and each pop is like going a level back - As we go downwards, we keep "accumulating" more transformations on our matrix stack, adding each transformation to the right of our equation (i.e. most recently added is the first one to be performed) - Then, when we draw an object, ALL the transformations on the top of the matrix stack are applied to it! - This is the reason why the matrix stack behaves the way it does: it handles this hierarchy of commands for us as a linear set of stuff, which is great! - It seems unnecessarily complicated at first, but in the long run, this matrix stack saves us a ton of work - "If you can understand this example code I gave you, draw the matrix stack for it, and understand why it works the way it does, you should be in excellent shape with this" - ...and again, Professor Turk loves giving matrix stack traces on exams - So, that's the matrix stack, but we're still stuck in Flatland. Let's try to break into the world of three dimensions - Let's add our 'z' coordinate, coming out of the page toward us, with the y axis still going up and the x coordinates going right - This is a RIGHT-HANDED COORDINATE system, probably coming from the right-hand rule, with the thumb on the x-axis and your index finger on the y-axis - It's perfectly okay to have the z-coordinate going into the page, of course - but that's a left-handed system - Now, for our 3D vectors, we'll need to actually add a 1 to the bottom to make it homogenous, just like we did in the 2D case. For instance: P = [x, y, z, 1] - Similarly, to make our transformation matrices homogenous, they have to be 4x4: [1 0 0 dx] [0 1 0 dy] [0 0 1 dz] [0 0 0 1 ] - The final bit of weirdness comes from rotating in 3D. Trying to rotate just around one of the axes is normal - for instance, to rotate counter-clockwise around the Z-axis (looking from the direction toward the origin): Rz = [cos -sin 0 0] [sin cos 0 0] [0 0 1 0] [0 0 0 1] - Similarly, for the other axes, Rx = [1 0 0 0] [0 cos -sin 0] [0 sin cos 0] [0 0 0 1] Ry = [cos 0 sin 0] [0 1 0 0] [-sin 0 cos 0] [0 0 0 1] - "Ry probably looks weird, but the reason is because its 2x2 rotation columns are SWAPPED compared with the other matrices - think of it that way, and it makes more sense" - "Remember, you're going to be implementing these in project 1 - so if you've got questions, fire away" - Trying to rotate around an arbitrary axis, on the other hand, is a little weirder...but we'll get to that - So, that's 3D, but we have a problem: all of our display devices are flat 2D panels! So, we need to somehow squash our 3D objects into a sensible 2D representation - To do this, we need to "project" our objects onto the screen, and there are 2 common ways of doing it: - PARALLEL PROJECTION (or "ORTHOGRAPHIC" projection) is where we pretend we have a rectangular "view plane" grid of pixels, representing the screen, and each of the pixels sends out a parallel "projector line" straight ahead - and then it draws whatever it hits first - This is nice and convenient - but it's NOT how our eyes work, sadly - PERSPECTIVE PROJECTION means that instead of shooting all the rays straight ahead, we instead shoot them out at an angle, emanating out from some point called the "center of projection" - Realistically, what this means is that objects that are farther away seem smaller - which is great! - On Friday, we'll dig into the math behind how we can do these projections - stay well till then!