cgraphicsprojectionisometric

How can I transform 3D coordinates into 2D coordinates using isometric projection?


Programming Language: C

I'm currently in the process of implementing a 3D wireframe model represented through isometric projection.

My current understanding of the project is to:

  1. parse a text map containing the x,y,z coordinates of the wireframe model
  2. Transforming the 3D coordinates to 2D using isometric projection
  3. Drawing the line using the Bresenham Line Algo and a few functions out of my graphic library of choice.

I'm done with Step 1 however I've been stuck on Step 2 for the last few days.

I understand that isometric projection is the process of projecting a 2D plane in a angle that it looks like it's 3D even though we are only working with x,y when drawing the lines. That is def. not the best way of describing it and if I'm incorrect please correct me.

Example of a text map:

0 0 0

0 5 0

0 0 0

My data structure of choice (implemented as array of structs)

typedef struct point
{
    float       x;
    float       y;
    float       z;
    bool        is_last;
    int     color; // Implemented after mandatory part
} t_point;

I pretty much just read out the rows, column and values of the text map and store them in x,y,z values respectively.

Now that I have to transform them I've tried the following formulas:

    const double angle = 30 * M_PI / 180.0;

void    isometric(t_dot *dot, double angle)
{
    dot->x = (dot->x - dot->y) * cos(angle);
    dot->y = (dot->x + dot->y) * sin(angle) - dot->z;
}
static void iso(int x, int y, int z)
{
    int previous_x;
    int previous_y;

    previous_x = x;
    previous_y = y;
    x = (previous_x - previous_y) * cos(0.523599);
    y = -z + (previous_x + previous_y) * sin(0.523599);
}
t_point *calc_isometric(t_point *pts, int max_pts)
{
    float   x;
    float   y;
    float   z;
    const double angle = 30 * M_PI / 180.0;
    int num_pts;

    num_pts = 0;
    while (num_pts < max_pts)
    {
        x = pts[num_pts].x;
        y = pts[num_pts].y;
        z = pts[num_pts].z;
        printf("x: %f y: %f z: %f\n", x, y, z);
        pts[num_pts].x = (x - y) * cos(angle);
        pts[num_pts].y = (x + y) * sin(angle) - z;
        printf("x_iso %f\ty_iso %f\n\n", pts[num_pts].x, pts[num_pts].y);
        num_pts++;
    }
    return (pts);
}

It spits out various things which makes no sense to me. I could just go one and try to implement the Line Algo. from here and hope for the best but I would like to understand what I'm actually doing here. Next to that I learned through me research that I need to set up my camera in a certain way to create the projection.

All in all I'm just very lost and my question boils down to this.

  1. Please help me understand the concept of isometric projection.
  2. How to transform 3D coordinates (x,y,z) into coordinates using isometric projection.

Solution

  • I see it like this:

    isometric

    // constants:
    float deg = M_PI/180.0;
    float ax = 30*deg;
    float ay =150*deg;
    vec2 X = vec2(cos(ax),-sin(ax)); // x axis
    vec2 Y = vec2(cos(ay),-sin(ay)); // y axis
    vec2 Z = vec2(    0.0,-    1.0); // z axis
    vec2 O = vec2(0,0);              // position of point (0,0,0) on screen
    // conversion:
    vec3 p=vec3(?,?,?); // input point
    vec2 q=O+(p.x*X)+(p.y*Y)+(p.z*Y); // output point
    

    the coordinatewise version:

    float Xx =  cos(ax);
    float Xy = -sin(ax);
    float Yx =  cos(ay);
    float Yy = -sin(ay);
    float Zx =      0.0;
    float Zy = -    1.0;
    float Ox =        0;
    float Oy =        0;
    // conversion:
    float px=?,py=?,pz=?; // input point
    float qx=Ox+(px*Xx)+(py*Yx)+(pz*Yx); // output point
    float qy=Oy+(px*Xy)+(py*Yy)+(pz*Yy); // output point
    

    Asuming x axis going to right and y axis going down ... the O is usually set to center of screen instead of (0,0) unless you add pan capabilities of your isometric world.

    In case you want to add arbitrary rotations within the "3D" XY plane see this:

    So you just compute the X,Y vectors on the ellipse (beware they will not be unit anymore!!!) So if I see it right it would be:

    float ax=?,ay=ax+90*deg;
    float Xx =  cos(ax)    ;
    float Xy = -sin(ax)*0.5;
    float Yx =  cos(ay)    ;
    float Yy = -sin(ay)*0.5;
    

    where ax is the rotation angle...