- Transformation Function
- Adding the Sphere and Torus
- The Animation Loop

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,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.*box, *sphere, *torus;

observer->t.type = BR_TRANSFORM_MATRIX34; BrMatrix34Translate(&observer->t.t.mat,BR_SCALAR(0.0),BR_SCALAR(0.0), BR_SCALAR(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.10.0)); camera_data = (br_camera *)observer->type_data; camera_data->you_z = BR_SCALAR(50);

**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':

The changes made tobox= 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));

`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.

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));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.BrMatrix34PreScale(&box->t.t.mat,BR_SCALAR(2.0),BR_SCALAR(1.0),BR_SCALAR(1.0));

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.

/*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.

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));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 (4BrMatrix34PreRotateZ(&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));}

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