Search code examples
c++opengl3dgtkglm-math

Using GLM with GTK to make simple 3D drawing


I am jus trying to draw a 3D Cartesian axis to see if I can get 3D to work. I am using GTK with Cairo to do the drawing. Here is my code...

glm::vec3 camera_pos(0, 0, -10);
glm::vec3 camera_target(0, 0, 0);
glm::vec3 up(0, 1, 0);

gboolean draw_callback(GtkWidget* widget, cairo_t* cr, gpointer data)
{
    guint width, height;

    width = gtk_widget_get_allocated_width(widget);
    height = gtk_widget_get_allocated_height(widget);

    glm::mat4 model = glm::translate(glm::vec3(width / 2.0f, height / 2.0f, 0.0f)) *
            glm::scale(glm::vec3(100.0f, 100.0f, 100.0f));
    glm::mat4 camera = glm::lookAt(camera_pos, camera_target, up);
    glm::mat4 perspective = glm::perspective(45.0f, (float)width / (float)height, 0.1f, 100.0f);

    glm::mat4 transform = perspective * camera * model;

    glm::vec4 xaxis = transform * glm::vec4(1, 0, 0, 1);
    glm::vec4 yaxis = transform * glm::vec4(0, 1, 0, 1);
    glm::vec4 zaxis = transform * glm::vec4(0, 0, 1, 1);
    glm::vec4 orig = transform * glm::vec4(0, 0, 0, 1);

    cout << orig.x << " " << orig.y << endl;

    cairo_set_source_rgb(cr, 1.0, 0, 0);
    cairo_move_to(cr, orig.x, -orig.y);
    cairo_line_to(cr, xaxis.x, -xaxis.y);
    cairo_stroke(cr);

    cairo_set_source_rgb(cr, 0, 1.0, 0);
    cairo_move_to(cr, orig.x, -orig.y);
    cairo_line_to(cr, yaxis.x, -yaxis.y);
    cairo_stroke(cr);

    cairo_set_source_rgb(cr, 0, 0, 1.0);
    cairo_move_to(cr, orig.x, -orig.y);
    cairo_line_to(cr, zaxis.x, -zaxis.y);
    cairo_stroke(cr);

    return FALSE;
}

Can someone check the math here because I am getting a lot of negative coordinates. Nothing appears on my screen when I run this.

Edit:

I just modified my camera vectors like this.

gboolean draw_callback(GtkWidget* widget, cairo_t* cr, gpointer data)
{
    guint width, height;

    width = gtk_widget_get_allocated_width(widget);
    height = gtk_widget_get_allocated_height(widget);

    glm::vec3 camera_pos(0, 0, 1000);
    glm::vec3 camera_target(width / 2.0f, height / 2.0f, 0);
    glm::vec3 up(0, 1, 0);

    glm::mat4 model = glm::translate(glm::vec3(width / 2.0f, height / 2.0f, 0.0f));// *
            //glm::scale(glm::vec3(100.0f, 100.0f, 100.0f));
    glm::mat4 camera = glm::lookAt(camera_pos, camera_target, up);
    glm::mat4 perspective = glm::perspective(45.0f, (float)width / (float)height, 0.1f, 100.0f);

    glm::mat4 transform = perspective * camera * model;

    glm::vec4 xaxis = transform * glm::vec4(100, 0, 0, 1);
    glm::vec4 yaxis = transform * glm::vec4(0, 100, 0, 1);
    glm::vec4 zaxis = transform * glm::vec4(0, 0, 100, 1);
    glm::vec4 orig = transform * glm::vec4(0, 0, 0, 1);

    cout << xaxis.x << " " << xaxis.y << endl;

    cairo_set_source_rgb(cr, 1.0, 0, 0);
    cairo_move_to(cr, orig.x, -orig.y);
    cairo_line_to(cr, xaxis.x, -xaxis.y);
    cairo_stroke(cr);

    cairo_set_source_rgb(cr, 0, 1.0, 0);
    cairo_move_to(cr, orig.x, -orig.y);
    cairo_line_to(cr, yaxis.x, -yaxis.y);
    cairo_stroke(cr);

    cairo_set_source_rgb(cr, 0, 0, 1.0);
    cairo_move_to(cr, orig.x, -orig.y);
    cairo_line_to(cr, zaxis.x, -zaxis.y);
    cairo_stroke(cr);

    return FALSE;
}

Now I can see a blue line from the corner of my screen but it is still wrong.


Solution

  • You are using a perspective projection, but you do not carry out the persepctive divide, which will totally screw up your results. glm::perspective will create a matrix which maps the viewing frustum with the given angle and apsect ratio along the negative z axis to a [-w,w]^3 "cube" in clip space. After the perspective divide by the w coordinate, the viewing frustum will be [-1,1]^3 in normalized device coords. Usually at this stage, the coordinates are further converted into window space, where the actual pixels come into play.

    In your case, you seem to try to incorporate the window resolution in the model transform at the start of the transform chain, which is totally weird if you later apply a standard GL projection matrix.