Tutorial OpenGL - Cámara

En este tutorial OpenGL moderno aprenderemos a crear una cámara móvil, que nos permitirá navegar libremente por una escena 3D, anteriormente para visualizar una escena usamos una cámara estática que nos permitía ver el objeto desde un único punto de vista, esta nueva cámara cambiara su posición al presionar determinadas teclas y cambiara su dirección de visión con el ratón.

Anteriormente usamos la función glm::lookAt(eye, center, up) para definir la posición, lugar a donde apunta la cámara y su vector vertical, lo primero que haremos será cambiar la posición de la cámara mediante las teclas WASD, la cámara, de momento, siempre mira hacia adelante.

Para captar los eventos del teclado sobrescribimos el método void onkey(int key, int scancode, int action, int mods) este nos permite obtener la tecla presionada y otro tipo de información relacionada, veamos un ejemplo de cómo captar la presión de la tecla ESC para indicarle a la aplicación que debe terminar su ejecución.

void onkey(int key, int scancode, int action, int mods) override {
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
        glfwSetWindowShouldClose(window, GL_TRUE);
}

En cuanto a la cámara se refiere necesitamos 3 vectores, el vector posición (cameraPos), el vector dirección (cameraPos + cameraFont) y el vector vertical (cameraUp).

glm::vec3 cameraPos   = glm::vec3(0.0f, 0.5f, 3.0f);
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
glm::vec3 cameraUp    = glm::vec3(0.0f, 1.0f, 0.0f);

glm::mat4 View = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);

Para cambiar la posición de la cámara captamos la presión de las correspondientes teclas y establecemos los nuevos valores.

GLfloat cameraSpeed = 0.05f;

if (key == GLFW_KEY_W)
    cameraPos += cameraSpeed * cameraFront;
if (key == GLFW_KEY_S)
    cameraPos -= cameraSpeed * cameraFront;
if (key == GLFW_KEY_A)
    cameraPos -= glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
if (key == GLFW_KEY_D)
    cameraPos += glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;

En este punto podemos movernos en el espacio 3D usando las teclas WASD, usaremos la variable cameraSpeed para controlar la velocidad de desplazamiento.

Para darle más funcionalidad de nuestra cámara vamos permitir la rotación, para ello utilizaremos los ángulos Euler (yaw, pitch, roll), la función glm::yawPitchRoll(yaw, pitch, roll) nos facilita el cálculo de la matriz de rotación en estos 3 ejes, los ejes de rotación correspondientes se muestran en la imagen, en lugar del avión imaginemos nuestra cámara.

angulo euler
La rotación en el eje roll no será implementada.

glm::mat4 R = glm::yawPitchRoll(yaw, pitch, 0.0f);

cameraFront = glm::vec3(R * glm::vec4(0, 0, -1, 0));
cameraUp = glm::vec3(R * glm::vec4(0, 1, 0, 0));

glm::mat4 View = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);

Vemos el cálculo de la matriz de vista en la nueva posición y con las rotaciones asignadas.

Necesitamos también controlar la rotación, usaremos las teclas QZER para ello, ejecutemos la aplicación y probemos, veremos que al girar la cámara esta se mueve en la dirección en que esta mirando.

if (key == GLFW_KEY_E)
    yaw += cameraSpeed / 2.0f;
if (key == GLFW_KEY_R)
    yaw -= cameraSpeed / 2.0f;

if (key == GLFW_KEY_Q)
    pitch += cameraSpeed / 2.0f;
if (key == GLFW_KEY_Z)
    pitch -= cameraSpeed / 2.0f;

Utilizaremos el ratón para cambiar los ángulos de rotación, lo que nos permitirá establecer con el ratón la dirección en que mira la cámara, sobrescribimos el método onmouse(double xpos, double ypos) aquí podemos obtener la posición del cursor, almacenamos la posición anterior y calculamos el desplazamiento, un movimiento vertical afecta el ángulo pitch y un movimiento horizontal afecta el ángulo yaw.

void onmouse(double xpos, double ypos) override {
    int width, height;
    glfwGetWindowSize(window, &width, &height);
    glfwSetCursorPos(window, width / 2.0, height / 2.0);

    GLfloat xoffset = ((width / 2.0) - xpos) * mouseSensitive;
    GLfloat yoffset = ((height / 2.0) - ypos) * mouseSensitive;

    yaw += xoffset;
    pitch += yoffset;
}

Para finalizar, solucionaremos un problema que tiene nuestra cámara, no podemos combinar los movimientos de la cámara, por ejemplo al presionar las teclas WD conjuntamente esperaríamos un desplazamiento en diagonal, pero es no ocurre porque de momento se capta la presión de una tecla a la vez, veamos como solucionarlo.

void chechKeys() {
    if (isKeyPress(GLFW_KEY_W))
        cameraPos += cameraSpeed * cameraFront;
    if (isKeyPress(GLFW_KEY_S))
        cameraPos -= cameraSpeed * cameraFront;
    if (isKeyPress(GLFW_KEY_A))
        cameraPos -= glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
    if (isKeyPress(GLFW_KEY_D))
        cameraPos += glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
}

inline bool isKeyPress(int key) {
    return (glfwGetKey(window, key) == GLFW_PRESS);
}

Utilizaremos el método glfwGetKey(int key) para determinar si una determinada tecla a sido presionada.

GitHub: Tutorial OpenGL Cámara

Comentarios

Temas relacionados

Entradas populares de este blog

tkinter Grid

Conectar SQL Server con Java

Controles y Contenedores JavaFX 8 - I

Histogramas OpenCV Python