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::perspective
和glm::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 ES —— Perspective Projection的推导