Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Setting up projection and camera matrices correctly for bitmaps in 3D

Credits go to Edgar Reynaldo and Kev Callahan for helping out!
This thread is locked; no one can reply to it. rss feed Print
Setting up projection and camera matrices correctly for bitmaps in 3D
bitrex
Member #16,587
November 2016

New user here, I've been really enjoying my time experimenting with Allegro 5.

I'm trying to accomplish the following using 3D projection matrices but I'm not sure how to proceed. Here's the setup: I have some bitmaps stored in a class along with 3D position information that I'd like to project into a 3D space. Then I'd like to create a camera transform which allows me to move around these projected bitmaps within the 3D space. Remember the game "Wing Commander"? Something like that. I understand that since the objects are bitmaps they'll always have the same "face" projected towards me, sort of like how objects in "Wolfenstein 3D" were as you moved around a level. For this application, that's OK.

I'm just having trouble figuring out how to set up the appropriate projection matrices and camera transform to render the bitmaps. The thread here:

https://www.allegro.cc/forums/thread/615276

gives an example where first a projection matrix is set up, and then a a camera transform is applied, but I'm not sure if this technique also applies to rendering bitmaps instead of 3D verticies. If there's another thread which covers this topic, a reference would be appreciated.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

The view matrix and the projection matrix are separate, but they are used in combination in the renderer. The view matrix is your camera matrix, that defines your view point and orientation on the world. The projection matrix defines the way the view is rendered, either through perspective projection, or through orthographic projection.

Here is a simple tutorial to display a texture on the screen using view and projection matrices in OpenGL.

Get allegro ready to draw to the backbuffer :

/// NOTE : This changes the view and projection matrices
al_set_target_bitmap(al_get_backbuffer(display));

Setup a camera on the world at (0,0,1500) looking at (0,0,0) with the up vector (0,1,0) :

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0,0,1500 , 0,0,0 , 0,1,0);

Now setup our perspective. We can use glFrustum, gluPerspective, or glOrtho to setup a perspective or orthographic projection respectively.

Setup a perspective projection with a field of view equivalent to half our screen size at a distance of 500 along the negative z-axis. The left and right and top and bottom parameters of glFrustum define the size of the near clipping plane (the top of the frustum). We are setting up our perspective so that the screen will be full size at a distance of 1000 from the camera which is at 500.

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-SCREEN_W/4 , SCREEN_W/4 , -SCREEN_H/4 , SCREEN_H/4 , 500 , 1500);

Drawing 3D textures is mostly the same as drawing 3D vertices. The only difference is that you attach a texture coordinate to a vertex by using glBindTexture and glTexCoord after creating a bitmap and getting its opengl texture id from allegro.

Load a texture.

ALLEGRO_BITMAP* bmp = al_load_bitmap("texture.png");
GLuint texture_id = al_get_opengl_texture(bmp);

Draw a simple texture to fill our virtual screen.

glEnable(GL_TEXTURE_2D);
glFrontFace(GL_CW);// Define winding order as clockwise
glBindTexture(GL_TEXTURE_2D , texture_id);
glBegin(GL_TRIANGLE_FAN);
   glTexCoord2f(1.0 , 0.0);glVertex3f(SCREEN_W/2 , SCREEN_H/2 , 500);// upper right vertex
   glTexCoord2f(1.0 , 1.0);glVertex3f(SCREEN_W/2 , -SCREEN_H/2 , 500);// lower right vertex
   glTexCoord2f(0.0 , 1.0);glVertex3f(-SCREEN_W/2 , -SCREEN_H/2 , 500);// lower left vertex
   glTexCoord2f(0.0 , 0.0);glVertex3f(-SCREEN_W/2 , SCREEN_H/2 , 500);// upper left vertex
glEnd();

And tell allegro to display everything :

This is untested, but it should work, or at least give you an idea what you need to do to render a 3D texture.

EDIT
You can also use allegro's primitives to render textures as well, but you still need to setup your view and projection matrices.

You can also use allegro's transforms to build a camera transform or a perspective transform and then use them as well.

Kev Callahan
Member #6,022
July 2005
avatar

bitrex
Member #16,587
November 2016

Thanks guys. The approach I been working with was attempting to use the built-in Allegro transforms such as al_perspective_transform and al_build_camera_transform to accomplish something similar, using the ex_camera.c example code as a guide.

I don't completely understand that example, it seems to use a lot of auxiliary static functions to compute dot products etc. that complicates things. I'm not familiar with those gl* functions yet, but it seems more straightforward than what I was attempting - maybe I should go with that method?

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

ex_camera uses cross products to generate vectors at right angles to a plane. It's what allows them to roll the camera from any orientation.

Right now, just focus on getting a camera setup, and then try moving it and rotating it around a central point. Worry about things like the up vector later.

You can use OpenGL directly, or Allegro's transforms. Allegro's transforms are probably a bit easier to use and understand as long as you're aware that you need both a view (camera) and a projection matrix set up.

bitrex
Member #16,587
November 2016

Okay, great. If it's not too much to ask, could you provide a code proof-of-concept of how that method would be applied to the problem? ;)

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Sure, I'll explain how to achieve the same thing with Allegro instead of OpenGL.

Setup a camera on the world at (0,0,1500) looking at (0,0,0) with the up vector (0,1,0) : (note that al_build_camera_transform is exactly equivalent to gluLookAt).

ALLEGRO_TRANSFORM cam_transform;
al_identity_transform(&cam_transform);
al_build_camera_transform(&cam_transform , 0 , 0 , 1500 , 0 , 0 , 0 , 0 , 1 , 0);
al_use_transform(&cam_transform);

Setting up an equivalent projection transform to the one before, that makes the screen full size at -1000 relative distance on the z-axis : (note that al_perspective_transform is semantically equivalent to a glFrustum call, but with the parameters in a different order).

ALLEGRO_TRANSFORM proj_transform;
al_identity_transform(&proj_transform);
al_perspective_transform(&proj_transform , -SCREEN_W/4 , -SCREEN_H/4 , 500 , SCREEN_W/4 , SCREEN_H/4 , 1500);
al_use_projection_transform(&proj_transform);

And now draw our texture screen sized using al_draw_prim and ALLEGRO_VERTEXs.

ALLEGRO_COLOR white = al_map_rgb(255,255,255);
int rx = al_get_bitmap_width(texture);
int by = al_get_bitmap_height(texture);
ALLEGRO_VERTEX v[4] = {
   {.x = SCREEN_W/2 , .y = SCREEN_H/2 , .z = 500, .color = white, .u = rx, .v = 0 },
   {.x = SCREEN_W/2 , .y = -SCREEN_H/2, .z = 500, .color = white, .u = rx, .v = by},
   {.x = -SCREEN_W/2, .y = -SCREEN_H/2, .z = 500, .color = white, .u = 0 , .v = by},
   {.x = -SCREEN_W/2, .y = SCREEN_H/2 , .z = 500, .color = white, .u = 0 , .v = 0 }
};
al_draw_prim(v , NULL , texture , 0 , 4 , ALLEGRO_PRIM_TRIANGLE_FAN);

bitrex
Member #16,587
November 2016

A huge help! Thanks so much gents, I really appreciate it.

Go to: