opengl - 如何让 OpenGL 相机指向下方?

标签 opengl glm-math

我正在尝试将两个程序集成在一起。

  • 有一个行星系统(带有移动的立方体)
  • 另一个有移动摄像机的代码。它还可以平移

我已经设法将它们放在一起。行星系统的 View 可以切换显示

  • 透视 View (按下“1”时)
  • 俯 View (按下“2”时)

我的俯 View 有问题(当按下 2 时)。它并不是指向行星系统。它位于行星的正上方,但并不向下看。我想将相机朝下,这样看起来像这样 Top-view of planet system 我一直未能成功地使用这部分代码(如下)来让相机向下看。更具体地说,是 g_camera.setViewMatrix 函数中的坐标。

// render from top view
    else if (key == GLFW_KEY_2 && action == GLFW_PRESS) {
        cout << "Top-View" << endl << endl;
        // set camera's view matrix
        g_camera.setViewMatrix(glm::vec3(0, 15, 0), glm::vec3(0, 0, 0), glm::vec3(1, 0, 0)); 
        //g_viewMatrix = glm::lookAt(glm::vec3(0, 15, 0), glm::vec3(0, 0, 0), glm::vec3(1, 0, 0));
        render_scene();
    }

在集成相机代码之前,我使用了这个look at函数。

g_viewMatrix = glm::lookAt(glm::vec3(0, 15, 0), glm::vec3(0, 0, 0), glm::vec3(1, 0, 0));

但是,当我将这些相同的向量插入 g_camera.setViewMatrix 函数时,它并没有指向同一方向。

我遇到的另一个问题:

红色椭圆实际上是一个圆形。如何让它显示为圆形而不是椭圆形?我集成了另一个程序中的圆圈代码。在那个节目中,这是一个完美的循环。

这是我的代码

#include <cstdio>       // for C++ i/o
#include <iostream>
#include <string>
#include <cstddef>
using namespace std;    // to avoid having to use std::

#define GLEW_STATIC     // include GLEW as a static library
#include <GLEW/glew.h>  // include GLEW
#include <GLFW/glfw3.h> // include GLFW (which includes the OpenGL header)
#include <glm/glm.hpp>  // include GLM (ideally should only use the GLM headers that are actually used)
#include <glm/gtx/transform.hpp>
using namespace glm;    // to avoid having to use glm::

#include "shader.h"
#include "camera.h"

#define PI 3.14159265
#define MAX_SLICES 50
#define MIN_SLICES 8
#define MAX_VERTICES (MAX_SLICES+2)*3   // a triangle fan should have a minimum of 3 vertices
#define CIRCLE_RADIUS 3.0
#define WINDOW_WIDTH 1500
#define WINDOW_HEIGHT 800

// struct for vertex attributes
struct Vertex
{
    GLfloat position[3];
    GLfloat color[3];
};

// global variables

GLfloat g_vertices_circle[MAX_VERTICES] = {
    0.0f, 0.0f, 0.0f,       // try adjusting this value to get rid of red line
    0.0f, 0.0f, 0.0f
};

GLfloat g_colors_circle[MAX_VERTICES] = {
    1.0f, 0.0f, 0.0f,
    1.0f, 0.0f, 0.0f
};

GLuint g_slices = MAX_SLICES;   // number of circle slices

Vertex g_vertices[] = {
    // vertex 1
    -0.5f, 0.5f, 0.5f,  // position
    1.0f, 0.0f, 1.0f,   // colour
    // vertex 2
    -0.5f, -0.5f, 0.5f, // position
    1.0f, 0.0f, 0.0f,   // colour
    // vertex 3
    0.5f, 0.5f, 0.5f,   // position
    1.0f, 1.0f, 1.0f,   // colour
    // vertex 4
    0.5f, -0.5f, 0.5f,  // position
    1.0f, 1.0f, 0.0f,   // colour
    // vertex 5
    -0.5f, 0.5f, -0.5f, // position
    0.0f, 0.0f, 1.0f,   // colour
    // vertex 6
    -0.5f, -0.5f, -0.5f,// position
    0.0f, 0.0f, 0.0f,   // colour
    // vertex 7
    0.5f, 0.5f, -0.5f,  // position
    0.0f, 1.0f, 1.0f,   // colour
    // vertex 8
    0.5f, -0.5f, -0.5f, // position
    0.0f, 1.0f, 0.0f,   // colour
};

GLuint g_indices[] = {
    0, 1, 2,    // triangle 1
    2, 1, 3,    // triangle 2
    4, 5, 0,    // triangle 3
    0, 5, 1,    // ...
    2, 3, 6,
    6, 3, 7,
    4, 0, 6,
    6, 0, 2,
    1, 5, 3,
    3, 5, 7,
    5, 4, 7,
    7, 4, 6,    // triangle 12
};

GLuint g_IBO = 0;               // index buffer object identifier
GLuint g_VBO[3];                // vertex buffer object identifier
GLuint g_VAO[2];                // vertex array object identifier
GLuint g_shaderProgramID = 0;   // shader program identifier
GLuint g_MVP_Index = 0;         // location in shader
glm::mat4 g_modelMatrix[5];     // planets object model matrices
glm::mat4 g_modelMatrixCircle[5];// circle model matrices
glm::mat4 g_modelMatrixSubPlanets[5];// object matrices for sub-planets (moon, disc etc)
glm::mat4 g_viewMatrix;         // view matrix
glm::mat4 g_projectionMatrix;   // projection matrix

Camera g_camera;            // camera 

float g_orbitSpeed[5] = { 0.3f, 1.0f, 0.7f, 0.9f, 1.2f };       // for speed of rotation around sun
float g_rotationSpeed[5] = { 0.07f, 0.7f, 3.0f, 5.0f, 1.0f };   // for speed of rotation on own axis
float g_scaleSize[5] = { 0.5f, 0.5f, 0.5f, 0.5f, 0.5f };        // for scaling the orbiting planets
float g_axisOfRotation[5] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, };  // for offsetting the axis of rotation

void generate_circle()
{
    float angle = PI * 2 / static_cast<float>(g_slices);    // used to generate x and y coordinates
    float scale_factor = static_cast<float>(WINDOW_HEIGHT) / WINDOW_WIDTH;  // scale to make it a circle instead of an elipse
    int index = 0;  // vertex index

    g_vertices_circle[3] = CIRCLE_RADIUS * scale_factor;    // set x coordinate of vertex 1

                                                            // generate vertex coordinates for triangle fan
    for (int i = 2; i < g_slices + 2; i++)
    {
        // multiply by 3 because a vertex has x, y, z coordinates
        index = i * 3;

        g_vertices_circle[index] = CIRCLE_RADIUS * cos(angle) * scale_factor;
        g_vertices_circle[index + 1] = CIRCLE_RADIUS * sin(angle);
        g_vertices_circle[index + 2] = 0.0f;

        //Color for edges. See stackoverflow
        g_colors_circle[index] = 1.0f;
        g_colors_circle[index + 1] = 0.0f;
        g_colors_circle[index + 2] = 0.0f;

        // update to next angle
        angle += PI * 2 / static_cast<float>(g_slices);
    }

    // Gets rid of line from middle of circle
    g_vertices_circle[0] = g_vertices_circle[3];
    g_vertices_circle[1] = g_vertices_circle[4];
    g_vertices_circle[2] = g_vertices_circle[5];
}   

static void init(GLFWwindow* window)
{
    glClearColor(0.0, 0.0, 0.0, 1.0);   // set clear background colour

    glEnable(GL_DEPTH_TEST);    // enable depth buffer test

    // create and compile our GLSL program from the shader files
    g_shaderProgramID = loadShaders("MVP_VS.vert", "ColorFS.frag");

    // find the location of shader variables
    GLuint positionIndex = glGetAttribLocation(g_shaderProgramID, "aPosition");
    GLuint colorIndex = glGetAttribLocation(g_shaderProgramID, "aColor");
    g_MVP_Index = glGetUniformLocation(g_shaderProgramID, "uModelViewProjectionMatrix");

    // initialise model matrix to the identity matrix
    g_modelMatrix[0] = g_modelMatrix[1] = g_modelMatrix[2] = g_modelMatrix[3] = g_modelMatrix[4] = glm::mat4(1.0f);
    g_modelMatrixCircle[0] = g_modelMatrixCircle[1] = glm::mat4(1.0f);
    g_modelMatrixSubPlanets[3] = glm::mat4(1.0f);;

    // initialise view matrix
    //g_viewMatrix = glm::lookAt(glm::vec3(10, 3, 8), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));  //perspective

    // set camera's view matrix
    //g_camera.setViewMatrix(glm::vec3(10, 3, 8), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
    g_camera.setViewMatrix(glm::vec3(0, 3, 14), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));

    int width, height;
    glfwGetFramebufferSize(window, &width, &height);
    float aspectRatio = static_cast<float>(width) / height;

    // set camera's projection matrix
    g_camera.setProjectionMatrix(glm::perspective(45.0f, aspectRatio, 0.1f, 100.0f));

    // initialise projection matrix
    g_projectionMatrix = glm::perspective(45.0f, aspectRatio, 0.1f, 100.0f);

    // generate identifier for VBO and copy data to GPU
    glGenBuffers(1, &g_VBO[0]);
    glBindBuffer(GL_ARRAY_BUFFER, g_VBO[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertices), g_vertices, GL_STATIC_DRAW);

    // generate identifier for IBO and copy data to GPU
    glGenBuffers(1, &g_IBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_IBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(g_indices), g_indices, GL_STATIC_DRAW);

    // generate identifiers for VAO
    glGenVertexArrays(1, &g_VAO[0]);

    // create VAO and specify VBO data
    glBindVertexArray(g_VAO[0]);
    glBindBuffer(GL_ARRAY_BUFFER, g_VBO[0]);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_IBO);
    // interleaved attributes
    glVertexAttribPointer(positionIndex, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, position)));
    glVertexAttribPointer(colorIndex, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, color)));

    glEnableVertexAttribArray(positionIndex);   // enable vertex attributes
    glEnableVertexAttribArray(colorIndex);

    /*------------------------Circle----------------------*/

    // generate vertices of triangle fan
    generate_circle();

    // create VBO and buffer the data
    glGenBuffers(1, &g_VBO[1]);
    glBindBuffer(GL_ARRAY_BUFFER, g_VBO[1]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * (g_slices + 2), g_vertices_circle, GL_STATIC_DRAW);

    glGenBuffers(1, &g_VBO[2]);
    glBindBuffer(GL_ARRAY_BUFFER, g_VBO[2]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * (g_slices + 2), g_colors_circle, GL_STATIC_DRAW);

    // create VAO and specify VBO data
    glGenVertexArrays(1, &g_VAO[1]);
    glBindVertexArray(g_VAO[1]);
    glBindBuffer(GL_ARRAY_BUFFER, g_VBO[1]);
    glVertexAttribPointer(positionIndex, 3, GL_FLOAT, GL_FALSE, 0, 0);  // specify the form of the data
    glBindBuffer(GL_ARRAY_BUFFER, g_VBO[2]);
    glVertexAttribPointer(colorIndex, 3, GL_FLOAT, GL_FALSE, 0, 0); // specify the form of the data

    /*----------------------------------------------------*/

    glEnableVertexAttribArray(positionIndex);   // enable vertex attributes
    glEnableVertexAttribArray(colorIndex);
}

//Generates a random value between 0.1 and 0.9
double generateRandomFloat(float min, float max) 
{
    return min + static_cast <float> (rand()) / (static_cast <float> (RAND_MAX / (max - min)));
}

// function used to update the scene
static void update_scene()
{
    // static variables for rotation angles
    static float orbitAngle[5] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, };
    static float rotationAngle[5] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
    float scaleFactor = 0.05;

    orbitAngle[0] += g_orbitSpeed[0] * scaleFactor;
    orbitAngle[1] += g_orbitSpeed[1] * scaleFactor;
    orbitAngle[2] += g_orbitSpeed[2] * scaleFactor;
    orbitAngle[3] += g_orbitSpeed[3] * scaleFactor;
    orbitAngle[4] += g_orbitSpeed[4] * scaleFactor;

    // update rotation angles
    rotationAngle[0] += g_rotationSpeed[0] * scaleFactor;
    rotationAngle[1] += g_rotationSpeed[1] * scaleFactor;
    rotationAngle[2] += g_rotationSpeed[2] * scaleFactor;
    rotationAngle[3] += g_rotationSpeed[3] * scaleFactor;
    rotationAngle[4] += g_rotationSpeed[4] * scaleFactor;

    // update model matrix (planets)
    g_modelMatrix[0] = glm::rotate(rotationAngle[0], glm::vec3(0.0f, 1.0f, 0.0f));

    g_modelMatrix[1] = glm::translate(glm::vec3(g_axisOfRotation[1], 0.0f, 0.0f))   //moves the axis of rotation along x-axis
        * glm::rotate(orbitAngle[1], glm::vec3(0.0f, 1.0f, 0.0f))
        * glm::translate(glm::vec3(2.0f, 0.0f, 0.0f))
        * glm::rotate(rotationAngle[1], glm::vec3(0.0f, -1.0f, 0.0f))       //enables rotation on own axis. try comment
        * glm::rotate(glm::radians(45.0f), glm::vec3(1.0f, 0.0f, 0.0f))     //rotates into a diamond shape
        * glm::rotate(glm::radians(45.0f), glm::vec3(0.0f, 0.0f, 1.0f))     //rotates into a diamond shape
        * glm::scale(glm::vec3(g_scaleSize[1], g_scaleSize[1], g_scaleSize[1]));

    g_modelMatrix[2] = glm::translate(glm::vec3(g_axisOfRotation[2], 0.0f, 0.0f))
        * glm::rotate(orbitAngle[2], glm::vec3(0.0f, -1.0f, 0.0f))
        * glm::translate(glm::vec3(4.0f, 0.0f, 0.0f))
        * glm::rotate(rotationAngle[2], glm::vec3(0.0f, 1.0f, 0.0f))
        * glm::scale(glm::vec3(g_scaleSize[2], g_scaleSize[2], g_scaleSize[2]));

    g_modelMatrix[3] = glm::translate(glm::vec3(g_axisOfRotation[3], 0.0f, 0.0f))
        * glm::rotate(orbitAngle[3], glm::vec3(0.0f, 1.0f, 0.0f))
        * glm::translate(glm::vec3(6.0f, 0.0f, 0.0f))
        * glm::rotate(rotationAngle[3], glm::vec3(0.0f, 1.0f, 0.0f))
        * glm::scale(glm::vec3(g_scaleSize[3], g_scaleSize[3], g_scaleSize[3]));

    g_modelMatrix[4] = glm::translate(glm::vec3(g_axisOfRotation[4], 0.0f, 0.0f))
        * glm::rotate(orbitAngle[4], glm::vec3(0.0f, -1.0f, 0.0f))  // -y changes orbit to clock-wise
        * glm::translate(glm::vec3(8.0f, 0.0f, 0.0f))
        * glm::rotate(rotationAngle[4], glm::vec3(0.0f, -1.0f, 0.0f))
        * glm::scale(glm::vec3(g_scaleSize[4], g_scaleSize[4], g_scaleSize[4]));

    // update model matrix (orbit paths ie.circles)
    g_modelMatrixCircle[1] = glm::rotate(glm::radians(90.0f), glm::vec3(1.0f, 0.0f, 0.0f));

    // update model matrix (mini planets eg. moon)
    g_modelMatrixSubPlanets[3] = glm::translate(glm::vec3(g_axisOfRotation[3], 0.0f, 0.0f))
        * glm::rotate(orbitAngle[3], glm::vec3(0.0f, 1.0f, 0.0f))   
        * glm::translate(glm::vec3(6.0f, 0.0f, 0.0f))
        * glm::rotate(rotationAngle[3], glm::vec3(0.0f, 1.0f, 0.0f))
        * glm::scale(glm::vec3(g_scaleSize[3], g_scaleSize[3], g_scaleSize[3]));
}

// function used to render the scene
static void render_scene()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear colour buffer and depth buffer

    glUseProgram(g_shaderProgramID);    // use the shaders associated with the shader program

    glm::mat4 MVP = glm::mat4(1.0f);    //ModelViewProjection matrix to be shared. Initialized to identity

//Circle 1
    //MVP = g_projectionMatrix * g_viewMatrix * g_modelMatrixCircle[1];
    MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_modelMatrixCircle[1];
    //MVP = g_camera.getViewMatrix() * g_modelMatrixCircle[1];
    glUniformMatrix4fv(g_MVP_Index, 1, GL_FALSE, &MVP[0][0]);
    glBindVertexArray(g_VAO[1]);            // make VAO active
    glDrawArrays(GL_LINE_LOOP, 0, g_slices + 2);    // display the vertices based on the primitive type

    glBindVertexArray(g_VAO[0]);        // make VAO active

// Object 1
    //MVP = g_projectionMatrix * g_viewMatrix * g_modelMatrix[0];
    MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_modelMatrix[0];
    // set uniform model transformation matrix
    glUniformMatrix4fv(g_MVP_Index, 1, GL_FALSE, &MVP[0][0]);

    glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);   // display the vertices based on their indices and primitive type

// Object 2
    //MVP = g_projectionMatrix * g_viewMatrix * g_modelMatrix[1];
    MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_modelMatrix[1];
    glUniformMatrix4fv(g_MVP_Index, 1, GL_FALSE, &MVP[0][0]);
    glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);   // display the vertices based on their indices and primitive type

// Object 3
    //MVP = g_projectionMatrix * g_viewMatrix * g_modelMatrix[2];
    MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_modelMatrix[2];
    glUniformMatrix4fv(g_MVP_Index, 1, GL_FALSE, &MVP[0][0]);
    glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);   // display the vertices based on their indices and primitive type

// Object 4
    //MVP = g_projectionMatrix * g_viewMatrix * g_modelMatrix[3];
    MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_modelMatrix[3];
    glUniformMatrix4fv(g_MVP_Index, 1, GL_FALSE, &MVP[0][0]);
    glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);   // display the vertices based on their indices and primitive type

// Object 5
    //MVP = g_projectionMatrix * g_viewMatrix * g_modelMatrix[4];
    MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_modelMatrix[4];
    glUniformMatrix4fv(g_MVP_Index, 1, GL_FALSE, &MVP[0][0]);
    glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);   // display the vertices based on their indices and primitive type

// Moon for Object 3
    //MVP = g_projectionMatrix * g_viewMatrix * g_modelMatrixSubPlanets[3] * g_modelMatrix[4];
    MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_modelMatrixSubPlanets[3] * g_modelMatrix[4];
    glUniformMatrix4fv(g_MVP_Index, 1, GL_FALSE, &MVP[0][0]);
    glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);   // display the vertices based on their indices and primitive type

    glFlush();  // flush the pipeline
}

static void cursor_position_callback(GLFWwindow* window, double xpos, double ypos)
{
    // variables to store mouse cursor coordinates
    static double previous_xpos = xpos;
    static double previous_ypos = ypos;
    double delta_x = xpos - previous_xpos;
    double delta_y = ypos - previous_ypos;

    // pass mouse movement to camera class
    g_camera.updateYaw(delta_x);
    g_camera.updatePitch(delta_y);

    // update previous mouse coordinates
    previous_xpos = xpos;
    previous_ypos = ypos;
}

// key press or release callback function
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
    // quit if the ESCAPE key was press
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
    {
        // set flag to close the window
        glfwSetWindowShouldClose(window, GL_TRUE);
        return;
    }
    // render in perspective view
    else if (key == GLFW_KEY_1 && action == GLFW_PRESS) {
        cout << "Perspective-View" << endl << endl;
        // set camera's view matrix
        g_camera.setViewMatrix(glm::vec3(0, 3, 14), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
        //g_viewMatrix = glm::lookAt(glm::vec3(10, 3, 8), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
        render_scene();
    }
    // render from top view
    else if (key == GLFW_KEY_2 && action == GLFW_PRESS) {
        cout << "Top-View" << endl << endl;
        // set camera's view matrix
        g_camera.setViewMatrix(glm::vec3(0, 15, 0), glm::vec3(0, 0, 0), glm::vec3(1, 0, 0)); 
        //g_viewMatrix = glm::lookAt(glm::vec3(0, 15, 0), glm::vec3(0, 0, 0), glm::vec3(1, 0, 0));
        render_scene();
    }
    // render from eye-level view
    else if (key == GLFW_KEY_3 && action == GLFW_PRESS) {
        cout << "Eye-level View" << endl << endl;
        // set camera's view matrix
        g_camera.setViewMatrix(glm::vec3(0, 0, 10), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0)); 
        //g_viewMatrix = glm::lookAt(glm::vec3(0, 0, 10), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
        render_scene();
    }
    // Randomize size, orbit speed, axis rotation speed of planets
    else if (key == GLFW_KEY_R && action == GLFW_PRESS) {   

        // Randomize planet size
        g_scaleSize[1] = generateRandomFloat(0.1, 0.75);
        g_scaleSize[2] = generateRandomFloat(0.1, 0.75);
        g_scaleSize[3] = generateRandomFloat(0.1, 0.75);
        g_scaleSize[4] = generateRandomFloat(0.1, 0.75);

        // Randomize speed of rotation (on planets own axis)
        g_rotationSpeed[1] = generateRandomFloat(0.1, 10.0);
        g_rotationSpeed[2] = generateRandomFloat(0.1, 10.0);
        g_rotationSpeed[3] = generateRandomFloat(0.1, 10.0);
        g_rotationSpeed[4] = generateRandomFloat(0.1, 10.0);

        // Randomize speed of rotation around sun
        g_orbitSpeed[1] = generateRandomFloat(0.1, 1.2);
        g_orbitSpeed[2] = generateRandomFloat(0.1, 1.2);
        g_orbitSpeed[3] = generateRandomFloat(0.1, 1.2);
        g_orbitSpeed[4] = generateRandomFloat(0.1, 1.2);

        // Randomize offset for axis of rotation
        g_axisOfRotation[1] = generateRandomFloat(-0.5, 0.5);
        g_axisOfRotation[2] = generateRandomFloat(-0.5, 0.5);
        g_axisOfRotation[3] = generateRandomFloat(-0.5, 0.5);
        g_axisOfRotation[4] = generateRandomFloat(-0.5, 0.5);

        // Display info for each planet
        cout << "PLANET 1 - \tSize: " << g_scaleSize[1] << "\tSpeed: " << g_rotationSpeed[1] 
             << "\tOrbit Speed: " << g_orbitSpeed[1] << "\tAxis offset: " << g_axisOfRotation[1] << endl;
        cout << "PLANET 2 - \tSize: " << g_scaleSize[2] << "\tSpeed: " << g_rotationSpeed[2] 
             << "\tOrbit Speed: " << g_orbitSpeed[2] << "\tAxis offset: " << g_axisOfRotation[2] << endl;
        cout << "PLANET 3 - \tSize: " << g_scaleSize[3] << "\tSpeed: " << g_rotationSpeed[3] 
             << "\tOrbit Speed: " << g_orbitSpeed[3] << "\tAxis offset: " << g_axisOfRotation[3] << endl;
        cout << "PLANET 4 - \tSize: " << g_scaleSize[4] << "\tSpeed: " << g_rotationSpeed[4] 
             << "\tOrbit Speed: " << g_orbitSpeed[4] << "\tAxis offset: " << g_axisOfRotation[4] << endl;
        cout << endl;

        render_scene();
    }
}

// error callback function
static void error_callback(int error, const char* description)
{
    cerr << description << endl;    // output error description
}

int main(void)
{
    GLFWwindow* window = NULL;  // pointer to a GLFW window handle

    glfwSetErrorCallback(error_callback);   // set error callback function

    // initialise GLFW
    if (!glfwInit())
    {
        // if failed to initialise GLFW
        exit(EXIT_FAILURE);
    }

    // minimum OpenGL version 3.3
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);

    // create a window and its OpenGL context
    window = glfwCreateWindow(1500, 1000, "Assignment 2", NULL, NULL);

    // if failed to create window
    if (window == NULL)
    {
        glfwTerminate();
        exit(EXIT_FAILURE);
    }

    glfwMakeContextCurrent(window); // set window context as the current context
    glfwSwapInterval(1);            // swap buffer interval

    // initialise GLEW
    if (glewInit() != GLEW_OK)
    {
        // if failed to initialise GLEW
        cerr << "GLEW initialisation failed" << endl;
        exit(EXIT_FAILURE);
    }

    // set key callback function
    glfwSetKeyCallback(window, key_callback);
    glfwSetCursorPosCallback(window, cursor_position_callback); 

    // use sticky mode to avoid missing state changes from polling
    glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);

    // use mouse to move camera, hence use disable cursor mode
    glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); 

    // initialise rendering states
    init(window);

    // variables for simple time management
    float lastUpdateTime = glfwGetTime();
    float currentTime = lastUpdateTime;

    // the rendering loop
    while (!glfwWindowShouldClose(window))
    {
        currentTime = glfwGetTime();

        g_camera.update(window);    // update camera

        // only update if more than 0.02 seconds since last update
        if (currentTime - lastUpdateTime > 0.02)
        {
            update_scene();     // update the scene
            render_scene();     // render the scene

            glfwSwapBuffers(window);    // swap buffers
            glfwPollEvents();           // poll for events

            lastUpdateTime = currentTime;   // update last update time
        }
    }

    // clean up
    glDeleteProgram(g_shaderProgramID);
    glDeleteBuffers(1, &g_IBO);
    glDeleteBuffers(1, &g_VBO[0]);
    glDeleteBuffers(1, &g_VBO[1]);
    glDeleteVertexArrays(1, &g_VAO[0]);
    glDeleteVertexArrays(1, &g_VAO[1]);

    // close the window and terminate GLFW
    glfwDestroyWindow(window);
    glfwTerminate();

    exit(EXIT_SUCCESS);
}

相机.cpp

    #include "Camera.h"

    Camera::Camera()
    {
        // initialise camera member variables
        mPosition = glm::vec3(0.0f, 0.0f, 1.0f);
        mLookAt = glm::vec3(0.0f, 0.0f, 0.0f);
        mUp = glm::vec3(0.0f, 1.0f, 0.0f);

        mYaw = 0.0f;
        mPitch = 0.0f;

        mViewMatrix = glm::lookAt(mPosition, mLookAt, mUp);
        mProjectionMatrix = glm::perspective(45.0f, 1.5f, 0.1f, 100.0f);
    }

    Camera::~Camera()
    {}

    void Camera::update(GLFWwindow* window)
    {
        // variables to store forward/back and strafe movement
        float moveForward = 0;
        float strafeRight = 0;

        // update variables based on keyboard input
        if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
            moveForward += MOVEMENT_SENSITIVITY;
        if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
            moveForward -= MOVEMENT_SENSITIVITY;
        if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
            strafeRight -= MOVEMENT_SENSITIVITY;
        if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
            strafeRight += MOVEMENT_SENSITIVITY;

        // rotate the respective unit vectors about the y-axis
        glm::vec3 rotatedForwardVec = glm::rotateY(glm::vec3(0.0f, 0.0f, -1.0f), mYaw);
        glm::vec3 rotatedRightVec = glm::rotateY(glm::vec3(1.0f, 0.0f, 0.0f), mYaw);
        // rotate the rotated forward vector about the rotated right vector
        rotatedForwardVec = glm::vec3(glm::rotate(mPitch, rotatedRightVec)*glm::vec4(rotatedForwardVec, 0.0f));

        // update position, look-at and up vectors
        mPosition += rotatedForwardVec * moveForward + rotatedRightVec * strafeRight;
        mLookAt = mPosition + rotatedForwardVec;
        mUp = glm::cross(rotatedRightVec, rotatedForwardVec);

        // compute the new view matrix
        mViewMatrix = glm::lookAt(mPosition, mLookAt, mUp);
    }

    void Camera::updateYaw(float yaw)
    {
        mYaw -= yaw * ROTATION_SENSITIVITY;
    }

    void Camera::updatePitch(float pitch)
    {
        mPitch -= pitch * ROTATION_SENSITIVITY;
    }

    void Camera::setViewMatrix(glm::vec3 position, glm::vec3 lookAt, glm::vec3 up)
    {
        mPosition = position;
        mLookAt = lookAt;
        mUp = up;

        mViewMatrix = glm::lookAt(mPosition, mLookAt, mUp);
    }

    void Camera::setProjectionMatrix(glm::mat4& matrix)
    {
        mProjectionMatrix = matrix;
    }

    glm::mat4 Camera::getViewMatrix()
    {
        return mViewMatrix;
    }

    glm::mat4 Camera::getProjectionMatrix()
    {
        return mProjectionMatrix;
    }

相机.h

#ifndef __CAMERA_H
#define __CAMERA_H

#include <GLFW/glfw3.h> // include GLFW (which includes the OpenGL header)
#include <glm/glm.hpp>  // include GLM (ideally should only use the GLM headers that are actually used)
#include <glm/gtx/transform.hpp>
#include <glm/gtx/rotate_vector.hpp>
using namespace glm;    // to avoid having to use glm::

#define MOVEMENT_SENSITIVITY 0.0005f        // camera movement sensitivity
#define ROTATION_SENSITIVITY 0.001f     // camera rotation sensitivity

class Camera {
public:
    Camera();
    ~Camera();

    void update(GLFWwindow* window);
    void updateYaw(float yaw);
    void updatePitch(float pitch);
    void setViewMatrix(glm::vec3 position, glm::vec3 lookAt, glm::vec3 up);
    void setProjectionMatrix(glm::mat4& matrix);
    glm::mat4 getViewMatrix();
    glm::mat4 getProjectionMatrix();

private:
    float mYaw;
    float mPitch;
    glm::vec3 mPosition;
    glm::vec3 mLookAt;
    glm::vec3 mUp;
    glm::mat4 mViewMatrix;
    glm::mat4 mProjectionMatrix;
};

#endif

顶点着色器

#version 330 core

// input data (different for all executions of this shader)
in vec3 aPosition;
in vec3 aColor;

// ModelViewProjection matrix
uniform mat4 uModelViewProjectionMatrix;

// output data (will be interpolated for each fragment)
out vec3 vColor;

void main()
{
    // set vertex position
    gl_Position = uModelViewProjectionMatrix * vec4(aPosition, 1.0);

    // the color of each vertex will be interpolated
    // to produce the color of each fragment
    vColor = aColor;
}

最佳答案

您必须从世界坐标映射到视口(viewport)坐标

x  y  z
--------
 1  0  0  | x' =  x
 0  0  1  | y' =  z
 0 -1  0  | z' = -y

使用它可以从上方查看场景:

g_camera.setViewMatrix(glm::vec3(0, 15.0f, 0), glm::vec3(0, 0, 0), glm::vec3(0, 0, -1.0f));


要对 View 进行 Pane 、缩放和轨道旋转,您必须设置平移和旋转矩阵,并且必须连接(乘法) 它们与 View 矩阵。

向类Camera添加成员来存储平移和旋转角度:

glm::vec3 _move;
float     _angX;
float     _angY;

调整方法Camera::update来总结平移和旋转角度:

#define MOVEMENT_SENSITIVITY 0.01f
#define ZOOM_SENSITIVITY 0.1f
#define ROTATION_SENSITIVITY 1.0f

void Camera::update(GLFWwindow* window)
{
  if ( glfwGetKey( window, GLFW_KEY_A )         == GLFW_PRESS ) _move[0] -= MOVEMENT_SENSITIVITY;
  if ( glfwGetKey( window, GLFW_KEY_D )         == GLFW_PRESS ) _move[0] += MOVEMENT_SENSITIVITY;
  if ( glfwGetKey( window, GLFW_KEY_S )         == GLFW_PRESS ) _move[1] -= MOVEMENT_SENSITIVITY;
  if ( glfwGetKey( window, GLFW_KEY_W )         == GLFW_PRESS ) _move[1] += MOVEMENT_SENSITIVITY;
  if ( glfwGetKey( window, GLFW_KEY_PAGE_DOWN ) == GLFW_PRESS ) _move[2] -= ZOOM_SENSITIVITY;
  if ( glfwGetKey( window, GLFW_KEY_PAGE_UP )   == GLFW_PRESS ) _move[2] += ZOOM_SENSITIVITY;
  if ( glfwGetKey( window, GLFW_KEY_UP )        == GLFW_PRESS ) _angX -= ROTATION_SENSITIVITY;
  if ( glfwGetKey( window, GLFW_KEY_DOWN )      == GLFW_PRESS ) _angX += ROTATION_SENSITIVITY;
  if ( glfwGetKey( window, GLFW_KEY_RIGHT )     == GLFW_PRESS ) _angY -= ROTATION_SENSITIVITY;
  if ( glfwGetKey( window, GLFW_KEY_LEFT )      == GLFW_PRESS ) _angY += ROTATION_SENSITIVITY;
}

请注意,您必须根据需要调整灵敏度和按钮甚至其他类型的输入。为了获得明确定义的行为,您应该在时间离散过程中执行更新方法。

在方法Camera::getViewMatrix中设置平移矩阵和旋转矩阵,并将它们连接到 View 矩阵:

glm::mat4 Camera::getViewMatrix()
{
    glm::mat4 rotX = glm::rotate( _angX * (float)PI / 180.0f, glm::vec3( mViewMatrix[0] ) );
    glm::mat4 rotY = glm::rotate( _angY * (float)PI / 180.0f, glm::vec3( mViewMatrix[1] ) );
    glm::mat4 trans = glm::translate( glm::mat4( 1.0 ), _move );
    return trans * mViewMatrix * rotX * rotY;
}

关于opengl - 如何让 OpenGL 相机指向下方?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45411585/

相关文章:

c++ - 在 OpenGL 中将矩阵与 vector 对齐

c++ - Glm VECTORIZE2_VEC 重新定义 XCode 警告

c++ - 在 CLion (MacOS) 中使用 OpenGL 和 GLUT 库时出现链接错误

编译时的OpenGL问题

c++ - opengl 微小的渲染故障,需要帮助和提示

c++ - 在一个 vbo 中绘制多个形状

c++ - OpenGL 中的 3D 旋转

c++ - opengl 从一个 vao 中绘制多个对象

c++ - 使用 glm 在本地和全局方向上旋转和平移对象

ios - 从 OpenGL 移植到 MetalKit - 投影矩阵(?)问题