Harold Serrano

View Original

How to rotate a game character using OpenGL ES

Introduction

3D models are developed in 3D modeling applications like Blender. Each 3D model is developed in their own local space system. When a 3D model is displayed on a display, its local space system is converted, i.e., transformed, into several space systems.

The space transformations a 3D model goes through are:

  • Model-World Space Transformation.
  • Model-World-View Space Transformation.
  • Perspective Projection Space Transformation (MVP transformation).

Objective

The goal for this project is to transform a model space into a Model-View-Projection space. At the end of the project, you will know how transformations are applied to rotate a 3D model.

Things to know

If you have not done so, I recommend you to read these posts:

In this post, Space system and Coordinate system refers to the same concept.

Model Space System

The Model Space System is simply the coordinate system where the 3D model was developed. This space system is unique to the 3D model.

A 3D model is made up of vertices. Every vertex is measured relative to an origin point. Two identical 3D models will have different vertex coordinates depending on the origin point chosen by the designer.

For example, figure 1 and 2 shows the same 3D model but with different origin points. Figure 1 the origin of the 3D model is at its center. Whereas, the origin for the 3D model in figure 2 is at its feet. If you were to measure the coordinates of the same vertex from these two models, both coordinates will differ as shown in the figures.

Figure 1. Model Space with origin at center

Figure 2. Model Space with origin at feet

Model-World Space System

A Model Space System is the unique space of the model. Two distinct models, each with their own space, can’t interact with each other. For interaction to occur, each model is transformed into the World Space System.

The transformation of a model space into a world space is referred as Model-World Space System.

Figure 2 shows the transformation of a 3D model into the world space. Unique to its space, the 3D model has not been translated. However, with respect to the world space, the model has been translated 2 units in the positive x-axis.

Figure 2. Model-World Space

Model-World-View System

What is seen on a screen is relative to a viewer, i.e., a camera. A change in a camera’s orientation and position changes what a viewer sees.

Once the Model-World Space is calculated, it needs to be transformed by the Camera Space System. The result of this transformation is called Model-World-View Space. Is it also often called Model-View Space.

Figure 3 shows the position of the camera relative to the world space. However, what you see on the display of your mobile device is through camera space, i.e., figure 4.

Figure 3. Position of Camera with respect to world

Figure 4. Model-World-View Space

Projective Space System

What is perceived in a screen as three dimensional is just an illusion. It is just a two dimensional image. The final transformation in the OpenGL pipeline occurs in what is called the Projective Space System. This transformation converts a three dimensional scenery into a two dimensional image. The Projective coordinate system can be configured in two ways:

  • Perspective View
  • Orthogonal View

Perspective View

When the projective's coordinate system is set as a Perspective View, it gives the illusion of producing a three dimensional scenery. This is an illusion created by producing a vanishing point and making objects farther from the camera smaller, thus producing the illusion of depth. Figure 4 shows an example of perspective view.

Orthogonal View

In Orthogonal View, every object in the scene is seen as a two-dimensional object. There is no illusion of depth. 2D games are set up to use orthogonal projection.

The Projective Space transforms the Model-View Space, resulting in the Model-View-Projection Space (MVP Space). The space is then transformed one final time by a screen space, done automatically by OpenGL. 

Transforming a 3D model space

The goal for this project is to transform a model space into a Model-View-Projection space. The shaders in our project will use this space transformation to render a 3D model. 

We will create four different spaces. They are:

  • Model Space
  • World Space
  • View Space
  • Projection Space

In this project, we will use matrices to represent our space systems.

The GLKit framework is an Apple framework that provides commonly used vector, quaternion and matrix operations. Our project will use the math library provided by this framework.

This is a hands on project. Feel free to download this template XCode project.

Open Character.mm file and go to method setTransformation(). Copy what is shown in listing 1.

Listing 1. Setting up the transformation spaces
void Character::setTransformation(){

//1. Set up the model space
modelSpace=GLKMatrix4Identity;

//2. Since we are importing the model from Blender, we need to change the axis of the model
//else the model will not show properly. x-axis is horizontal axis, y-axis is coming out the screen, z-axis is vertical axis

GLKMatrix4 blenderSpace=GLKMatrix4MakeAndTranspose(1,0,0,0,
0,0,1,0,
0,-1,0,0,
0,0,0,1);

//3. Transform the model space by Blender Space
modelSpace=GLKMatrix4Multiply(blenderSpace, modelSpace);


//4. Set up the world space
worldSpace=GLKMatrix4Identity;

//5. Transform the model space to the world space
modelWorldSpace=GLKMatrix4Multiply(worldSpace,modelSpace);

//6. Set up the view space. We are translating the view space 1.5 unit down and 5 units out of the screen.
cameraViewSpace = GLKMatrix4MakeTranslation(0.0f, -1.5f, -5.0f);

//7. Transform the model-World Space by the View space
modelWorldViewSpace = GLKMatrix4Multiply(cameraViewSpace, modelWorldSpace);


//8. set the Projection-Perspective space with a 45 degree field of view and an aspect ratio
//of width/height. The near and far clipping planes are set to 0.1 and 100.0 respectively
projectionSpace = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(45.0f), fabsf(screenWidth/screenHeight), 0.1f, 100.0f);


//9. Transform the model-world-view space to the projection space
modelWorldViewProjectionSpace = GLKMatrix4Multiply(projectionSpace, modelWorldViewSpace);

//10. extract the 3x3 normal matrix from the model-world-view space for shading(light) purposes
normalMatrix = GLKMatrix3InvertAndTranspose(GLKMatrix4GetMatrix3(modelWorldViewSpace), NULL);


//11. Assign the model-world-view-projection matrix data to the uniform location:modelviewProjectionUniformLocation
glUniformMatrix4fv(modelViewProjectionUniformLocation, 1, 0, modelWorldViewProjectionSpace.m);

//12. Assign the normalMatrix data to the uniform location:normalMatrixUniformLocation
glUniformMatrix3fv(normalMatrixUniformLocation, 1, 0, normalMatrix.m);


}

Our goal is to render a 3D model on the screen with no rotations nor translations. Thus, the model and world space will contain no rotations nor translations. A space system with no rotation nor translation is represented with an Identity matrix.

To create an identity matrix with the GLKit framework you use the method GLKMatrix4Identity. This method creates a 4x4 identity matrix for our model space (line 1).

A 3D modeling artist used Blender to design the 3D model used in this project. Unfortunately, the coordinate systems of Blender and OpenGL are not the same. Thus, a transformation from Blender space to OpenGL space is required. Line 2 show the matrix which will transform our model space into the correct space.

The GLKMatrix4Multiply transforms the model space into the blender space (line 3).

The GLKMatrix4Identity creates an identity matrix for the world space (line 4).

The world space transforms the model space into the Model-World space (line 5).

Line 6 shows the creation of the camera space. The camera space contains no rotations. However, the method GLKMatrix4MakeTranslation translate the camera in the y and z axis.

The camera space transforms the Model-World space into the Model-World-View space (line 7).

The Model-Wold-View space is also referred as the Model-View space.

In line 8, the GLKMatrix4MakePerspective method creates a Projection-Perspective space. The space is computed with a 45 degree field of view. And a near and far clipping plane of 0.1 and 100.0, respectively.

The projection space transforms the Model-World-View space into the Model-World-View-Projection matrix (line 9).

The MVP matrix is an alternative name for the Model-World-View-Projection matrix.

The shader used in this project will light the 3D model. The Lighting operations require a normal matrix. This normal matrix is extracted from the Model-World-View space (line 10).

Finally, the MVP and normal matrix are sent to the vertex shader in lines 11 & 12.

The Model-World-View-Projection and Model-View-Projection terms refers to the same space system.

Run the project. You should see the 3D model rendered on the screen.

Figure 1.

Applying a rotational transformation

Let's provide a rotation transformation to the 3D model. We are going to transform the model space with a rotational transform matrix. This transformation will occur at a rate of 60 Frames-Per-Second (FPS).

The project has been setup to call the draw and update methods 60 FPS. The update method receives the time lapsed since the last update. This time will serve as an angle parameter to the rotation transform matrix.

Open up the Character.mm file and locate the update() method. Copy what is shown in listing 2.

Listing 2. Applying a rotation transform to the model
void Character::update(float dt){

//1. Rotate the model space by "dt" degrees about the vertical axis
modelSpace=GLKMatrix4Rotate(modelSpace, dt, 0.0f, 0.0f, 1.0f);

//2. Transform the model space to the world space
modelWorldSpace=GLKMatrix4Multiply(worldSpace,modelSpace);

//3. Transform the model-World Space by the View space
modelWorldViewSpace = GLKMatrix4Multiply(cameraViewSpace, modelWorldSpace);

//4. Transform the model-world-view space to the projection space
modelWorldViewProjectionSpace = GLKMatrix4Multiply(projectionSpace, modelWorldViewSpace);

//5. extract the 3x3 normal matrix from the model-world-view space for shading(light) purposes
normalMatrix = GLKMatrix3InvertAndTranspose(GLKMatrix4GetMatrix3(modelWorldViewSpace), NULL);

//6. Assign the model-world-view-projection matrix data to the uniform location:modelviewProjectionUniformLocation
glUniformMatrix4fv(modelViewProjectionUniformLocation, 1, 0, modelWorldViewProjectionSpace.m);

//7. Assign the normalMatrix data to the uniform location:normalMatrixUniformLocation
glUniformMatrix3fv(normalMatrixUniformLocation, 1, 0, normalMatrix.m);

}

The GLKMatrix4Rotate method transforms the model space dt degrees about the vertical axis (line 1).

Note: The 3D model was developed in Blender. In Blender, the z-axis represents the vertical axis.

Every other space is then updated with the new transformation (lines 2-5).

Lines 6 & 7 provide the new space transformation to the shaders.

Run the project. The 3D model should now rotate about the vertical axis on your screen.

Source Code

The final source code can be found here.

Questions?

So, do you have any questions? Is there something you need me to clarify? Did this project help you? Please let me know. Add a comment below and subscribe to receive our latest game development projects.