OpenGL相机导致拉伸(C ++)

时间:2018-04-06 19:38:58

标签: c++ opengl matrix

我正在研究OpenGL中的相机移动。当我旋转相机时,我视图中的物体在经过我时会产生不寻常的拉伸效果。这可以在我的YouTube视频(https://youtu.be/RviJ0bVw880)上看到。我相信我的投影矩阵或视图矩阵有问题,但我不确定。

主要问题:旋转相机时,如何防止物体拉伸?

这是我的C ++代码(我相信你要找的是接近底部):

//Load functions from usr/include/
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <stdio.h>
#include <glm/glm.hpp>
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/ext.hpp>
#include "glm/gtx/string_cast.hpp"
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
/**/#include <iostream>
/**/#include <vector>
//Main function
int main() {
    std::ios_base::sync_with_stdio(false);//Disables the synchronization between the C and C++ standard streams (though  mixing C- and C++ style I/O will be a challenge)
    std::cin.tie(NULL);//Unties cin from cout for faster cin and cout functions (this does mean that they are off sync but if you are not using cin than it doesnt matter)
    if(!glfwInit()) {
        //Initialization failed
        fprintf(stderr,"Failed to initialize GLFW\n");//Initialization error
        return -1;//A -1 returned to the main function indicates a unsuccessful run
    }
    //Window hints change the way the window works (like settings)
    glfwWindowHint(GLFW_SAMPLES,4);//4x antialiasing
    //"Major" and "minor" are two components of a single version number, separated by a dot.
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR,3);//Version 3...
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR,3);//.3
    //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT,GL_TRUE);//To make MacOS happy; should not be needed
    glfwWindowHint(GLFW_OPENGL_PROFILE,GLFW_OPENGL_CORE_PROFILE);//We don't want the old OpenGL
    const GLFWvidmode*mode=glfwGetVideoMode(glfwGetPrimaryMonitor());//Constant (not-changable) GLFWvideomode (variable type) is named "mode", is set to the primary monitor
    glfwWindowHint(GLFW_RED_BITS,mode->redBits);
    glfwWindowHint(GLFW_GREEN_BITS,mode->greenBits);
    glfwWindowHint(GLFW_BLUE_BITS,mode->blueBits);
    glfwWindowHint(GLFW_REFRESH_RATE,mode->refreshRate);
    GLFWwindow*window=glfwCreateWindow(mode->width,mode->height,"My Title",glfwGetPrimaryMonitor(),NULL);//Create window that is the size of "mode" (constant primary monitor), named "", on the primary monitor
    if(window==NULL) { //If glfw window does not exist
        fprintf(stderr,"Failed to open GLFW window. If you have an Intel GPU, they are not 3.3 compatible.\n");
        glfwTerminate();//End glfw processes
        return -1;
    }
    glfwMakeContextCurrent(window);//Initialize GLEW
    glewExperimental=true;//Needed in core profile
    if(glewInit()!=GLEW_OK) { //If glew is not okay
        fprintf(stderr,"Failed to initialize GLEW\n");
        return -1;
    }
    glEnable(GL_DEPTH_TEST);
    static const GLfloat g_vertex_buffer_data[]= { //Creates static (only runs once) constant (not-changable) array for VBO data
        -1.0f,-1.0f,-1.0f, // triangle 1 : begin
        -1.0f,-1.0f, 1.0f,
        -1.0f, 1.0f, 1.0f, // triangle 1 : end
        1.0f, 1.0f,-1.0f, // triangle 2 : begin
        -1.0f,-1.0f,-1.0f,
        -1.0f, 1.0f,-1.0f, // triangle 2 : end
        1.0f,-1.0f, 1.0f,
        -1.0f,-1.0f,-1.0f,
        1.0f,-1.0f,-1.0f,
        1.0f, 1.0f,-1.0f,
        1.0f,-1.0f,-1.0f,
        -1.0f,-1.0f,-1.0f,
        -1.0f,-1.0f,-1.0f,
        -1.0f, 1.0f, 1.0f,
        -1.0f, 1.0f,-1.0f,
        1.0f,-1.0f, 1.0f,
        -1.0f,-1.0f, 1.0f,
        -1.0f,-1.0f,-1.0f,
        -1.0f, 1.0f, 1.0f,
        -1.0f,-1.0f, 1.0f,
        1.0f,-1.0f, 1.0f,
        1.0f, 1.0f, 1.0f,
        1.0f,-1.0f,-1.0f,
        1.0f, 1.0f,-1.0f,
        1.0f,-1.0f,-1.0f,
        1.0f, 1.0f, 1.0f,
        1.0f,-1.0f, 1.0f,
        1.0f, 1.0f, 1.0f,
        1.0f, 1.0f,-1.0f,
        -1.0f, 1.0f,-1.0f,
        1.0f, 1.0f, 1.0f,
        -1.0f, 1.0f,-1.0f,
        -1.0f, 1.0f, 1.0f,
        1.0f, 1.0f, 1.0f,
        -1.0f, 1.0f, 1.0f,
        1.0f,-1.0f, 1.0f
    };
    GLuint vao;//Declares variable vbo, GLuint (opengl's unsigned interger)
    glGenVertexArrays(1,&vao);
    glBindVertexArray(vao);
    //Upload this vertex data to the graphics card
    GLuint vbo;//Declares variable vbo, GLuint (opengl's unsigned interger)
    glGenBuffers(1,&vbo);//Generate 1 buffer
    glBindBuffer(GL_ARRAY_BUFFER,vbo);//To upload the actual data to the graphics card you first have to make it the active object
    glBufferData(GL_ARRAY_BUFFER,sizeof(g_vertex_buffer_data),g_vertex_buffer_data,GL_STATIC_DRAW);//Now that our VBO is active we can copy the vertex data to it
    const char*vertexSource=R"glsl(
    #version 150 core
    in vec4 position;
    uniform mat4 model;
    uniform mat4 view;
    uniform mat4 project;
    void main()
    {
        gl_Position=project*view*model*position;
    }
  )glsl";
    GLuint vertexShader=glCreateShader(GL_VERTEX_SHADER);//Creates shader object
    glShaderSource(vertexShader,1,&vertexSource,NULL);//Loads data to shader object
    glCompileShader(vertexShader);//Compiles shader object
    //Vertex compile error message
    //*
    int success;
    char infoLog[512];
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
    if(!success)
    {
        glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
    }
    //*/
    const char* fragmentSource=R"glsl(
    #version 150 core

    out vec4 outColor;

    void main()
    {
      outColor = vec4(1.0, 0.5, 0.0, 1.0);
    }
  )glsl";
    //The fragment shader is compiled in exactly the same way
    GLuint fragmentShader=glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader,1,&fragmentSource,NULL);
    glCompileShader(fragmentShader);
    //Fragment compile error message
    //*
    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
    if(!success)
    {
        glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
    }
    //*/
    //Combines shaders into one program
    GLuint shaderProgram=glCreateProgram();//Create shader program
    //Attatch vertex shader and fragment shader to new shader program
    glAttachShader(shaderProgram,vertexShader);
    glAttachShader(shaderProgram,fragmentShader);
    glLinkProgram(shaderProgram);//Links shader program
    //Shader program linking error message
    //*
    GLint linked;
    int InfoLogLength;
    glGetProgramiv(shaderProgram, GL_INFO_LOG_LENGTH, &InfoLogLength);
    if (InfoLogLength > 0) {
        std::vector<char> ProgramErrorMessage(InfoLogLength+1);
        glGetProgramInfoLog(shaderProgram, InfoLogLength, NULL, &ProgramErrorMessage[0]);
        printf("%s\n", &ProgramErrorMessage[0]);
    }
    //*/
    //To actually start using the shaders in the program, you just have to call:
    glUseProgram(shaderProgram);
    //You first need to retrieve a reference to the position input in the vertex shader
    GLint posAttrib=glGetAttribLocation(shaderProgram,"position");
    glVertexAttribPointer(posAttrib,3,GL_FLOAT,GL_FALSE,0,0);//Specify how the data for that input is retrieved from the array
    glEnableVertexAttribArray(posAttrib);
    glm::mat4 model = glm::mat4(1.0f);
    model = glm::scale(model,glm::vec3(1.f));
    model = glm::translate(model,glm::vec3(0.f,0.f,0.f));

    glUniformMatrix4fv(glGetUniformLocation(shaderProgram,"model"),1,GL_FALSE,glm::value_ptr(model));
    float apple;
    glm::mat4 view = glm::lookAt(glm::vec3(0,0,1),glm::vec3(0,0,0),glm::vec3(0,1,0));
    glUniformMatrix4fv(glGetUniformLocation(shaderProgram,"view"),1,GL_FALSE,glm::value_ptr(view));
    std::cout<<glm::to_string(view);
    glm::mat4 project = glm::perspective(90.0f,(float)mode->width/(float)mode->height,0.1f,-10.0f);
    int prj_loc = glGetUniformLocation(shaderProgram,"project");
    glUniformMatrix4fv(prj_loc,1,GL_FALSE,glm::value_ptr(project));
    while(!glfwWindowShouldClose(window)){ 
        glClearColor(0.5f,0.5f,0.5f,1.0f);
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
        glDrawArrays(GL_TRIANGLES,0,12*3);
        glfwSwapBuffers(window);
        glfwPollEvents();
        if(glfwGetKey(window,GLFW_KEY_RIGHT)==GLFW_PRESS)
            apple+=0.1;
            view = glm::rotate(view, glm::radians(apple),{0,1,0});
        if(glfwGetKey(window,GLFW_KEY_LEFT)==GLFW_PRESS)
            apple-=0.1;
            view = glm::rotate(view, glm::radians(apple),{0,1,0});
        if(glfwGetKey(window,GLFW_KEY_DOWN)==GLFW_PRESS)
            apple=0;
        if(glfwGetKey(window,GLFW_KEY_UP)==GLFW_PRESS)
            apple=0;
        glm::mat4 project = glm::perspective(90.0f,(float)mode->width/(float)mode->height,0.1f,100.0f);
        int prj_loc = glGetUniformLocation(shaderProgram,"project");
        glUniformMatrix4fv(prj_loc,1,GL_FALSE,glm::value_ptr(project));
        glm::mat4 view = glm::lookAt(glm::vec3(0,0,5),glm::vec3(sin(apple)*5,0,cos(apple))*5,glm::vec3(0,1,0));
        glUniformMatrix4fv(glGetUniformLocation(shaderProgram,"view"),1,GL_FALSE,glm::value_ptr(view));
    }
    glfwTerminate();
    return 0;//A 0 returned to the main function indicates a successful run
}

1 个答案:

答案 0 :(得分:0)

假设您想摆脱透视失真,而不是:

glm::mat4 project = glm::perspective(90.0f,(float)mode->width/(float)mode->height,0.1f,100.0f);

你可以尝试:

 glm::mat4 project = glm::ortho(0.f,(float)mode->width/(float)mode->height,0.0,1.0,0.1f,100.0f);

为了设置正交投影。