Search code examples
c++openglglfwglm-mathopengl-compat

Creating a camera to rotate a cube not working


I have created a program that creates a coloured cube, I tried to move around the cube in the keyCallback function. This didn't work ow i intended it to work and instead moved the cube. I tried to create a camera and this is my full program:

#include <stdio.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm.hpp>
#include <gtc\matrix_transform.hpp>
#include <GL/freeglut.h>
#include <GL\GL.h>

void DrawCube(GLfloat centerPosX, GLfloat centerPosY, GLfloat centerPosZ, GLfloat edgeLength);
void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
void framebuffer_size_callback(GLFWwindow* wndow, int width, int height);

GLfloat rotateX = 0.0f;
GLfloat rotateY = 0.0f;

GLfloat xPos = 0.0f;
GLfloat yPos = 0.0f;
GLfloat zPos = 0.0f;

int main(void) {
    GLFWwindow* window;

    //Init library
    if (!glfwInit())
        return -1;
    //create a window
    glEnable(GL_DEPTH_TEST);
    window = glfwCreateWindow(840, 420, "electroCaft", NULL, NULL);
    int screenWidth, screenHeight;
    glfwSetKeyCallback(window, keyCallback);
    //get resolution
    glfwGetFramebufferSize(window, &screenWidth, &screenHeight);
    if (!window) {
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);
    glViewport(0.0f, 0.0f, screenWidth, screenHeight);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, screenWidth, 0, screenHeight, 0, 1000); // essentially setting coodinates last num sets view point of distance
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glEnable(GL_DEPTH_TEST);
    glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f);
    glm::vec3 cameraTarget = glm::vec3(0.0f, 0.0f, 0.0f);
    glm::vec3 cameraDirection = glm::normalize(cameraPos - cameraTarget);
    glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f);
    glm::vec3 cameraRight = glm::normalize(glm::cross(up, cameraDirection));
    glm::vec3 cameraUp = glm::cross(cameraDirection, cameraRight);
    glm::mat4 view;
    view = glm::lookAt(glm::vec3(0.0f, 0.0f, 3.0f),
        glm::vec3(0.0f, 0.0f, 0.0f),
        glm::vec3(0.0f, 1.0f, 0.0f));
    float radius = 10.0f;
    float camX = sin(glfwGetTime()) * radius;
    float camZ = cos(glfwGetTime()) * radius;
    //glm::mat4 view;
    view = glm::lookAt(glm::vec3(camX, 0.0, camZ), glm::vec3(0.0, 0.0, 0.0), glm::vec3(0.0, 1.0, 0.0));


    GLfloat halfScreenWidth = screenWidth / 2;
    GLfloat halfScreenHeight = screenHeight / 2;

    GLfloat rotationSpeed = 1.0f;

    //load textures

    //loop until user closes window
    while (!glfwWindowShouldClose(window)) {
        glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

        //render graphics
        //glClear(GL_COLOR_BUFFER_BIT);
        glClearColor(62.0f / 255.0f, 85.9f / 255.0f, 255.0 / 255.0, 0.0);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        //drawing here
        //printf("screen width is: %d \n", screenWidth);

        view = glm::lookAt(glm::vec3(camX, 0.0, camZ), glm::vec3(100, 100, 100), glm::vec3(0.0, 1.0, 0.0));

        glPushMatrix();
        glTranslatef((GLfloat)screenWidth / 2.0f, (GLfloat)screenHeight / 2.0f, -500.0f);
        glRotatef(rotateX, 1, 0, 0);
        glRotatef(rotateY, 0, 1, 0);
        //rotateX += 1;
        //rotateY -= 1;

        //DrawCube(halfScreenWidth, halfScreenHeight, -500, 250); //x,y,w,h z is calculated in cube func
        DrawCube(xPos, yPos, zPos, 250);
        //DrawCube(xPos - 50, yPos, zPos, 50);
        //DrawCube(xPos + 50, yPos, zPos, 50);
        //DrawCube(halfScreenWidth, halfScreenHeight - 100, -500, 250);
        glPopMatrix();



        glfwSwapBuffers(window);
        glfwPollEvents();
    }
    glfwTerminate();
    return 0;

}


void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
    const GLfloat rotationSpeed = 10;


    if (action == GLFW_PRESS || action == GLFW_REPEAT)
    {
        switch (key)
        {
        case GLFW_KEY_W:
            zPos += rotationSpeed;
            break;
        case GLFW_KEY_S:
            zPos -= rotationSpeed;
            break;
        case GLFW_KEY_D:
            xPos += rotationSpeed;
            break;
        case GLFW_KEY_A:
            xPos -= rotationSpeed;
            break;
        case GLFW_KEY_SPACE:
            yPos -= rotationSpeed;
            break;

        //rotate the cube
        case GLFW_KEY_UP:
            rotateX -= rotationSpeed;
            break;
        case GLFW_KEY_DOWN:
            rotateX += rotationSpeed;
            break;
        case GLFW_KEY_RIGHT:
            rotateY += rotationSpeed;
            break;
        case GLFW_KEY_LEFT:
            rotateY -= rotationSpeed;
            break;
        }


    }
}

void framebuffer_size_callback(GLFWwindow* wndow, int width, int height)
{
    glViewport(0, 0, width, height);
    //glViewport(xPos, yPos, zPos, width);
}



void DrawCube(GLfloat centerPosX, GLfloat centerPosY, GLfloat centerPosZ, GLfloat edgeLength) {
    GLfloat halfSideLength = edgeLength * 0.5;
    GLfloat vertices[] = {
        // front face
        centerPosX - halfSideLength, centerPosY + halfSideLength, centerPosZ + halfSideLength, //top left
        centerPosX + halfSideLength, centerPosY + halfSideLength, centerPosZ + halfSideLength, //top right
        centerPosX + halfSideLength, centerPosY - halfSideLength, centerPosZ + halfSideLength, //bottom right
        centerPosX - halfSideLength, centerPosY - halfSideLength, centerPosZ + halfSideLength, // bottom left

        // back face
        centerPosX - halfSideLength, centerPosY + halfSideLength, centerPosZ - halfSideLength, //top left
        centerPosX + halfSideLength, centerPosY + halfSideLength, centerPosZ - halfSideLength, //top right
        centerPosX + halfSideLength, centerPosY - halfSideLength, centerPosZ - halfSideLength, //bottom right
        centerPosX - halfSideLength, centerPosY - halfSideLength, centerPosZ - halfSideLength, // bottom left

        // left face
        centerPosX - halfSideLength, centerPosY + halfSideLength, centerPosZ + halfSideLength, //top left
        centerPosX - halfSideLength, centerPosY + halfSideLength, centerPosZ - halfSideLength, //top right
        centerPosX - halfSideLength, centerPosY - halfSideLength, centerPosZ - halfSideLength, //bottom right
        centerPosX - halfSideLength, centerPosY - halfSideLength, centerPosZ + halfSideLength, // bottom left

        // right face
        centerPosX + halfSideLength, centerPosY + halfSideLength, centerPosZ + halfSideLength, //top left
        centerPosX + halfSideLength, centerPosY + halfSideLength, centerPosZ - halfSideLength, //top right
        centerPosX + halfSideLength, centerPosY - halfSideLength, centerPosZ - halfSideLength, //bottom right
        centerPosX + halfSideLength, centerPosY - halfSideLength, centerPosZ + halfSideLength, // bottom left

        // top face
        centerPosX - halfSideLength, centerPosY + halfSideLength, centerPosZ + halfSideLength, //top left
        centerPosX - halfSideLength, centerPosY + halfSideLength, centerPosZ - halfSideLength, //top right
        centerPosX + halfSideLength, centerPosY + halfSideLength, centerPosZ - halfSideLength, //bottom right
        centerPosX + halfSideLength, centerPosY + halfSideLength, centerPosZ + halfSideLength, // bottom left

        // bottom face
        centerPosX - halfSideLength, centerPosY - halfSideLength, centerPosZ + halfSideLength, //top left
        centerPosX - halfSideLength, centerPosY - halfSideLength, centerPosZ - halfSideLength, //top right
        centerPosX + halfSideLength, centerPosY - halfSideLength, centerPosZ - halfSideLength, //bottom right
        centerPosX + halfSideLength, centerPosY - halfSideLength, centerPosZ + halfSideLength // bottom left
    };

    //glRotated(edgeLength, 0, 0, 1);
    //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);
    glVertexPointer( 3, GL_FLOAT, 0, vertices);
    glColorPointer(3, GL_FLOAT, 0, vertices);
    glDrawArrays(GL_QUADS, 0, 24);
    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_COLOR_ARRAY);
}

I am not sure if any of the glm code that is for the camera is meant to be part of the loop or not. I have the view being defined in the loop, I believe that this is correct but I'm not sure if I need to use the camera position somehow as part of the position for the cube.


Solution

  • You've to load the view matrix (view) to the current matrix in the main loop by glLoadMatrix.
    Note, glm::lookAt just calculates the matrix and returns the matrix form the function, but it doesn't magically set any OpenGL matrix. SO the matrix which is returned from the function has to be set to the current modelview matrix:

    glm::mat4 view = glm::lookAt(eye, center, up);
    glLoadMatrixf( glm::value_ptr(view) );
    

    If you want to stay the cube in the center of the view, then I recommend to setup a projection matrix, which projects symmetrically to the x and y axis. e.g.:

    glOrtho(-screenWidth/2, screenWidth/2, -screenHeight/2, screenHeight/2, -1000, 1000); 
    

    Note, a displaced projection would cause that the view rectangle is displaced and the cube seem so be centered (or rotate around) the bottom left of the viewport.

    See the example, to rotate the view (eye position) around the cube:

    #include <glm/gtc/type_ptr.hpp> // glm::value_ptr
    
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-screenWidth/2, screenWidth/2, -screenHeight/2, screenHeight/2, -1000, 1000); 
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    
    while (!glfwWindowShouldClose(window)) {
    
        // [...]
    
        float time = glfwGetTime();
        float radius = 500.0f;
        float camX = sin(time) * radius;
        float camZ = cos(time) * radius;
    
        glm::vec3 center = glm::vec3(0.0f, 0.0f, 0.0f);
        glm::vec3 eye    = center + glm::vec3(camX, camZ, 0.0f);
        glm::vec3 up     = glm::vec3(0.0, 0.0, 1.0);
        glm::mat4 view   = glm::lookAt(eye, center, up);
        glLoadMatrixf( glm::value_ptr(view) );
    
        glPushMatrix();
        glTranslatef(xPos, yPos, zPos);
        glRotatef(rotateX, 1, 0, 0);
        glRotatef(rotateY, 0, 1, 0);
        DrawCube(0.0f, 0.0f, 0.0f, 250.0f);
        glPopMatrix();
    
        // [...]
    }