OpenGL ES Tutorial for Android – Part III – Transformations

I have started a new updated serie of tutorials on OpenGL ES 2.0 for android. Check them out at: OpenGL ES 2.0

Last tutorial was about building your polygons. This tutorial is all about transformations, how to move the polygons around. I will continue this tutorial from where the previous ended so you can use that source code or make a copy of it.

I am not going to bore you with a lot of mathematics but I believe it is important to know that when OpenGL render a mesh it multiplies all vertices with a matrix. All the transformations you do are about manipulating the vertices in different ways by modifying this matrix. You can think of the matrix as a paper and that you never move the pen before you start to draw. You always draw in the center. But by doing a translation on the matrix you are moving the paper and also the center. A rotation is like rotating the paper around the center. And a scale is a bit harder to visualize with the paper view but it is like changing the unit size regarding to how you translate your meshes. Usually you talk about transformations according to the mesh not the world, but it is still important to know about.

Coordinate System

OpenGL uses a so called right-handed coordinate system. A system is called right-handed if you look from the positive end towards the origin of the axis the counter-clockwise rotation is considered to be a positive rotation.

When you have started up your view and haven’t applied any transformations the axis are aligned like this: The x-axis goes from left to right, the y-axis comes from the bottom and goes up and the z-axis is moving from the back of the screen towards the front of the screen.

Coordinate System

Translate

Coordinate SystemA translations added to the matrix makes the mesh appear as it has been moved. Translations are made along the axis and with no rotation added the axis are in there default state. Translation affects all the vertices in a polygon the same amount over the same axis. Translations are simply additions and subtractions to a current value. The image to the right shows a translation in 2 dimensions.
The start point is {x:-2, y:1} we like to go to {x:1, y:3} so we add {x:3, y:2}.

A simple addition: {x:-2, y:1} + {x:3, y:2} = {x:-2 + 3, y:1 + 2} = {x:1, y:3}.

In 3 dimensions we do the same, if we are located at position: {x:1, y:1, z:0} and we like to move 3 units into the screen we add {x:0, y:0, z:-3} and end up at: {x:1, y:1, z:-3}.

In the last tutorial we moved the square 4 units into the screen just to be able to see the square. What we did was that we added {x:0, y:0, z:-4} to the current position. This is the code we used for the translation:

If you do several translations after each other the order of the movement is along the X, Y and Z axis, in that order. On translate the order isn’t so important but when we do a rotation it’s really important.

It can be quite tricky to remember how the axis are aligned. Fortunate there is a good trick to remember the direction of the axis. Hold your left hand like the photo below. The point on each finger represents the positive direction on one axis. Your thumb is y-axis, index finger is x-axis and your middle finger would represent the z-axis. When I first started with 3D programming I actually wrote the letters, x, y and z on my fingers :)

Help with the axis.

Rotate

Rotating is what it sounds like. You add a rotation to the matrix making it appears like the mesh are rotated. With no translation before the rotation is around the origo. The x, y and z values defines the vector to rotate around. The angle value is the number of degrees to rotate. Coordinate System

If you remember these three things you will manage rotation quite easy.

1. The rotation value are in degrees.
Most frameworks and math functions on computers use radians but OpenGL use degrees.

2. When doing several rotations the order are important.
If you like to restore a rotation you negate the angle or all the axis like this: glRotatef(angle, x, y, z) is restored with glRotatef(angle, -x, -y, -z) or glRotatef(-angle, x, y, z).

But if you do several rotations after each other like this:

gl.gRotatef(90f, 1.0f, 1.0f, 1.0f)

And want to restore the mesh to it’s original position you can’t just negate the angle like this:

gl.gRotatef(90f, -1.0f, -1.0f, -1.0f)

You have to revert the order of the rotations as well like this:

The order of several rotations is important.

3. If you look from the positive end towards the origin of the axis the positive rotation is counter-clockwise.
If you take a pencil in your hand, let the point be in the same direction as your thumb, as in the picture below, then aligns the pencil with the x-axis. Let the pencil’s point be aligned with the positive direction of the axis. Your other fingers will now point in the positive direction of the rotation over that axis.

Positive rotation.

Translate & Rotate

Since both rotation and translations are made within each mesh own coordinate system it is important to remember that the order you do the translation and rotation are very important.

If you do a translation on the mesh first and then rotate it, the translation is made on the current state of the mesh coordinate system and then rotated at the new location.

Translate Rotate

If you first rotate and the move the mesh it will be moved accordingly to its own rotated coordinate system.
Translate Rotate

Scale

Scaling is just as it sounds and it is possible to scale over each axis separately. Scaling is the same as multiplying all vertexes with the same scalar. In the image below we scale with: gl.glScalef(2f, 2f, 2f). That means that we multiply all vertixes with 2.
Scale.

Translate & Scale

The order of scaling and translating does matter. If you translate before scaling the transformation is intact. Like this example, first a translation of 2 units and then scale it by 0.5.

Translate scale.

But if you scale before the translation you get a different result. Since you scale the mesh coordinate system then do the translation you will not move the mesh the same amount as you would before the scaling. So if you first scale with 0.5 and then do a translation of 2 units the result will appear as a translation of 1 unit.

Scale translate.

Load Identity, push and pop matrix

When you translate, rotate or scaling you are not applying the transformation from the same preconditions, you are applying them to the previous transition. You need to be able to reset the position.

glLoadIdentity

glLoadIdentity replaces the current matrix with the identity matrix. It is the same as calling glLoadMatrix with the identity matrix:
There are situations where you don’t want to reset the model matrix, you rather want to go back to how it was just before your latest transformation.

glPushMatrix

glPushMatrix makes a copy of the current matrix and put it on the stack. This means that when you do any kind of translations after glPushMatrix you are doing them on a copy.

glPopMatrix

To get back to the previous matrix you use the glPushMatrix command.

A good practice can be to have one glLoadIdentity in the begining of each frame and after that use glPushMatrix and glPopMatrix.

Putting it all togetter

So to make something with this new knowlege let us do 3 squares call them A, B and C. Scale them so that B is 50% smaller then A and C is 50% smaller then B. Then let A rotate counter-clockwise in the center of the screen. B should rotate clockwise around A and finaly C rotating clockwise around B and counter-clockwise in a high speed around it’s own center.

And don’t forget to add angel as a variable as well. Thanks Tim!

References

The info used in this tutorial is collected from:
Android Developers
OpenGL ES 1.1 Reference Pages

You can download the source for this tutorial here: Tutorial_Part_III
You can also checkout the code from: code.google.com

Previous tutorial: OpenGL ES Tutorial for Android – Part II – Building a polygon
Next tutorial: OpenGL ES Tutorial for Android – Part IV – Adding colors

64 Comments

  1. Tim Hansen

    Absolutely brilliant!!! You explained everything perfectly and clearly. This tutorial really helps getting to grips with the subject matter.

    One minor little problem is that you have added code in the downloadable source files, which isn’t listed in the tutorial, which means that this example doesn’t work until the angle variable is added. After it is, it does work, but the effect isn’t as described (although it does look cool!). Of course everything does work once the other code is added.

    But anyway, this is probably the best tutorial on OpenGL ES on the web and I can’t wait until the next instalment!

    BTW, if I wanted to make a triangle or a pentagram, how would I do that? I tried playing around with vertices and indices, but to no avail! 8(

  2. Lars

    Very useful. Thank you. Best tutorial I’ve found. For the first time, I understand 3D graphics programming!

    Lars

  3. Per-Erik Bergman

    First, thanks for the nice comments.

    Tim: To make a triangle just use this:

    // Our vertices.
    private float vertices[] = {
    0.0f, 1.0f, 0.0f, // 0, Top Center
    -1.0f, -1.0f, 0.0f, // 1, Bottom Left
    1.0f, -1.0f, 0.0f, // 2, Bottom Right
    };

    // The order we like to connect them.
    private short[] indices = { 0, 1, 2 };

    With all shapes that is more complex, like a pentagon I would recommend to draw it on paper and find all the triangles and then decide on how to make the vertex setup.

  4. Tim Hansen

    Thanks for the feedback. I got it working in the end!

  5. Hamy

    Hope you keep going! These are going great so far!

  6. suburban

    Congratulations, It is a great tutorial to start from. It is simple to understand although you keep using correct vocabulary for technical things.

    Even though, I don’t agree with your explanation about the rotation. Rotating 90 degrees on a (1,1,1) vector is not the same as rotating 90 degrees on (1,0,0) then on (0,1,0) and then on (0,0,1). Plus, if you first rotatete X degrees on a vector (1,1,1) and then -X on the same vector, the result is the original matrix.

    This is what I have come to after some tests, and it is also what I understand from the API on the khronos website. Of course I am new to Open GL, so I would appreciate if you correct me in case I am wrong.

    Congratulations again for this great tutorial and thanks a lot!!!

  7. Per-Erik Bergman

    suburban, great that you noticed that. The x, y and z values is the definition of what vector to rotate around. If you for example try to rotate the big square with gl.glRotatef(angle, 1, 1, 0) instead you get a diagonal flipping rotation. My head was in another 3D system :). I have updated this tutorial.

  8. vandelay

    Your explanations are magnificent!

    Anxiously awaiting the meshes and color tutorial.

    Muchas gracias.
    – v

  9. Gary Wang

    Really GOOD article for Android OpenGL ES… Thanks for ur sharing!

  10. Omega

    Fantastic! These are extremely well thought out and very well broken down examples.

    I’ve been getting my head around OpenGL over the past week and I wish I had dug up these posts sooner!
    Your approach offers the perfect balance between the underlying principles and api specific use. As a programmer, I appreciate how you’ve incorporated both of these elements.

    I’ll be gushing about these posts for a while (and coding even more).

  11. ufans

    Really great tutorial.

    Could you flesh out this thing about a mesh having its own coordinate system after a transformation. Naively, I would assume that you do transformations _within_ the very same unchangable coordinate system.

    Thanks
    Ufans

  12. Per-Erik Bergman

    ufans: yes, you do the transformations on the same coordinate system. What I mean with: “… within each mesh own coordinate system…” is that since your next transformation will depend on the previous one especially with a “translation after a rotation” it is for many people easier to think of the mesh with it’s own coordinate system since that is what you work with it is easier to remember that. Like: “Why does my mesh don’t move to the right? Yeah, because I just rotated it.” I’m not sure this explanation was any help and perhaps I should have been a bit clearer in the tutorial.

  13. LiuQi

    Nice tutorial.
    But for the rotation part, I think you made an error in your explanation. glRotatef(angle, x, y, z) cannot be restored with glRotatef(angle, -x, -y, -z), it should be glRotatef(-angle, -x, -y, -z), since glRotatef(angle, x, y, z) is the same as glRotatef(angle, -x, -y, -z).

  14. Hoang

    thank you so much for your tutorial :)

  15. Hoang

    Thanh you so much for your tutorial :)

  16. Jennifer

    May I know how to make the point to become visible and make it to crosshair point. The crosshair point , “+” is the final output of coordinate after translation has made. How to do it? thanks

  17. Scofield

    Per-Erik Bergman i love u , u are god like

  18. Rohan Balakrishnan

    Fantastic tutorial. I have one question though. I’m developing an app on an Android phone that has a 533×320 pixel screen. What is the conversion between the units used for OpenGL transformation functions and pixels? What is the pixel to unit ratio?

  19. gabriel

    and if i want to make the square to ocupy 50% of the device screen? how i go about calculating that?

  20. Wonderful – the examples actually unzipped and worked the first time. Great!

  21. This tutorial is like art, truly amazing. Thank you!

  22. John

    Great tutorial. I do have a question. I am moving a square by using keypad input and so have different translations corresponding to different keypad inputs. It works but only for 1 keypad input. In other words if I press up on the keypad a translation of

    gl.glTranslatef(0, 0.1f, 0);

    is performed.

    The problem is that I can only do this once and when I press up again nothing happens. Do I need extra code in onDrawFrame??

  23. Raj

    Thanks a bunch for writing this tutorial.
    I was a absolute zero in OpenGL and now I have been able to write some basic apps.

  24. Per-Erik Bergman

    LiuQi: No, it is right. the angle indicates the direction on rotation to rotate back you need to rotate the same amount but in the other direction -angle. Inverting the rotation axel change the direction of the rotation and there for you do not need to negate the angle.

    Jennifer: The easiest way is to use a plane and a texture.

    Rohan Balakrishnan: OpenGL has it’s own coordinate system. Usually you have -1 to the left 1 to the right, up and down is depending on the ratio.

    John: Since we reset the matrix on every frame you need to move more and more. So on key pressed do: myKeypadX += 0.1 and then in the rendering loop do a: glTranslatef(0, myKeypadX, 0)

  25. Morpheus

    Where do you set the speed or frame rate? You increase the angle++, but at what rate is onDraw called? Where is that defined? Thanks. Great tutorial.

  26. S4milli4

    Really well done tutorial. You may miss some screens of the results though.

  27. I have to thanks you :)
    I’m not a rock-math star but I like OpenGL, your explanations are simply great !
    Keep it up !

  28. dpk

    Let’s say you wanted to show the object at a different rotation in different frames. Like, the first frame, you want it to be 10 degrees rotated in some direction, and the second frame you want to apply a new rotation on top of that 10 degrees. How would you you “save” the current matrix so you can “load” it again the next frame (w/, say, glLoadMatrixf?)? There’s no corresponding glSaveMatrixf function. Do you have to do the math by hand, outside of OpenGL?

    • Cory

      The matrices are actually saved by default. However, since we are calling gl.glLoadIdentity() on each frame at the very beginning, the current matrix is reset to the identity matrix.

  29. qoole

    Thank you for your tutorial, it’s very clear.

  30. GC

    This is a very simple but powerful tutorial.
    Many things become clear now for me.
    Many thanks.

  31. Excellent!
    Great Tutorial!

  32. Thank you for quick tutor.

  33. Guillermo

    Thanks again! it was really easy to read

  34. karim

    everything is well explained except for one thing ,
    there is an implicite loop somewhere , but i really cant find where
    the whole thing is looping after we increment the angle but how is it doing it ?

  35. xFaTE

    popMatrix is mixed up with pushmatrix
    just a hint
    but everything else GREAT!!!

  36. shobha

    This tutorial is very helpful for a beginer.Thank you ..

  37. Sheddy Bear

    xFaTE: Push and Pop are correct in this tutorial. You use a stack of matrices, and you are performing the translate/rotate/scale on the matrix on top of the stack. Push adds a matrix to the top of the stack (copies the top matrix then adds it to the top, so the top TWO matrices are the same immediately following a push), and pop takes the top matrix off. Most glPushMatrix are eventually paired with a glPopMatrix

    Also GREAT tutorial!! I took a computer graphics course 3 years ago but I haven’t done any since, this was a brilliant refresher course.

  38. thai

    Really usefull^^

  39. waikin

    hey great series of tutorials.

    i’m having trouble trying to move a few objects towards the screen on loop. Can anyone help me out with the code to that? lets say make the cubes move into the screen again and again?

    i’ve been playing around with gl.gltranslatef (0f,0f,-5f) but to no avail.

    Sorry if this is too noobish. Help would be very much appreciated!

  40. Hangfire

    Thank you for these tutorials, they’re proving to be more helpful to me than a number of books I’ve bought.

    Just one question…

    At the end of the onDraw method you restore the the last 2 matrices. But at the start of the onDraw method we load the identity matrix. My question is why restore? My guess is to keep the stack of matrices to a minimum preventing the hundreds of stacked matrices from building up.

  41. Eldar

    Great tutorial. Thanks a lot!

  42. ZiN

    Your tutorials are fairly good, they helped me remember a few things and work out where I was going wrong. I followed someone elses tutorial in which there was a few mistakes, I had a funny feeling about it but didn’t test it till last thing.

    Anyway minor mistake with your picture of your left hand. It should be your right hand as OpenGL uses the right hand rule. Thumb is always X and first, second index finger finger is Y and middle finger is Z. Just remember right hand rule, use right hand, starting from thumb working your way around through x,y,z.

    That might clear up confusion a bit when people come across left hand rule systems in which you just use the same procedure but with your left hand. I hope this helps someone.

  43. Praveen Mehra

    thanks a lot it is very owesome…………

  44. Absolutely fantastic job! You have set the standard for online tutorials.

  45. x

    The best tutorial I have seen about OpenGL until now, thanks very much!

  46. lokesh

    Very useful tutorial..Make a idea in Opengl…

  47. Adrian May

    I’m playing with ES 2.0 on a Desire and I find that the coordinate system is left handed, not right handed. X points to the left, y to the top of the screen, and Z points INTO the screen away from your eye. This is contrary to what all the bloggers say, but it’s definitely true on my phone. Is this something strange about ES 2.0?

  48. koupoo

    the picture rotation showed is not fit:
    gl.glRotatef(90f, 0.0f, 0.0f, 1.0f); // OpenGL docs.

  49. Nish

    I am still confuse with coordinate system. I checked Android dev guide too. it shows -1 to 1 X and -1 to 1 Y. So that means all positions has to think values between -1 to 1? And the center is 0,0 that is middle of screen?

    Can you please help to clarify this. I can understand all openGL method but this coordinate system made me completely confused :(

  50. Another congratulation for a great tutorial!

    One comment – the second and third PUSH and POP are unnecessary, since the matrix is replaced with identity matrix at the beginning of each frame. Even if that was not the case, the third PUSH/POP pair is unnecessary.

  51. Khawar Raza

    Very nice tutorial. I am loving it…!!!
    Keep it up.

  52. Merlain

    AMAZING!!
    although I’m a 3d animator,rigger and script writer, I learned a lot today.

    I’m confuse about one thing though, it should be basic knowledge, but I have a childish question :

    Because onDrawFrame is been called several times ( to draw each frame ), why we don’t end up with hundreds or thousands of squares that been created over and over through calling square.draw() on each loop ?

    • Per-Erik Bergman

      Because of this line:
      gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

      clears the screen from everything drawn in the previous frame.

  53. James

    Hi..,

    I have created a simple triangle shown in the GLSurfaceView. Now I want to check touch events on the triangle. If I touch over the tringle, it should say like touched. If I touch outside of it, it should display like not touched. I need to map screen coordinates to 3d coordinates for this but I dont know how to do that. Could you tell me how this issue can be resolved?

    • Per-Erik Bergman

      One way is to work with something called ray picking. I have no tutorial planed for that at the moment.

Trackbacks for this post

  1. Research (Done by Lai Chin Wang) « ifyp
  2. Forbidden things and tricks of OpenGL ES 1.x programming(Android) | Software development support, software risk,bugs for bugs, risk analysis,
  3. OpenGL ES Tutorial for Android – Part III – Transformations | Per-Erik Bergman
  4. OpenGL ES Tutorial for Android – Part II – Building a polygon – Jayway
  5. OpenGL ES Tutorial for Android – Part IV – Adding colors – Jayway

Leave a Reply