Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Further question regarding camera and projection transforms

This thread is locked; no one can reply to it. rss feed Print
Further question regarding camera and projection transforms
bitrex
Member #16,587
November 2016

As a followup to this thread:

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

I have my sprites being loaded and projected onto the screen with appropriate perspective applied, great.

At this point I'm a little confused as to how to set up the coordinate system to accomplish what I'm trying to do.

I'd like a static background (ideally a skybox) placed at infinity, with the bitmaps placed at various 3D coordinates inside the "world."

So my issue is understanding how the settings in a line like this:

al_build_camera_transform(&cam_transform , 0 , 0 , 1500 , 0 , 0 , 0 , 0 , 1 , 0);

and:

`al_perspective_transform(&proj_transform , -SCREEN_W/4 , -SCREEN_H/4 , 500 , SCREEN_W/4 , SCREEN_H/4 , 1500);`

fit in to the picture.

As I understand it, the first line sets up a camera at (0, 0, 1500) pointed towards the scene. And the second creates a perspective transform for the vertices where 500 and 1500 are the near and far object clip distances, respectively.

If I try blitting a small 2D sprite to the screen, like a star for a starfield and set its Z coordinate at something like 1400, it's scaled to be right up in front of the camera. If I set it at say 100, it's somewhat further back, but not nearly far enough back if I wanted to say scroll this starfield in the Z direction towards the camera and make it appear from "nothing."

Why is the camera position set at 1500, which is the "far" clip distance? Shouldn't it be set at the "near" clip distance?

What are the z dimensions of my 3D "world" in this setup? Is it between 500 and 1500?

I'm just having some trouble understanding how these various coordinates interrelate, any advice or references would be appreciated.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

First, figure out the direction the camera is pointing. In this case, it's from z = 1500 towards z = 0, so it's pointing along the negative z-axis. Second, apply the view volume (perspective attributes) to the camera. The near clipping plane is at 500 in front of the camera, which places it at z = 1000. The far clipping plane is at 1500 in front of the camera, which places it at z = 0. So the z range of your world in this case is [1000 , 0]. That's why an object at 1400 appears to be right in front of the camera, because it's only 100 away from it. However, something at that z distance should have been clipped out of view by the near clipping plane at 1000 absolute z if you were drawing it with opengl. The depth buffer may not have been setup properly to clip objects. With allegro (or OpenGL) you have to enable the depth buffer :

Allegro 5

al_set_new_display_option(ALLEGRO_DEPTH_SIZE , 16 , ALLEGRO_SUGGEST);
al_create_display(...);

OpenGL

glEnable(GL_DEPTH_TEST);

As for drawing a skybox, I think you can do it by drawing it first, and then clearing the depth buffer.

glClear(GL_DEPTH_BUFFER_BIT);

With your glPerspective call, you need to understand the coordinates are relative to your camera. With the gluLookAt function, the coordinates are absolute. That is where your confusion is coming from.

bitrex
Member #16,587
November 2016

Great, thanks. I was definitely not enabling the depth buffer prior to instantiating the display, so that was a problem...:-/

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

With some general trigonometry you can get an estimated depth necessary to make your star sprite appear only one pixel wide.

With a FOV set up as before, you have the screen setup to be full size at a distance of 1000 from the camera. This gives you horizontal and vertical fields of view of :

tan(HFOV/2) = (SCREEN_W/2)/1000;

tan(VFOV/2) = (SCREEN_H/2)/1000;

Giving you :

HFOV = 2*atan((SCREEN_W/2)/1000);

VFOV = 2*atan((SCREEN_H/2)/1000);

And you want to find the distance that would make your WxH sprite appear to be 1 pixel wide or tall, which takes up 1/SCREEN_W % of the HFOV or 1/SCREEN_H % of the VFOV.

HFOV1 = HFOV/SCREEN_W;

VFOV1 = VFOV/SCREEN_H;

Now we know that the HFOV and VFOV are defined by their width and height and their distance, so we have from before :

tan(HFOV1) = SPRITE_W/DISTANCE;

tan(VFOV1) = SPRITE_H/DISTANCE;

This gives us :

DISTANCE = SPRITE_W/tan(HFOV1);

DISTANCE = SPRITE_H/tan(VFOV1);

Substituting from before we have :

DISTANCE = SPRITE_W / tan((2/SCREEN_W)*atan((SCREEN_W/2)/1000));

DISTANCE = SPRITE_H / tan((2/SCREEN_H)*atan((SCREEN_H/2)/1000));

From that you should be able to calcualate a distance at which to draw your star sprite. That or you can just draw it smaller than actual size.

bitrex
Member #16,587
November 2016

Thanks again for your help, I've got my moving star field working pretty good now.

One more question to polish it off - the bitmaps I'm using as textures have a black border that in my original implementation, using al_draw_bitmap and setting the blender option, was rendered as transparent.

I'm having trouble setting it up using the primitive in the same way - I'm seeing a black rectangle outling the square that the bitmap is "pasted" onto. How to rectify?

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

bitrex
Member #16,587
November 2016

Sorry, still having a lot of trouble with this. I've edited my bitmap such that it has an alpha channel layer with alpha=0 around the border I believe, the checkerboard pattern is showing through in my image editor, and then prior to rendering the texture onto the primitive I've messed around with various arguments to al_map_rgba as a field in the list of four vertices, but I can't seem to get the negative space around the relevant texture portions of the bitmap to disappear entirely, allowing me to independently set the transparent of my "star."

Sometimes if one object is rendered in front of another it seems to kinda be working, and other times, not. :-/

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Make sure the edge is 'crisp' and that there aren't any halfway blended black pixels around the edge, otherwise they'll show up as gray or dark black.

For your vertice colors, you want to use white scaled by the alpha to vary the transparency.

It sounds like you're not using pre-multiplied alpha on your bitmaps, but it is the default. Read the manual entry on al_load_bitmap_flags for details.

If you can, post more code and I'll take a look at it. Zip files are best.

bitrex
Member #16,587
November 2016

So here's the setup, I have the blender set like this prior to starting the main loop:

al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA);

And then when rendering I set up the vertices similar to the example code:

#SelectExpand
1float r = 1.0f; 2float g = 1.0f; 3float b = 1.0f; 4float a = 0.5f; 5 6ALLEGRO_COLOR bkg = al_map_rgba_f(1*a, 1*a , 1*a , a); 7ALLEGRO_VERTEX v[4] = 8 { 9 {(*_main_sprite)[0] - rx/2, (*_main_sprite)[1] + by/2, (*_main_sprite)[2], rx, 0.0, {bkg}}, 10 {(*_main_sprite)[0] + rx/2, (*_main_sprite)[1] + by/2, (*_main_sprite)[2], rx, by, {bkg}}, 11 {(*_main_sprite)[0] + rx/2, (*_main_sprite)[1] - by/2, (*_main_sprite)[2], 0.0, by, {bkg}}, 12 {(*_main_sprite)[0] - rx/2, (*_main_sprite)[1] - by/2, (*_main_sprite)[2], 0.0, 0.0, {bkg}} 13 }; 14 15 16al_draw_prim(v, NULL, _main_sprite->bitmap(), 0, 4,` ALLEGRO_PRIM_TRIANGLE_FAN);

The result is attached. You may be able to see that at top center a star behind seems to be showing through the border in front as I want, but in the distant center star it looks like a black border is occluding the star behind.

Using the equations you provided, if I'm not wrong I found that the "one pixel wide" Z-depth for these sprites is at around 150,000, which seems to look about right in practice.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

bitrex
Member #16,587
November 2016

Okay, it's attached.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Your star is just too dark in the heavy alpha areas. It's going to show that dark boundary when you draw it. You can try a flood fill in paint.net with zero alpha black on the background after painting it black. Also, you probably want to save it as a .png file. 32 bit BMP support is spotty as far as I know.

EDIT
You could try this star, it's just something I came up with quick off of google images.
610618

EDIT
The dark blue will still occlude things behind it. It's just a matter of getting the star clear in the areas you want it.

bitrex
Member #16,587
November 2016

Thank you, that .png does look quite bit better in practice than mine, but still not quite right. I agree though it seems to be a problem with my images, maybe not my blender setup. I wonder if using a circle instead of a square for the primitive the texture is applied to would help things...

Only other question I have at this point is how I can apply a backdrop/skybox to the scene using the transformations such that it always appears behind my foreground sprites. I've tried using the code I have, but if I use the perspective transform to place it in the scene such that fills the window, all my sprites end up getting Z-buffered out as they're "behind" the backdrop.

I'm guessing I need to calculate the appropriate (large) x/y coordinates for primitive at "infinity" to texture and apply the orthographic transform?

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

An orthographic transform makes everything the same size appear the same size regardless of distance. Think of it as a cubical view volume.

The algorithm I would use is :

1. Setup an orthorgraphic transform as big as your skybox.
2. Render your skybox.
3. Clear the depth buffer bit (glClear(GL_DEPTH_BUFFER_BIT);)
4. Setup your perspective transform
5. Draw your stars and objects

Go to: