Stage3D / AGAL from scratch. Part VI – Organise your Matrices

Organise your Matrices

In previous articles we used some matrices to modify the rendering of a triangle. Rotations, scales, translations, We also learned to use a projection matrix to render the depth effect into the clipspace projection. And we saw that we would upload the matrix as a vertex constant, and use it with the “m44” AGAL opcode.

Matrices operation aren’t distributives, meaning if you scale first, then rotate, it’s not the same thing than if you rotate then scale. So you will have to organize your matrices in a certain order to get things done smooth and easy. Follow the guide.

From cameras to matrices

First of all, . It’s made out of 3 classes :

  • The article example bootstrap
  • A simple Cube class, that will just create a colored cube vertex and index buffer, and store a matrix for its position.
  • An ArcballCamera class that you can use and share for your experiments. Very usefull to get a quick way of “browsing” your scene around the origin point.

The Cube class

Just a quick word about the Cube class, since you should be able to do it by yourself now : It is not “clean” and “optimised” at all, and I did it only to make the main code more readable.

The Cube class doesn’t even have a “render” function. When you instantiate a Cube, it will create its vertexBuffer and indexBuffer, and upload the simplest data ever. This cube is made out of 8 vertices which is why the color are merging on the corner and that you don’t get a plain color per face. The Cube also create the simple “3 lines” shader you need to have some rendering, and upload it. That’s it.

The ArcBallCamera class

The ArcBallCamera is a camera that rotates around the origin point. When I tried to build it at first, I though I had to look for geometry formula, about placing a point onto a 3D sphere or something. Actually, it’s a lot simpler.

Your matrices modify the “world”, not the camera

It sounds stupid to say it, but it is something you have to keep in mind. For instance, if you want to have your camera slowly going away from your scene, you will have to increase it’s z position, because you are actually “pushing” the world away from your clipspace.

Keep that in mind, and remember that matrices operations are not distributives. To make your arcball camera, the operation are actually very simple : rotate the world, then push it away. That’s it !

Both “method” should work, but it’s actually really simple to use the second one, for the same result : rotate the “world”, then “push” it away.

The rest of the class is pretty simple : on EnterFrame event, the class applies some rotation then some translation to a Matrix 3D according to mouse position and mouseWheel actions.

The ModelViewProjection matrix

OK, so we have a matrix that is our camera, and we have one for the projection, and we have one for the cube, great, but now ?

The final matrix used for the rendering is often named the modelViewProjection matrix. for a very simple reason : you have to append your every matrices in the following order :

  1. The Model Matrix : your model being the mesh you are currently drawing
  2. The View Matrix : the view being your “camera” somehow
  3. The Projection Matrix : being the “lense” in some 3D Engine, the projection always come last as far as I know.

Following this order will give you very intelligible results.

Head up toward the OrganizeYourMatrices class. Notice that when the context is created, I instantiate a single cube, a camera, and the projection matrix we will use later. Go one to the render function.

Rendering several cubes with only one

To both illustrates how following the previous matrices order will give you the wanted result and that you can draw several times the same vertexBuffer, I will keep my single cube and render four of them around the origin.

// render second cube cube.moveTo(1.1, -1.1, 0);renderCube(); // render third cubecube.moveTo(-1.1, 1.1, 0); renderCube(); // render fourth cube cube.moveTo(1.1, 1.1, 0);renderCube();

The following code isn’t the cleanest one I made but at least it is easy to understand. The only cube we have can be “moved” to 4 differents positions, and drawn onto the screen using the renderCube method. Go ahead, that is were the magic will happen.

        /**         * Render the cube according to it's current parameters ( = modelMatrix)         */        private function renderCube():void {            modelViewProjection = new Matrix3D();            modelViewProjection.append(cube.modelMatrix);         // MODEL            modelViewProjection.append(camera.matrix);            // VIEW...                modelViewProjection.append(projectionMatrix);        // PROJECTION !            // program           bluehost  context.setProgram(cube.program);            // vertices            context.setVertexBufferAt(0, cube.vertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_3); // x, y, z            context.setVertexBufferAt(1, cube.vertexBuffer, 3, Context3DVertexBufferFormat.FLOAT_3); // r, g, b            //constants            context.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, modelViewProjection, true);            // render            context.drawTriangles(cube.indexBuffer);        }

Each time I want to draw the cube, I first start by recreating a modelViewProjection matrix. I could have instantiate it somewhere else, and only reset the matrix using modelViewProjection.identity(), that would have been better, but anyway, it’s the same.

First, append the modelMatrix of the cube. This matrix contains the translation parameters we made using cube.moveTo(x, y, z). Append the camera’s matrix, and finish with the projection.

The rest of the renderCube method is just classic Stage3D stuff : declaring your current program, and buffers, and drawing triangles.

The reason you can call several times (in this case, 4) the drawTriangles function and still get the complete scene is because the drawTriangle function only renders your mesh into the backbuffer. So the last thing you need to do on your rendering method is to present the backbuffer onto the screen.

Now you should get something like this

Append and Prepend

There is some case where it is difficult to use this order because of implementations details. Hopefully, there is a way to add a transformation at the top of the operations stack : prepend.

Prepend comes in different flavors : prepend a matrix, prependTranslation, prependRotation and so on.

to understand what prepend does, just look at the 2 following codes : they both do the exact same thing.

modelViewProjection = new Matrix3D(); modelViewProjection.append(cube.modelMatrix);         // MODEL modelViewProjection.append(camera.matrix);            // VIEW... modelViewProjection.append(projectionMatrix);        // PROJECTION !
modelViewProjection = new Matrix3D(); modelViewProjection.append(camera.matrix);            // VIEW... modelViewProjection.append(projectionMatrix);        // PROJECTION ! modelViewProjection.prepend(cube.modelMatrix);   // PREPEND MODEL

That’s all for today, I hope you enjoyed this, as always, and that will be useful for you. Don’t hesitate to use, modify or share the since it’s a very simple snippet of code.

As always, feedback is appreciated !

6 thoughts on “Stage3D / AGAL from scratch. Part VI – Organise your Matrices

  1. Thanks for the whole set of high quality tutorials. Stage3D is still pretty new thing so every article is a great contribution to the community!

  2. Excellent tutorials on your blog. For a first time blogger, you put many to shame.
    Any chance of digging into AGAL a bit more?

    Thank you.

    • Thank you very much !

      Yeah, AGAL tutorial won’t stop, but actually, I write articles as I discover stuff myself. Sometimes I don’t have times for my research or to write anything, so that is why you have to wait a little. Next step will be more about geometry, then a little about making a directional light. stay tuned !

  3. thanks for the tutorial. could you explain the code in the camera class a bit more ?

    f.e.
    why prepend rotation?
    why pointAt mat’s position ? whats that mean ?

    _mat.pointAt(_mat.position, _target);

    thank you very mush.

    • prepend rotation only means that I want the matrix rotation to be done before any other actions. In my case, I want to rotate the world, then push it (= turn the “camera” around the origin, then make it go backward).

      The pointAt method is not necessary here (and actually not used right) but the method is used to rotate a matrix so it faces the given point.

      ex : _camera.pointAt(_someObject.position);

Comments are closed.