3D_for_GML:_Rolling_ball - hpgDesigns/hpgdesigns-dev.io GitHub Wiki
1.1 Understanding transformation
By now you should be familiar with some of the basic drawing functions:
drawing a ball, block or floor object is probably a piece of cake. The
same is probably true for objects that move in 3D space. Something we
haven’t looked at though is how to use transformation. All
transformation codes in GM start with d3d_transform_
. Transformation
of what? Well, let’s take a look at a drawing code from one of the
previous
tutorials:
d3d_draw_ellipsoid(x-16, y-16, z, x+16, y+16, z+32, background_get_texture(bk_player), 1, 1, 16);
The ball is drawn at a location based on the object’s x, y and z. The code draws an object at its own location. Transformation is based not on the object’s own location but on the world as a whole. Transformation of what? Well, transformation of the 3D world in which objects are drawn. Transformation is based on the virtual 3D world, not on objects.
1.2 Starting and ending transformation
To start transformation of the 3D world, we use this code:
d3d_transform_set_identity();
This will set the origin of the 3D world to location 0,0,0 (which is the center of the world). It is important to end transformation afterwards, using the same command:
d3d_transform_set_identity();
1.3 Using rotations around two axes
This tutorial uses a rolling ball to show how transformations, in particular rotations, work. The code that performs the transformation can be found in the Draw event of the ball object (draw_ball). The complete code to draw a rolling ball is:
//begin transformation
d3d_transform_set_identity();
//rotate
d3d_transform_add_rotation_y(rotation);
d3d_transform_add_rotation_z(direction);
//translate
d3d_transform_add_translation(x, y, z+16);
//Draw a ball
d3d_draw_ellipsoid(-16, -16, -16, 16, 16, 16, background_get_texture(bk_ball), 4, 2, 32);
//end transformation
d3d_transform_set_identity();
As you can see, the transformation starts with setting the identity: the origin of the 3D world. If transformation has begun, the world is rotated, first around the y axis (roll) and secondly around the z axis (yaw). The rotation value that will be used is defined in the ball motion script mot_ball, using the following lines of code:
//set rotation
rotation-=speed;
If the ball moves faster, rotation increases. The rotation value is used to rotate around the y axis creating a rolling effect. The direction value is used to rotate the ball around the z axis creating the effect of a ball rolling in the direction it is heading. As a result of this, the 3D world will now be rotated around two axes. This works fine as long as the ball stays at the world’s very center but if the ball has to move around in the 3D world, we will have to shift the world coordinates which is called translation.
1.4 Applying translation
Translating the world effectively means that you shift the 3D world towards a 3D coordinate (point) so that the 3D drawing ends up at the desired location. Let’s take a look at the code in the forementioned draw_ball script that translates the world to the coordinates of the ball object:
//translate
d3d_transform_add_translation(x, y, z+16);
This means the invisible drawing box (that is the 3D world’s coordinate system) will be moved over to the location of the ball (at position x, y, z of the ball). Because the ball’s z location is actually at 0, we'll add 16 to have the ball drawn a little higher so it appears to sit on the ground (floor). We have now shifted the drawing box to where the ball object is located in the 3D world. This means we will no longer have to use the ball’s coordinates if we are going to draw. The drawing box is already translated to the object’s location so we can draw at a location of 0,0,0. The drawing code will be placed within the setting of identities. The whole point of transformation is to transform the invisible drawing box that is the 3D world.
1.5 Drawing and transformation
Back to our ball object. The drawing box has been moved over to the ball’s location which means we don’t need to use x, y and z any more in the ball’s Drawing event. This makes our drawing code for the ball object look like this:
//Draw a ball
d3d_draw_ellipsoid(0-16, 0-16, 0-16, 0+16, 0+16, 0+16, background_get_texture(bk_ball), 4, 2, 32);
If you remove the zeros, you will get the code that is used in the gm6 file that comes with this tutorial text:
//Draw a ball
d3d_draw_ellipsoid(-16, -16, -16, 16, 16, 16, background_get_texture(bk_ball), 4, 2, 32);
We've rotated and translated and have now drawn the ball. All that remains now is to end the transformation with:
//end transformation
d3d_transform_set_identity();
1.6 About the camera
The camera code that is used in the script draw_camera looks like this:
//Draw what camera sees
with(obj_ball)
{
d3d_set_projection(x-128, y, 128, x, y, z+16, 0, 0, 1);
}
This results in a camera that stays focused on the ball.