OpenGL透视相机

Posted

技术标签:

【中文标题】OpenGL透视相机【英文标题】:OpenGL Perspective Camera 【发布时间】:2019-11-26 22:57:18 【问题描述】:

我不确定为什么代码不显示旋转立方体。我正在寻找原因。我认为这与观点或观点有关,但我不确定。我只需要了解为什么我不能将一个简单的立方体放到屏幕上。

#include <iostream>
#include <GL/glew.h>

// GLFW
#include <GLFW/glfw3.h>

#include "LoadShader.hpp" // just a function in a header that returns a GLuint for a shaderProgram

#define FS1 "shader1.frag"
#define VS1 "shader1.vert"

#define GLM_ENABLE_EXPERIMENTAL
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/string_cast.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <assimp/cimport.h>
#include <assimp/scene.h>
#include <assimp/postprocess.h>


// Window dimensions
const GLuint WIDTH = 800, HEIGHT = 600;

// The MAIN function, from here we start the application and run the game loop
int main()

    // Init GLFW
    glfwInit( );

    // Set all the required options for GLFW
    glfwWindowHint( GLFW_CONTEXT_VERSION_MAJOR, 3 );
    glfwWindowHint( GLFW_CONTEXT_VERSION_MINOR, 3 );
    glfwWindowHint( GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE );
    glfwWindowHint( GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE );

    glfwWindowHint( GLFW_RESIZABLE, GL_FALSE );

    // Create a GLFWwindow object that we can use for GLFW's functions
    GLFWwindow *window = glfwCreateWindow( WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr );

    int screenWidth, screenHeight;
    glfwGetFramebufferSize( window, &screenWidth, &screenHeight );

    if ( nullptr == window )
    
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate( );

        return EXIT_FAILURE;
    

    glfwMakeContextCurrent( window );

    // Set this to true so GLEW knows to use a modern approach to retrieving function pointers and extensions
    glewExperimental = GL_TRUE;
    // Initialize GLEW to setup the OpenGL Function pointers
    if ( GLEW_OK != glewInit( ) )
    
        std::cout << "Failed to initialize GLEW" << std::endl;
        return EXIT_FAILURE;
    
    glEnable( GL_DEPTH_TEST ) ; 
    //glDepthFunc( GL_LESS ) ; 
    // Define the viewport dimensions
    glViewport( 0, 0, screenWidth, screenHeight );

    //glMatrixMode(GL_PROJECTION);
    // Set up vertex data (and buffer(s)) and attribute pointers

    GLfloat vertices[  ] =
       // verticies  a0             // colors  a1
        // front
        -1.0, -1.0,  1.0, .70f , 0.32f , 0.31f ,
         1.0, -1.0,  1.0, .20f , 0.4f , 0.21f ,
         1.0,  1.0,  1.0, .50f , 0.32f , 0.71f ,
        -1.0,  1.0,  1.0, .60f , 0.62f , 0.11f ,
        // back
        -1.0, -1.0,  -1.0, .30f , 0.87f , 0.60f ,
         1.0, -1.0, -1.0, .30f , 0.87f , 0.f ,
         1.0,  1.0, -1.0, .10f , 0.f , 0.60f ,
        -1.0,  1.0, -1.0, .20f , 0.87f , 0.60f ,
        // side Right 
        1.0f , 1.0 , 1.0 , .45f , .3f , .4f ,
        1.0 , -1.0 , 1.0 , .5f , .8f, .1f , 
        1.0 , -1.0 , -1.0 , .3f , .6f , .0f ,
        1.0 , 1.0 , -1.0 , .45f , .87f , .53f ,
        // left Side
        -1.0f , 1.0 , 1.0 ,  .45f , .23f , .54f ,
        -1.0 , -1.0 , 1.0 ,  .51f , .84f, .81f , 
        -1.0 , -1.0 , -1.0 ,  .6f , .4f , .78f ,
        -1.0 , 1.0 , -1.0 , .45f , .87f , .53f ,
        //top
        -1.f , 1.f , 1.f , .35f , .87f , .54f ,
        -1.f , 1.f , -1.f , .45f , .98f, .92f ,
        1.f , 1.f , 1.f , .50f , 0.f , .32f  , 
        1.f , 1.f , -1.f , 1.f , .72f , .87f ,
        // bottom
        -1.f , -1.f , 1.f , .35f , .87f , .54f ,
        -1.f , -1.f , -1.f , .45f , .98f, .92f ,
        1.f , -1.f , 1.f , .50f , .89f , .32f  , 
        1.f , -1.f , -1.f , 0.f , .72f , .87f 
    ;

    GLuint indices[  ] =
    
        0 ,  1 ,  2 ,  0 ,  2 ,  3 ,
        4 ,  5 ,  6 ,  4 ,  6 ,  7 ,
        8 , 9 , 10 , 8 , 10 , 11 ,
        12 , 13 , 14 , 12 , 14 , 15  ,
        16 , 19 , 18 , 16 , 17 , 19 ,
        20 , 23 , 22 , 20 , 21 , 23
     ; 
    int numOfIndices = sizeof( indices ) / sizeof ( GLuint ) ; 
    std::cout << numOfIndices << std::endl ;

    GLuint VAO , VBO , EBO ; 
    glGenVertexArrays( 1 , &VAO ) ; 
    glBindVertexArray( VAO ) ; 
    glGenBuffers( 1 , &VBO ) ; 
    glBindBuffer( GL_ARRAY_BUFFER , VBO ) ; 
    glBufferData( GL_ARRAY_BUFFER , sizeof( vertices ) , vertices , GL_STATIC_DRAW ) ; 

    glVertexAttribPointer( 0 , 3 , GL_FLOAT , GL_FALSE , 6 * sizeof(GLfloat) , ( GLvoid * ) 0  ) ; 
    glEnableVertexAttribArray( 0 ) ; 
    glVertexAttribPointer( 1 , 3 , GL_FLOAT , GL_FALSE , 6 * sizeof(GLfloat) , (GLvoid*)(3 * sizeof(GL_FLOAT)) ) ;
    glEnableVertexAttribArray( 1 ) ; 

    glGenBuffers( 1 , &EBO ) ; 
    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER , EBO ) ; 
    glBufferData( GL_ELEMENT_ARRAY_BUFFER , sizeof( indices ) , indices , GL_STATIC_DRAW ) ; 

    GLuint program = LoadShaders( VS1 , FS1 ) ; 
    glUseProgram( program ) ; 

    float rotationDegrees = 1.f ; 
    float fov = 1.0f ; 



    glm::mat4 view;
    view = glm::lookAt(glm::vec3( 0.0f, 1.0f, -3.0f), 
           glm::vec3(0.0f, 0.0f, 0.0f), 
           glm::vec3(0.0f, 1.0f, 0.0f));
    glm::mat4 projectionMatrix = glm::perspective( fov , ( ( float ) HEIGHT  ) / WIDTH , 1.f , 10.0f ) ;
    glm::mat4 modelTransform = glm::translate( glm::mat4( 1.f ) , glm::vec3( .0f , -3.0f , -3.0f ) ) ;
    glm::mat4 rotation = glm::rotate( glm::mat4(1.f) , rotationDegrees , glm::vec3( 1.f , 1.f , 0.f ) ) ;
    //glm::mat4 rotation = glm::rotate( rotation1 , 30.f , glm::vec3( 0.f , 2.f , 0.f )  ) ;
    glm::mat4 fullTransform = projectionMatrix * modelTransform * rotation ; 


    GLuint transformLocation = glGetUniformLocation( program , "uModelTranslate" ) ; 
    GLuint projectionLocation = glGetUniformLocation( program , "uProjectionMatrix" ) ;
    //modelTransform = modelTransform * rotation ; 
    glUniformMatrix4fv( transformLocation , 1 , GL_FALSE , &modelTransform[0][0] ) ; 
    glUniformMatrix4fv( projectionLocation , 1 , GL_FALSE , &fullTransform[0][0] ) ;
    bool canUp , canDown , canL , canR , canW , canS ,canA , canD , canQ , canE ;
    canQ = true ; 
    canE = true ; 
    canD= true ; 
    canA = true ;  
    canUp = true ; 
    canS = true ; 
    canDown = true ; 
    canR = true ; 
    canL = true ; 
    canW = true ; 
    float nearF = 0.1f ; 

    float zZ = -3.0 ; 
    float yY = 1.0f ; 
    float xX = 0.f ;

    while ( !glfwWindowShouldClose( window ) )
    
        // Check if any events have been activiated (key pressed, mouse moved etc.) and call corresponding response functions
        glfwPollEvents( );

        rotationDegrees += .0001f ; 
        if( rotationDegrees >= 360 )
        
            rotationDegrees =0 ; 
        
        view = glm::lookAt(glm::vec3( yY , xX, zZ), 
           glm::vec3(0.0f, 0.0f, 0.0f), 
           glm::vec3(0.0f, 1.0f, 0.0f));
        glm::mat4 rotation = glm::rotate( glm::mat4(1.f) , rotationDegrees , glm::vec3( 1.f , 1.f , 0.f ) ) ;
        glm::mat4 projectionMatrix = glm::perspective(glm::radians(fov), (float) WIDTH / (float)HEIGHT , nearF, 10.0f);
        glm::mat4 fullTransform = projectionMatrix * view * rotation ; 
        glUniformMatrix4fv( projectionLocation , 1 , GL_FALSE , &fullTransform[0][0] ) ;

        // Render
        // Clear the colorbuffer
        glClearColor( 0.f, 0.f, 0.f, 1.0f );
        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

        if (glfwGetKey(window,GLFW_KEY_ESCAPE) == GLFW_PRESS )
        
            glfwSetWindowShouldClose(window,true);
        
        if (glfwGetKey(window,GLFW_KEY_UP) == GLFW_PRESS && canUp )
        
            canUp = false ; 
            fov +=  1.f ;
            std::cout << fov << std::endl ; 
        
        if (glfwGetKey(window,GLFW_KEY_UP) != GLFW_PRESS && !canUp )
        
            canUp = true ; 
        
        if (glfwGetKey(window,GLFW_KEY_DOWN) == GLFW_PRESS && canDown)
        
            canDown = false ; 
            fov +=  -1.f ; 
            std::cout << fov << std::endl ;
        
        if (glfwGetKey(window,GLFW_KEY_DOWN) != GLFW_PRESS && !canDown)
        
            canDown = true ; 
        
                if (glfwGetKey(window,GLFW_KEY_ESCAPE) == GLFW_PRESS )
        
            glfwSetWindowShouldClose(window,true);
        

        if (glfwGetKey(window,GLFW_KEY_LEFT) == GLFW_PRESS && canL )
        
            canL = false ; 
            nearF +=  1.f ;
            std::cout << nearF << std::endl ; 
        
        if (glfwGetKey(window,GLFW_KEY_LEFT) != GLFW_PRESS && !canL )
        
            canL = true ; 
        
        if (glfwGetKey(window,GLFW_KEY_RIGHT) == GLFW_PRESS && canR)
        
            canR = false ; 
            nearF +=  -1.f ; 
            std::cout << nearF << std::endl ;
        
        if (glfwGetKey(window,GLFW_KEY_RIGHT) != GLFW_PRESS && !canR)
        
            canR = true ; 
        

        if (glfwGetKey(window,GLFW_KEY_W) == GLFW_PRESS && canW)
        
            canW = false ; 
            zZ +=  -1.f ; 
            std::cout << zZ << std::endl ;
        
        if (glfwGetKey(window,GLFW_KEY_W) != GLFW_PRESS && !canW)
        
            canW = true ; 
        


        if (glfwGetKey(window,GLFW_KEY_S) == GLFW_PRESS && canS)
        
            canS = false ; 
            zZ +=  +1.f ; 
            std::cout << zZ << std::endl ;
        
        if (glfwGetKey(window,GLFW_KEY_S) != GLFW_PRESS && !canS)
        
            canS = true ; 
        

        if (glfwGetKey(window,GLFW_KEY_A) == GLFW_PRESS && canA)
        
            canA = false ; 
            xX +=  +1.f ; 
            std::cout << xX << std::endl ;
        
        if (glfwGetKey(window,GLFW_KEY_A) != GLFW_PRESS && !canA)
        
            canA = true ; 
        

        if (glfwGetKey(window,GLFW_KEY_D) == GLFW_PRESS && canD)
        
            canD = false ; 
            xX +=  -1.f ; 
            std::cout << xX << std::endl ;
        
        if (glfwGetKey(window,GLFW_KEY_D) != GLFW_PRESS && !canD)
        
            canD = true ; 
        

        if (glfwGetKey(window,GLFW_KEY_Q) == GLFW_PRESS && canQ)
        
            canQ = false ; 
            yY +=  -1.f ; 
            std::cout << yY << std::endl ;
        
        if (glfwGetKey(window,GLFW_KEY_Q) != GLFW_PRESS && !canQ)
        
            canQ = true ; 
        
        if (glfwGetKey(window,GLFW_KEY_E) == GLFW_PRESS && canE)
        
            canE = false ; 
            yY +=  1.f ; 
            std::cout << yY << std::endl ;
        
        if (glfwGetKey(window,GLFW_KEY_E) != GLFW_PRESS && !canE)
        
            canE = true ; 
        

        //glUseProgram( program ) ; 
        glDrawElements( GL_TRIANGLES , numOfIndices , GL_UNSIGNED_INT , 0 ) ; 

        // Swap the screen buffers
        glfwSwapBuffers( window );
    

    glfwTerminate( );

    return EXIT_SUCCESS;

【问题讨论】:

据我们所知,您的着色器很糟糕。在minimal reproducible example 中编辑。随意使用this 作为基础。 为什么你在一个glm::perspective()调用中使用glm::radians()而不是另一个? 不确定它是否对 glm 弧度有影响。我在这里的大部分内容都来自一个例子。我的目标是在 3d 空间中创建一个立方体并让它旋转,它实际上看起来像一个立方体而不是一个倾斜的矩形。 如果您运行我的代码,您将能够使用键盘调整矩阵中的变量所以。 【参考方案1】:

glm::perspectiveglm::rotate 的角度单位是弧度。 1° 的视野非常小。modelTransform 矩阵的平移分量将对象移出viewing frustum 并且必须减少。 此外,我建议启用Depth Test。

例如:

float rotationDegrees = 0.0f; 
float fov = 90.0f; 
float nearF = 0.1f; 
float zZ = -3.0; 
float yY = 1.0f; 
float xX = 0.0f;
   
glEnable(GL_DEPTH_TEST);

while (!glfwWindowShouldClose(wnd))

    glm::mat4 rotation         = glm::rotate(glm::mat4(1.0f), glm::radians(rotationDegrees), glm::vec3(1.0f , 1.0f , 0.0f)) ;
    glm::mat4 modelTransform   = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.5f, 0.0f)) ;
    glm::mat4 view             = glm::lookAt(glm::vec3(yY , xX, zZ), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));  
    glm::mat4 modelview        = view * modelTransform * rotation;
    glm::mat4 projectionMatrix = glm::perspective(glm::radians(fov), (float)WIDTH / (float)HEIGHT, nearF, 10.0f);

    rotationDegrees += 1.0f;

    glUniformMatrix4fv(transformLocation, 1, GL_FALSE, glm::value_ptr(modelview)); 
    glUniformMatrix4fv(projectionLocation, 1, GL_FALSE, glm::value_ptr(projectionMatrix));

    // [...]

顶点着色器:

#version 330 core

layout (location = 0) in vec3 inPos;
layout (location = 1) in vec3 inColor;

out vec3 vertCol;

uniform mat4 uProjectionMatrix;
uniform mat4 uModelTranslate;

void main()

    vertCol     = inColor;
    gl_Position = uProjectionMatrix * uModelTranslate * vec4(inPos.xyz, 1.0);

【讨论】:

您能否确认您在编译时所做的更改对您有效?

以上是关于OpenGL透视相机的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL - 透视问题

如何使用OpenGL着色器在平面上绘制没有透视的纹理?

✠OpenGL-3-数学基础

OpenGL ES —— Perspective Projection的推导

OpenGL ES —— Perspective Projection的推导

使用鼠标拖动的 OpenGL 平移点