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.
The `Pre-' family of transformation function calls,
The `Post-' family of transformation function calls,
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,
Consider what would happen if we reversed the order,
Figure 34 Rotation follows Translation
If this code were substituted in
Let's apply a scaling transformation to change the shape of the box from a cube to a rectangle.
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.
The `sphere' is translated in x to position it closer to the right hand edge of the screen. Note that the line
A `torus' model is added and translated in z to bring it closer to the view position.
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.
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.
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.
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.
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.
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.
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.
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. 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.
sphere->t.type = BR_TRANSFORM_MATRIX34;
could have been omitted as BR_TRANSFORM_MATRIX34
is the default transformation type.
/*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.BRTUTOR1.C
has evolved into BRTUTOR2.C
.
Generated with CERN WebMaker