BRender Tutorial Guide:3 Positioning Actors:Your Second Program
Next|Prev|Up
Transformation Function
Adding the Sphere and Torus
The Animation Loop

Your Second Program


The remainder of this chapter is devoted to demonstrating how to implement translation, rotation, and scaling transformations. BRTUTOR1.C (remember the revolving grey cube) is used as a template. By the end of the chapter, BRTUTOR1.C will have evolved into BRTUTOR2.C, a copy of which is included on your Tutorial Programs disk. You may wish to monitor your progress by editing a copy of BRTUTOR1.C as we go along. This will allow you to compile and run the program at appropriate stages in its evolution. What better way to familiarise yourself with BRender functions than to experiment with them as they are introduced?

When complete, this program will display three models - a box, a sphere and a torus. The actor declarations are thus,

	br_actor *world, *observer, *box, *sphere, *torus;
The camera position is moved 10 units backwards along the positive z-axis, instead of five as previously (the cube will appear smaller). The size of the view volume is increased by moving the yon-plane further away from the view position.

	observer->t.type = BR_TRANSFORM_MATRIX34;
	BrMatrix34Translate(&observer->t.t.mat,BR_SCALAR(0.0),BR_SCALAR(0.0),
BR_SCALAR(10.0));
	camera_data = (br_camera *)observer->type_data;
	camera_data->you_z = BR_SCALAR(50);
Note the explicit cast conversion. Some actors, including camera actors, may have dynamically allocated type-specific data attached. The revised view volume is depicted in Figure 33.

BRTUTOR2.C

/* 
 * Copyright (c) 1996 Argonaut Technologies Limited. All rights reserved.
 * Program to Display a scene containing a Box, a Sphere and a Torus
 */
#include <stddef.h>
#include <stdio.h>
#include "brender.h"
#include "dosio.h"
int main(int argc, char **argv)
{
	br_pixelmap *screen_buffer, *back_buffer, *depth_buffer, *palette;
	br_actor *world, *observer, *light, *box, *sphere, *torus;
	int i;
	br_camera *camera_data;
 
/********* Initialise BRender and Graphics Hardware ************/
BrBegin();
/*
 * Initialise screen buffer and set up CLUT (ignored in true colour) 
 */
.      .      .
.      .      .
.      .      .
.      .      .
.      .      .
.      .      .
BrZbBegin(screen_buffer->type, BR_PMT_DEPTH_16);
back_buffer = BrPixelmapMatch(screen_buffer,BR_PMMATCH_OFFSCREEN);
depth_buffer = BrPixelmapMatch(screen_buffer,BR_PMMATCH_DEPTH_16);

/*************** Build the World Database **********************/
/* 
 * Start with None actor at root of actor tree and call it `world'
 */ 
world = BrActorAllocate(BR_ACTOR_NONE,NULL);

/*
 * Add, and enable, the default light source
 */
light = BrActorAdd(world,BrActorAllocate(BR_ACTOR_LIGHT,NULL));
BrLightEnable(light);
/*
 * Load and Position Camera
 */
observer = BrActorAdd(world,BrActorAllocate(BR_ACTOR_CAMERA,NULL));
observer->t.type = BR_TRANSFORM_MATRIX34; 
BrMatrix34Translate(&observer->t.t.mat,BR_SCALAR(0.0),BR_SCALAR(0.0),
                                                      BR_SCALAR(10.0));
camera_data = (br_camera *)observer->type_data;
camera_data->you_z = BR_SCALAR(50);
/*
 * Load and Position Box Model
 */
box = BrActorAdd(world,BrActorAllocate(BR_ACTOR_MODEL,NULL));
box->t.type = BR_TRANSFORM_MATRIX34;
BrMatrix34RotateY(&box->t.t.mat,BR_ANGLE_DEG(30));
BrMatrix34PostTranslate(&box->t.t.mat,BR_SCALAR(-2.5),BR_SCALAR(0.0),
                                                      BR_SCALAR(0.0));
BrMatrix34PreScale(&box->t.t.mat,BR_SCALAR(2.0),BR_SCALAR(1.0), BR_SCALAR(1.0));
/*
 * Load and Position Sphere Model
 */
sphere = BrActorAdd(world,BrActorAllocate(BR_ACTOR_MODEL,NULL));
sphere->model = BrModelLoad("sph32.dat");
BrModelAdd(sphere->model);
sphere->t.type = BR_TRANSFORM_MATRIX34;
BrMatrix34Translate(&sphere->t.t.mat,BR_SCALAR(2.0),BR_SCALAR(0.0),
                                                    BR_SCALAR(0.0));
/*
 * Load and Position Torus Model
 */
torus = BrActorAdd(world,BrActorAllocate(BR_ACTOR_MODEL,NULL));
torus->model = BrModelLoad("torus.dat");
BrModelAdd(torus->model);
torus->t.type = BR_TRANSFORM_MATRIX34;
BrMatrix34Translate(&torus->t.t.mat,BR_SCALAR(0.0),BR_SCALAR(0.0),
                                                   BR_SCALAR(3.0));

/********************** Animation Loop ***********************/
	for(i=0; i < 360; i++) {
			BrPixelmapFill(back_buffer,0);
			BrPixelmapFill(depth_buffer,0xFFFFFFFF);
			BrZbSceneRender(world,observer,back_buffer,depth_buffer);
			BrPixelmapDoubleBuffer(screen_buffer,back_buffer);
			BrMatrix34PostRotateX(&box->t.t.mat,BR_ANGLE_DEG(2.0));
			BrMatrix34PreRotateZ(&torus->t.t.mat,BR_ANGLE_DEG(4.0));
			BrMatrix34PreRotateY(&torus->t.t.mat,BR_ANGLE_DEG(-6.0));  
			BrMatrix34PreRotateX(&torus->t.t.mat,BR_ANGLE_DEG(2.0));
			BrMatrix34PostRotateX(&torus->t.t.mat,BR_ANGLE_DEG(1.0));
			BrMatrix34PostRotateY(&sphere->t.t.mat,BR_ANGLE_DEG(0.8));  
	}
/*
 * Close down 
 */
BrPixelmapFree(depth_buffer);
BrPixelmapFree(back_buffer);
BrZbEnd();
.      .      .
.      .      .
.      .      .
.      .      .
.      .      .
.      .      .
	BrEnd();
	return 0;
}
BRTUTOR2.C



Figure 33 Revised view position and view volume

The following code loads and positions the cube or `box':

	box = BrActorAdd(world,BrActorAllocate(BR_ACTOR_MODEL,NULL));
	/*Define box's transformation*/
	box->t.type = BR_TRANSFORM_MATRIX34;
	BrMatrix34RotateY(&box->t.t.mat,BR_ANGLE_DEG(30));
	BrMatrix34PostTranslate(&box->t.t.mat,BR_SCALAR(-2.5),BR_SCALAR(1.0), 
                                                         BR_SCALAR(1.0)); 
The changes made to BRTUTOR1.C so far are highlighted in bold. If you were to implement these changes and re-compile the program, a revolving grey cube would be displayed close to the left edge of the screen.

Transformation Function

Remember that matrix multiplication is non-commutative. The order in which transformations are applied is critical. Three families of calls are provided for implementing transformations. The standard implementation,

	BrMatrix34Translate()
	BrMatrix34Rotate()
	BrMatrix34Scale()
sets a target matrix to a matrix representing a translation, rotation or scaling.

The `Pre-' family of transformation function calls,

	BrMatrix34PreTranslate()
	BrMatrix34PreRotate()
	BrMatrix34PreScale()
pre-multiplies a target matrix by a matrix representing a translation, rotation or scaling, and puts the result back in the target matrix.

The `Post-' family of transformation function calls,

	BrMatrix34PostTranslate()
	BrMatrix34PostRotate()
	BrMatrix34PostScale()
post-multiplies a specified matrix by a matrix representing a translation, rotation or scaling, and puts the result back in the specified matrix.

Use the standard calls to initialise a matrix to represent a specified transformation.

Given a matrix representing a transformation, or series of transformations, use the `Pre-' family of calls to add an additional transformation at the beginning.

Given a target matrix representing a transformation, or series of transformations, use the `Post-' family of calls to append a transformation at the end.

Consider the `box' transformation above - a rotation followed by a translation. If we neglected to specify a `Post-' translation,

	BrMatrix34RotateY(&box->t.t.mat,BR_ANGLE_DEG(30)); 
	BrMatrix34Translate(&box->t.t.mat,BR_SCALAR(-2.5),BR_SCALAR(0.0),
                                                     BR_SCALAR(0.0));
the rotation would not be implemented. We would simply get a translation in x, as the rotation matrix has been replaced by the translation matrix.

Consider what would happen if we reversed the order,

	BrMatrix34Translate(&box->t.t.mat,BR_SCALAR(-2.5),BR_SCALAR(0.0),
                                                     BR_SCALAR(0.0));
	BrMatrix34PostRotateY(&box->t.t.mat,BR_ANGLE_DEG(30));
to give a translation followed by a rotation. The box would be translated in x, before being rotated around the y-axis.



Figure 34 Rotation follows Translation

If this code were substituted in BRTUTOR2.C, the resulting animated sequence would be very different from that generated by the original program. Note that the following code would produce exactly the same result,

	BrMatrix34RotateY(&box->t.t.mat,BR_ANGLE_DEG(30));
	BrMatrix34PreTranslate(&box->t.t.mat,BR_SCALAR(-2.5),BR_SCALAR (0.0),
                                                        BR_SCALAR(0.0));
a translation followed by a rotation. Try out these and other variations for yourself. A little experimentation at this stage could pay dividends later.

Let's apply a scaling transformation to change the shape of the box from a cube to a rectangle.

	BrMatrix34RotateY(&box->t.t.mat,BR_ANGLE_DEG(30)); 
	BrMatrix34PostTranslate(&box->t.t.mat,BR_SCALAR(-2.5),BR_SCALAR (0.0),
                                                         BR_SCALAR(0.0));
	BrMatrix34PreScale(&box->t.t.mat,BR_SCALAR(2.0),BR_SCALAR(1.0), 
	                                                BR_SCALAR(1.0));
We called the `Pre-' scaling function because we wanted the scaling transformation to be applied to the box before it was positioned in the scene. The above scaling multiplies the x-components of the box's vertices by 2.

Note that, had we specified `Post-' scaling, the translation factor would have been scaled along with the vertices. In this case, the previously specified translation factor (-2.5) would have been doubled (to -5). You are again invited to experiment.

Adding the Sphere and Torus

At this stage our program displays a scaled `box' near the left edge of the screen, revolving around the x-axis. Let's introduce the other models, starting with the sphere.

	/*Load and Position Sphere Model*/
	sphere = BrActorAdd(world,BrActorAllocate(BR_ACTOR_MODEL,NULL));
	sphere->model = BrModelLoad("sph32.dat");
	BrModelAdd(sphere->model);
	sphere->t.type = BR_TRANSFORM_MATRIX34;
	BrMatrix34Translate(&sphere->t.t.mat,BR_SCALAR(2.0),BR_SCALAR(0.0),
                                                       BR_SCALAR(0.0));
The first line of this code adds a new model actor to the database, as a child of `world', and calls it `sphere'. If you want to display a model other than the default cube, you must first load it from a model data file,

	sphere->model = BrModelLoad("sph32.dat");
then add it to the registry,

	BrModelAdd(sphere->model);
Remember that actors, models, materials and pixel maps must be added to the registry before they can be used. Model descriptions are stored in .dat files. A number of sample model files are contained on your Tutorial Programs disk (all with .dat extensions). You can create your own models in 3D Studio, then convert them to BRender .dat format using the supplied utilities 3DS2BR and GEOCONV. 3DS2BR converts 3D Studio models stored as .3ds binary files while GEOCONV handles ASCII (.asc) files.

The `sphere' is translated in x to position it closer to the right hand edge of the screen. Note that the line

	sphere->t.type = BR_TRANSFORM_MATRIX34;
could have been omitted as BR_TRANSFORM_MATRIX34 is the default transformation type.

A `torus' model is added and translated in z to bring it closer to the view position.

	/*Load and Position Torus Model*/
	torus = BrActorAdd(world,BrActorAllocate(BR_ACTOR_MODEL,NULL));
	torus->model = BrModelLoad("torus.dat");
	BrModelAdd(torus->model);
	torus->t.type = BR_TRANSFORM_MATRIX34;
	BrMatrix34Translate(&torus->t.t.mat,BR_SCALAR(0.0),BR_SCALAR(0.0),
                                                      BR_SCALAR(3.0));
If you add the above code and re-compile the program, a torus will be displayed in the centre of the screen - flanked on one side by a revolving rectangle and on the other by a sphere.

The Animation Loop

Let's complete the animation. The revised animation loop is given below, with additional code highlighted:

for(i=0; i < 360; i++) {

	BrPixelmapFill(back_buffer,0);
	BrPixelmapFill(depth_buffer,0xFFFFFFFF);
	BrZbSceneRender(world,observer,back_buffer,depth_buffer);
	BrPixelmapDoubleBuffer(screen_buffer,back_buffer);
	BrMatrix34PostRotateX(&box->t.t.mat,BR_ANGLE_DEG(2.0));
	BrMatrix34PreRotateZ(&torus->t.t.mat,BR_ANGLE_DEG(4.0)); 
	BrMatrix34PreRotateY(&torus->t.t.mat,BR_ANGLE_DEG(-6.0)); 
	BrMatrix34PreRotateX(&torus->t.t.mat,BR_ANGLE_DEG(2.0)); 
	BrMatrix34PostRotateX(&torus->t.t.mat,BR_ANGLE_DEG(1.0)); 
	BrMatrix34PostRotateY(&sphere->t.t.mat,BR_ANGLE_DEG(0.8));  
}
Lets consider the torus. For each iteration of the loop, the specified PreRotations are added at the beginning of the transformation series (so they are implemented before the translation), and the PostRotation is added at the end. The concatenated matrix thus represents rotations in x, y and z (4xb0 , -6xb0 , and 2xb0 respectively), followed by the compound transformation defined by the previous concatenation which is then followed by a 1xb0 rotation in x.

The sphere is PostRotated in y. Since it had been previously translated +2 units in x, it circles the y-axis in a broad sweep.

BRTUTOR1.C has evolved into BRTUTOR2.C.


Generated with
CERN WebMaker