Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Stepping Into the Third Dimension

This thread is locked; no one can reply to it. rss feed Print
Stepping Into the Third Dimension
Todd Cope
Member #998
November 2000
avatar

I am interested in adding support for 3D rendering to my framework. To begin, I'll explain how my framework functions with regard to rendering.

In T³ Framework you select a view with t3f_select_view(). A view is defined with t3f_create_view(offset_x, offset_y, width, height, vp_x, vp_y, flags). The first four arguments represent the position and size of the view within the ALLEGRO_DISPLAY. vp_x and vp_y are the coordinates of the vanishing point within the view itself.

Views utilize what I call a virtual resolution that is defined during initialization of the framework. A default view is created during this step that, assuming no other steps are taken, gives you an ALLEGRO_DISPLAY with dimensions equal to the virtual resolution. If I initialize the framework with a virtual resolution of 640x480, then select a view that was created with <code>t3f_create_view(0, 0, 320, 240, 320, 240, ...), drawing a pixel to <code>(320, 240)<code> will render that pixel at (160, 120) within the ALLEGRO_DISPLAY. If I use the framework's projection routines with this view selected, the vanishing point will be located at (160, 120) within the ALLEGRO_DISPLAY.

For my purposes, I need to be able to have the same kind of functionality while working with actual 3D code. Ultimately, what I need to know is how do I set up Allegro so I can use its primitives functions to render 3D objects into one of these views with the vanishing point being what's defined in the view?

When trying to do actual 3D rendering I was unable to find a way to make the perspective such that the vanishing point was anything other than the center of the ALLEGRO_DISPLAY.

MikiZX
Member #17,092
June 2019

For what is worth... :|

EDIT: I might have misunderstood your post when I originally posted - If you are only looking at setting up a 'window' within your display then possibly https://www.allegro.cc/manual/5/al_build_transform will help you out.

Original post:
I should likely need to google&read about this more though I have a feeling that you are confusing vanishing points (which can be many on a 2d screen presenting a 3d world) and perspective projection.
Googling says this: "A vanishing point is a point on the image plane of a perspective drawing where the two-dimensional perspective projections (or drawings) of mutually parallel lines in three-dimensional space appear to converge."
So basically it is the paralel lines of your 3d objects that, when projected on 2d view, will appear to have a common vanishing point.
So, unless I am very much mistaken, I think the vanishing points on your 2d view will depend more on the geometry and position of your 3d objects than on the projection used itself.
Likely the vanishing points can be accentuaded by changing the field of view of the camera though that is the most one could do, I think.

Then again, I can only see the center of the view be offset using vertex shaders - though this I do not believe will have any effect on the vanishing points - only effect of this would be that the further away the objects are in the 3d world the smaller and closer to the offset point they will be on your 2d view.

Todd Cope
Member #998
November 2000
avatar

Well, Google's definition fits my understanding of vanishing points just fine. I use my own projection routines to place sprites in 3D space already and they move toward the vanishing point within my view if I push them away from the camera far enough.

I'm just trying to find out if there is a way to cause OpenGL to render a 3D scene to a portion of the ALLEGRO_DISPLAY and have it work as if that portion is all there is. Ultimately, I need to be able to create up to four views for split screen games and be able to render 3D scenes within each of those views and have the perspective be correct (the vanishing point being at the center of each view for the scene rendered in that view).

When I search for a solution to this problem, glViewport() comes up and seems like it should work for what I'm trying to do. I tried calling it before rendering my primitives, but it didn't seem to do anything. Is this something that I would need to do with straight OpenGL? Maybe Allegro is doing things behind the scenes that is overwriting my viewport settings. Or maybe I am misunderstanding how this all works.

I think what I'm trying to do is common enough that it shouldn't require a hack like altering the scene's geometry.

MikiZX
Member #17,092
June 2019

I see now what you mean. I haven't done this before so I can only suggest what to try - if you do no succeed let me know and I will do it for you though you sound like you will be able to figure this out on your own.
I believe what you are looking for is a combination of https://www.allegro.cc/manual/5/al_set_clipping_rectangle and the al_build_transform. In my understanding the al_set_clipping_rectangle will set the viewport where Allegro5 will draw (so your 0,0 to 320,240 area) and the al_build_tranform will offset the drawing so that the distance vanishing point is placed an the center of that area (at 160,120). Could you just confirm which Allegro5 commands you are using to draw or are you using OpenGl calls directly?.

EDIT: You could also (likely in the easiest way) achieve this effect by drawing your 3d scene directly to Allegro5 bitmap and then drawing that bitmap directly on the screen at screen position that you wish. To make this work like this you would need to look into https://www.allegro.cc/manual/5/al_set_target_bitmap

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

glViewPort

Also, vanishing points don't depend on the projection matrix used, but more so the alignment of the objects in the view.

Todd Cope
Member #998
November 2000
avatar

I mentioned glViewport(). I tried using it in combination with Allegro functions, but the scene would not adjust to the new viewport.

Here's the code I'm using to set everything up (borrowed from ex_camera):

static void setup_3d_projection(void)
{
   ALLEGRO_TRANSFORM projection;
   ALLEGRO_DISPLAY *display = al_get_current_display();
   double dw = al_get_display_width(display);
   double dh = al_get_display_height(display);
   double f;
   al_identity_transform(&projection);
   al_translate_transform_3d(&projection, 0, 0, -1);
   f = tan(ex.camera.vertical_field_of_view / 2);
   al_perspective_transform(&projection, -1 * dw / dh * f, f,
      1,
      f * dw / dh, -f, 1000);
   glViewport(0, 0, dw / 2, dh / 2);
   al_use_projection_transform(&projection);
}

With this code, I would expect the entire contents of the scene to be rendered at (0, dh / 2) and fill up the bottom left corner of the screen. Instead, it just renders exactly the same thing as before.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Allegro is probably setting the viewport too. Move it after your al_use_projection_transform and see if its different.

glViewport is the only thing that can do this, other than clipping and making your own projection.

Todd Cope
Member #998
November 2000
avatar

I tried that and got the same result.

Edit: I think I found a good solution to my problem. If I create a sub-bitmap of the backbuffer the size and position of my desired viewport and set that bitmap as the target, the rendering works as expected.

For example, if I wanted to make a four way split screen for a game, I can do something like this:

#SelectExpand
1ALLEGRO_DISPLAY * display; 2ALLEGRO_BITMAP * backuffer = NULL; 3ALLEGRO_BITMAP * viewport[4] = {NULL}; 4int dw, dh; 5 6display = al_create_display(640, 480); 7if(!display) 8{ 9 error_out(); 10} 11dw = al_get_display_width(display); 12dh = al_get_display_height(display); 13backbuffer = al_get_backbuffer(display); 14 15viewport[0] = al_create_sub_bitmap(backbuffer, 0, 0, dw / 2, dh / 2); 16viewport[1] = al_create_sub_bitmap(backbuffer, dw / 2, dh / 2, dw / 2, dh / 2); 17viewport[2] = al_create_sub_bitmap(backbuffer, dw / 2, 0, dw / 2, dh / 2); 18viewport[3] = al_create_sub_bitmap(backbuffer, 0, dh / 2, dw / 2, dh / 2);

When it's time to render:

int i;

for(i = 0; i < 4; i++)
{
  al_set_target_bitmap(viewport[i]);
  render_scene();
}

I think this method will integrate nicely with my framework.

Go to: