OpenGL--摄像机
目錄(?)[+]
一、 攝像機
1. 攝像機/觀察空間
定義一個攝像機,我們需要一個攝像機在世界空間中的位置、觀察的方向、一個指向它的右測的向量以及一個指向它上方的向量。?
攝像機的位置?
獲取攝像機位置很簡單。攝像機位置簡單來說就是世界空間中代表攝像機位置的向量。我們把攝像機位置設置為前面教程中的那個相同的位置:
- 1
攝像機方向?
用攝像機位置向量減去場景原點向量的結果就是攝像機指向向量。由于我們知道攝像機指向z軸負方向,我們希望方向向量指向攝像機的z軸正方向。如果我們改變相減的順序,我們就會獲得一個指向攝像機正z軸方向的向量。
- 1
- 2
右軸?
我們需要的另一個向量是一個右向量(Right Vector),它代表攝像機空間的x軸的正方向。為獲取右向量我們需要先使用一個小技巧:定義一個上向量(Up Vector)。我們把上向量和第二步得到的攝像機方向向量進行叉乘。兩個向量叉乘的結果就是同時垂直于兩向量的向量,因此我們會得到指向x軸正方向的那個向量(如果我們交換兩個向量的順序就會得到相反的指向x軸負方向的向量):
- 1
- 2
上軸?
現在我們已經有了x軸向量和z軸向量,獲取攝像機的正y軸相對簡單;我們把右向量和方向向量(Direction Vector)進行叉乘:
- 1
使用這些攝像機向量我們就可以創建一個LookAt矩陣了,它在創建攝像機的時候非常有用。
2. LookAt
現在我們有了3個相互垂直的軸和一個定義攝像機空間的位置坐標,我們可以創建我們自己的LookAt矩陣了:?
?
R是右向量,U是上向量,D是方向向量P是攝像機位置向量。注意,位置向量是相反的,因為我們最終希望把世界平移到與我們自身移動的相反方向。?
GLM已經提供了這些支持。我們要做的只是定義一個攝像機位置,一個目標位置和一個表示上向量的世界空間中的向量(我們使用上向量計算右向量)。接著GLM就會創建一個LookAt矩陣,我們可以把它當作我們的觀察矩陣:
- 1
- 2
- 3
- 4
3. 自由移動
首先我們必須設置一個攝像機系統,在我們的程序前面定義一些攝像機變量很有用:
glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f); glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f); glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);- 1
- 2
- 3
LookAt函數現在成了:
view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);- 1
我們首先設置之前定義的cameraPos為攝像機位置。方向(Direction)是當前的位置加上我們剛剛定義的方向向量。這樣能保證無論我們怎么移動,攝像機都會注視目標。我們在按下某個按鈕時更新cameraPos向量。
我們已經為GLFW的鍵盤輸入定義了一個key_callback函數,我們來添加幾個新按鍵命令:
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) {...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; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
當我們按下WASD鍵,攝像機的位置都會相應更新。如果我們希望向前或向后移動,我們就把位置向量加上或減去方向向量。如果我們希望向旁邊移動,我們做一個叉乘來創建一個右向量,沿著它移動就可以了。這樣就創建了類似使用攝像機橫向、前后移動的效果。
4. 視角移動
歐拉角?
歐拉角(Euler Angle)是表示3D空間中可以表示任何旋轉的三個值,由萊昂哈德·歐拉在18世紀提出。有三種歐拉角:俯仰角(Pitch)、偏航角(Yaw)和滾轉角(Roll),下面的圖片展示了它們的含義:?
?
俯仰角是描述我們如何往上和往下看的角,它在第一張圖中表示。第二張圖顯示了偏航角,偏航角表示我們往左和往右看的大小。滾轉角代表我們如何翻滾攝像機。?
對于我們的攝像機系統來說,我們只關心俯仰角和偏航角,所以我們不會討論滾轉角。用一個給定的俯仰角和偏航角,我們可以把它們轉換為一個代表新的方向向量的3D向量。
- 1
- 2
- 3
5. 鼠標輸入
首先我們要告訴GLFW,應該隱藏光標,并捕捉(Capture)它。捕捉鼠標意味著當應用集中焦點到鼠標上的時候光標就應該留在窗口中(除非應用拾取焦點或退出)。我們可以進行簡單的配置:?
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);?
這個函數調用后,無論我們怎么去移動鼠標,它都不會顯示了,也不會離開窗口。對于FPS攝像機系統來說很好:?
為計算俯仰角和偏航角我們需要告訴GLFW監聽鼠標移動事件。我們用下面的原型創建一個回調函數來做這件事(和鍵盤輸入差不多):
- 1
這里的xpos和ypos代表當前鼠標的位置。我們注冊了GLFW的回調函數,鼠標一移動mouse_callback函數就被調用:
glfwSetCursorPosCallback(window, mouse_callback);- 1
在處理FPS風格的攝像機鼠標輸入的時候,我們必須在獲取最終的方向向量之前做下面這幾步:
- 計算鼠標和上一幀的偏移量。
- 把偏移量添加到攝像機和俯仰角和偏航角中。
- 對偏航角和俯仰角進行最大和最小值的限制。
- 計算方向向量。
我們必須先儲存上一幀的鼠標位置,我們把它的初始值設置為屏幕的中心(屏幕的尺寸是800乘600):
GLfloat lastX = 400, lastY = 300;- 1
然后在回調函數中計算方向向量:
void mouse_callback(GLFWwindow* window, double xpos, double ypos) {//第一次則將當前位置設置為上一幀的位置來避免抖動if (firstMouse){lastX = xpos;lastY = ypos;firstMouse = false;}//計算偏移量并保存當前幀坐標為上一幀坐標GLfloat xoffset = xpos - lastX;GLfloat yoffset = lastY - ypos;lastX = xpos;lastY = ypos;//縮放偏轉量GLfloat sensitivity = 0.05;xoffset *= sensitivity;yoffset *= sensitivity;//計算偏轉位置yaw += xoffset;pitch += yoffset;//控制偏轉范圍if (pitch > 89.0f)pitch = 89.0f;if (pitch < -89.0f)pitch = -89.0f;//計算實際方向向量glm::vec3 front;front.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch));front.y = sin(glm::radians(pitch));front.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch));cameraFront = glm::normalize(front); }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
6. 縮放
當視野變小時可視區域就會減小,產生放大了的感覺。我們用鼠標滾輪來放大。和鼠標移動、鍵盤輸入一樣我們需要一個鼠標滾輪的回調函數:
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) {if (aspect >= 1.0f && aspect <= 45.0f)aspect -= yoffset;if (aspect <= 1.0f)aspect = 1.0f;if (aspect >= 45.0f)aspect = 45.0f; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
yoffset值代表我們滾動的大小。當scroll_callback函數調用后,我們改變全局aspect變量的內容。因為45.0f是默認的fov,我們將會把縮放級別限制在1.0f到45.0f。
我們現在在每一幀都必須把透視投影矩陣上傳到GPU,但這一次使aspect變量作為它的fov:
projection = glm::perspective(aspect, (GLfloat)WIDTH / (GLfloat)HEIGHT, 0.1f, 100.0f);- 1
最后不要忘記注冊滾動回調函數:
glfwSetScrollCallback(window, scroll_callback);- 1
7. 攝像機類
直接貼出原教程給出的攝像機類:
#pragma once// Std. Includes #include <vector>// GL Includes #include <GL/glew.h> #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp>// Defines several possible options for camera movement. Used as abstraction to stay away from window-system specific input methods enum Camera_Movement {FORWARD,BACKWARD,LEFT,RIGHT };// Default camera values const GLfloat YAW = -90.0f; const GLfloat PITCH = 0.0f; const GLfloat SPEED = 3.0f; const GLfloat SENSITIVTY = 0.25f; const GLfloat ZOOM = 45.0f;// An abstract camera class that processes input and calculates the corresponding Eular Angles, Vectors and Matrices for use in OpenGL class Camera { public:// Camera Attributesglm::vec3 Position;glm::vec3 Front;glm::vec3 Up;glm::vec3 Right;glm::vec3 WorldUp;// Eular AnglesGLfloat Yaw;GLfloat Pitch;// Camera optionsGLfloat MovementSpeed;GLfloat MouseSensitivity;GLfloat Zoom;// Constructor with vectorsCamera(glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f), GLfloat yaw = YAW, GLfloat pitch = PITCH) : Front(glm::vec3(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), MouseSensitivity(SENSITIVTY), Zoom(ZOOM){this->Position = position;this->WorldUp = up;this->Yaw = yaw;this->Pitch = pitch;this->updateCameraVectors();}// Constructor with scalar valuesCamera(GLfloat posX, GLfloat posY, GLfloat posZ, GLfloat upX, GLfloat upY, GLfloat upZ, GLfloat yaw, GLfloat pitch) : Front(glm::vec3(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), MouseSensitivity(SENSITIVTY), Zoom(ZOOM){this->Position = glm::vec3(posX, posY, posZ);this->WorldUp = glm::vec3(upX, upY, upZ);this->Yaw = yaw;this->Pitch = pitch;this->updateCameraVectors();}// Returns the view matrix calculated using Eular Angles and the LookAt Matrixglm::mat4 GetViewMatrix(){return glm::lookAt(this->Position, this->Position + this->Front, this->Up);}// Processes input received from any keyboard-like input system. Accepts input parameter in the form of camera defined ENUM (to abstract it from windowing systems)void ProcessKeyboard(Camera_Movement direction, GLfloat deltaTime){GLfloat velocity = this->MovementSpeed * deltaTime;if (direction == FORWARD)this->Position += this->Front * velocity;if (direction == BACKWARD)this->Position -= this->Front * velocity;if (direction == LEFT)this->Position -= this->Right * velocity;if (direction == RIGHT)this->Position += this->Right * velocity;}// Processes input received from a mouse input system. Expects the offset value in both the x and y direction.void ProcessMouseMovement(GLfloat xoffset, GLfloat yoffset, GLboolean constrainPitch = true){xoffset *= this->MouseSensitivity;yoffset *= this->MouseSensitivity;this->Yaw += xoffset;this->Pitch += yoffset;// Make sure that when pitch is out of bounds, screen doesn't get flippedif (constrainPitch){if (this->Pitch > 89.0f)this->Pitch = 89.0f;if (this->Pitch < -89.0f)this->Pitch = -89.0f;}// Update Front, Right and Up Vectors using the updated Eular anglesthis->updateCameraVectors();}// Processes input received from a mouse scroll-wheel event. Only requires input on the vertical wheel-axisvoid ProcessMouseScroll(GLfloat yoffset){if (this->Zoom >= 1.0f && this->Zoom <= 45.0f)this->Zoom -= yoffset;if (this->Zoom <= 1.0f)this->Zoom = 1.0f;if (this->Zoom >= 45.0f)this->Zoom = 45.0f;}private:// Calculates the front vector from the Camera's (updated) Eular Anglesvoid updateCameraVectors(){// Calculate the new Front vectorglm::vec3 front;front.x = cos(glm::radians(this->Yaw)) * cos(glm::radians(this->Pitch));front.y = sin(glm::radians(this->Pitch));front.z = sin(glm::radians(this->Yaw)) * cos(glm::radians(this->Pitch));this->Front = glm::normalize(front);// Also re-calculate the Right and Up vectorthis->Right = glm::normalize(glm::cross(this->Front, this->WorldUp)); // Normalize the vectors, because their length gets closer to 0 the more you look up or down which results in slower movement.this->Up = glm::normalize(glm::cross(this->Right, this->Front));} };- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
轉載請注明出處:http://blog.csdn.net/ylbs110/article/details/52506033
二、 示例
代碼:
#include <iostream> using namespace std; // GLEW #define GLEW_STATIC #include <GL/glew.h> // GLFW #include <GLFW/glfw3.h> // SOIL #include <SOIL\SOIL.h>#include <glm\glm.hpp> #include <glm\gtc\matrix_transform.hpp> #include <glm\gtc\type_ptr.hpp>#include "Shader.h" #include "Camera.h"const GLuint WIDTH = 800, HEIGHT = 600;void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode); GLuint loadTexture(string fileName, GLint REPEAT, GLint FILTER); void do_movement(); void scroll_callback(GLFWwindow* window, double xoffset, double yoffset); void mouse_callback(GLFWwindow* window, double xpos, double ypos); // Shaders const GLchar* vertexShaderSource = "#version 330 core\n" "layout (location = 0) in vec3 position;\n"//頂點數據傳入的坐標 "layout (location = 1) in vec3 color;\n"//頂點數據傳入的顏色 "layout (location = 2) in vec2 texCoord;\n"//頂點數據傳入的顏色 "uniform vec4 offset;\n" "uniform float mixPar;\n" "uniform mat4 model;\n" "uniform mat4 view;\n" "uniform mat4 projection;\n" "out vec3 Color;\n" "out vec2 TexCoord;\n" "out vec4 vertexColor;\n"//將頂點坐標作為顏色傳入片段著色器,測試所得效果 "out float MixPar;\n" "void main()\n" "{\n" "gl_Position =projection * view * model* vec4(position.x, position.y, position.z, 1.0)+offset;\n" "vertexColor=gl_Position*0.2f;\n" "Color=color*0.2f;\n" "TexCoord=texCoord;\n" "MixPar=mixPar;\n" "}\0";const GLchar* fragmentShaderSource = "#version 330 core\n" "out vec4 color;\n" "in vec4 vertexColor;\n" "in vec3 Color;\n" "in vec2 TexCoord;\n" "in float MixPar;\n" "uniform sampler2D ourTexture1;\n" "uniform sampler2D ourTexture2;\n" "void main()\n" "{\n" "color =mix(texture(ourTexture1, TexCoord),texture(ourTexture2, vec2(TexCoord.x,1-TexCoord.y)),MixPar)+vec4(Color, 1.0f)+vertexColor;\n"//合成兩張紋理并對第二張紋理進行翻轉操作,混合比例由上下鍵控制 "}\n\0"; Camera mainCamera; Shader shader;//shader GLuint texContainer, texAwesomeface;//紋理idfloat key_UD = 0.5f;//混合比例 GLuint VBO, VAO;GLfloat deltaTime = 0.0f; // 當前幀遇上一幀的時間差 GLfloat lastFrame = 0.0f; // 上一幀的時間bool keys[1024];GLfloat lastX = 400, lastY = 300; GLfloat scrollSpeed = 0.05f; bool firstMouse = true;glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f); glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f); glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);void shaderInit() {shader = Shader(vertexShaderSource, fragmentShaderSource); } void textureInit() {texContainer = loadTexture("container.jpg", GL_CLAMP_TO_EDGE, GL_LINEAR);texAwesomeface = loadTexture("awesomeface.png", GL_MIRRORED_REPEAT, GL_NEAREST); } GLuint loadTexture(string fileName,GLint REPEAT, GLint FILTER) {//創建紋理GLuint texture;glGenTextures(1, &texture);//綁定紋理glBindTexture(GL_TEXTURE_2D, texture);// 為當前綁定的紋理對象設置環繞、過濾方式glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, FILTER);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, FILTER);//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);// 加載紋理int width, height;unsigned char* image = SOIL_load_image(fileName.c_str(), &width, &height, 0, SOIL_LOAD_RGB);// 生成紋理glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);glGenerateMipmap(GL_TEXTURE_2D);//釋放圖像的內存并解綁紋理對象SOIL_free_image_data(image);glBindTexture(GL_TEXTURE_2D, 0);return texture; }void vertexObjectInit() {//不使用索引緩沖對象用兩個三角形繪制一個梯形// 設置頂點緩存和屬性指針GLfloat vertices[] = {-0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f,0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 0.0f,1.0f, 0.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.0f,1.0f, 1.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.0f,1.0f, 1.0f,-0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f,-0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 0.0f,0.0f, 0.0f,-0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f,0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 0.0f,1.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 0.0f,1.0f, 1.0f,0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 0.0f,1.0f, 1.0f,-0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f,-0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f,-0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f,-0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f,-0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f,-0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f,-0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f,-0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 0.0f,1.0f, 0.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.0f,1.0f, 1.0f,0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 0.0f,0.0f, 1.0f,0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 0.0f,0.0f, 1.0f,0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 0.0f,0.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 0.0f,1.0f, 0.0f,-0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f,0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 0.0f,1.0f, 1.0f,0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 0.0f,1.0f, 0.0f,0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 0.0f,1.0f, 0.0f,-0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f,-0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f,-0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.0f,1.0f, 1.0f,0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 0.0f,1.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 0.0f,1.0f, 0.0f,-0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f,-0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f};//創建索引緩沖對象glGenBuffers(1, &VBO);glGenVertexArrays(1, &VAO);glBindVertexArray(VAO);// 把頂點數組復制到緩沖中供OpenGL使用glBindBuffer(GL_ARRAY_BUFFER, VBO);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);// 位置屬性glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0);glEnableVertexAttribArray(0);// 顏色屬性glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));glEnableVertexAttribArray(1);glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat)));glEnableVertexAttribArray(2);glBindBuffer(GL_ARRAY_BUFFER, 0);// 這個方法將頂點屬性指針注冊到VBO作為當前綁定頂點對象,然后我們就可以安全的解綁glBindVertexArray(0);// 解綁 VAO (這通常是一個很好的用來解綁任何緩存/數組并防止奇怪錯誤的方法) }int main() {//初始化GLFWglfwInit();glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);//創建窗口對象GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr);if (window == nullptr){std::cout << "Failed to create GLFW window" << std::endl;glfwTerminate();return -1;}glfwMakeContextCurrent(window);//注冊鍵盤回調glfwSetKeyCallback(window, key_callback);//注冊鼠標回調glfwSetCursorPosCallback(window, mouse_callback);//注冊鼠標滾輪回到glfwSetScrollCallback(window, scroll_callback);//設置光標隱藏并捕獲glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);//初始化GLEWglewExperimental = GL_TRUE;if (glewInit() != GLEW_OK){std::cout << "Failed to initialize GLEW" << std::endl;return -1;}//告訴OpenGL渲染窗口尺寸大小int width, height;glfwGetFramebufferSize(window, &width, &height);glViewport(0, 0, width, height);glEnable(GL_DEPTH_TEST);//初始化并綁定shadersshaderInit();//初始化texturestextureInit();//初始化頂點對象數據vertexObjectInit();mainCamera = Camera();//讓窗口接受輸入并保持運行while (!glfwWindowShouldClose(window)){GLfloat currentFrame = glfwGetTime();deltaTime = currentFrame - lastFrame;lastFrame = currentFrame;//檢查事件glfwPollEvents();do_movement();//渲染指令glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//設置根據時間變換的x,y偏移值,最終效果為圓周運動GLfloat timeValue = glfwGetTime();GLfloat offsetx = (sin(timeValue) / 2) + 0.5;GLfloat offsety = (cos(timeValue) / 2) + 0.5;//繪制長方形 shader.Use();//綁定兩張貼圖glActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_2D, texContainer);glUniform1i(glGetUniformLocation(shader.Program, "ourTexture1"), 0);glActiveTexture(GL_TEXTURE1);glBindTexture(GL_TEXTURE_2D, texAwesomeface);glUniform1i(glGetUniformLocation(shader.Program, "ourTexture2"), 1);// 更新uniform值//設置運動軌跡//GLint vertexorangeLocation = glGetUniformLocation(shader.Program, "offset");//glUniform4f(vertexorangeLocation, offsetx, offsety, 0.0f, 1.0f);//設置混合比例GLint mixPar = glGetUniformLocation(shader.Program, "mixPar");glUniform1f(mixPar, key_UD);glm::mat4 model;model = glm::rotate(model, (GLfloat)glfwGetTime() * 5.0f, glm::vec3(0.5f, 1.0f, 0.0f));glm::mat4 view;view = mainCamera.GetViewMatrix();glm::mat4 projection;projection = glm::perspective(mainCamera.Zoom*scrollSpeed, (float)(WIDTH / HEIGHT), 0.1f, 100.0f);GLint modelLoc = glGetUniformLocation(shader.Program, "model");glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));GLint viewLoc = glGetUniformLocation(shader.Program, "view");glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));GLint projectionLoc = glGetUniformLocation(shader.Program, "projection");glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection));glm::vec3 cubePositions[] = {glm::vec3(0.0f, 0.0f, 0.0f),glm::vec3(2.0f, 5.0f, -15.0f),glm::vec3(-1.5f, -2.2f, -2.5f),glm::vec3(-3.8f, -2.0f, -12.3f),glm::vec3(2.4f, -0.4f, -3.5f),glm::vec3(-1.7f, 3.0f, -7.5f),glm::vec3(1.3f, -2.0f, -2.5f),glm::vec3(1.5f, 2.0f, -2.5f),glm::vec3(1.5f, 0.2f, -1.5f),glm::vec3(-1.3f, 1.0f, -1.5f)};glBindVertexArray(VAO);for (GLuint i = 0; i < 10; i++){glm::mat4 model;model = glm::translate(model, cubePositions[i]);if (i < 4) { GLfloat angle = (GLfloat)glfwGetTime()*5.0f * i;model = glm::rotate(model, angle, glm::vec3(1.0f, 0.3f, 0.5f));glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));}else{glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));}glDrawArrays(GL_TRIANGLES, 0, 36);}glBindVertexArray(0);//交換緩沖glfwSwapBuffers(window);}glDeleteVertexArrays(1, &VAO);glDeleteBuffers(1, &VBO);//釋放資源glfwTerminate();return 0; } void do_movement() {// 攝像機控制GLfloat cameraSpeed = 5.0f* deltaTime;if (keys[GLFW_KEY_W])mainCamera.ProcessKeyboard(FORWARD, deltaTime);if (keys[GLFW_KEY_S])mainCamera.ProcessKeyboard(BACKWARD, deltaTime);if (keys[GLFW_KEY_A])mainCamera.ProcessKeyboard(LEFT, deltaTime);if (keys[GLFW_KEY_D])mainCamera.ProcessKeyboard(RIGHT, deltaTime); } void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) {// 當用戶按下ESC鍵,我們設置window窗口的WindowShouldClose屬性為true// 關閉應用程序if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)glfwSetWindowShouldClose(window, GL_TRUE);if (key == GLFW_KEY_UP&& action == GLFW_PRESS)//按下UP鍵增加混合比例key_UD = key_UD + 0.1f;if (key == GLFW_KEY_DOWN&& action == GLFW_PRESS)//按下DOWN減小混合比例key_UD = key_UD - 0.1f;if (action == GLFW_PRESS)keys[key] = true;else if (action == GLFW_RELEASE)keys[key] = false; } void mouse_callback(GLFWwindow* window, double xpos, double ypos) {if (firstMouse){lastX = xpos;lastY = ypos;firstMouse = false;}GLfloat xoffset = xpos - lastX;GLfloat yoffset = lastY - ypos; // Reversed since y-coordinates go from bottom to left lastX = xpos;lastY = ypos;mainCamera.ProcessMouseMovement(xoffset, yoffset); }void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) {cout << yoffset << endl;mainCamera.ProcessMouseScroll(yoffset); }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278
- 279
- 280
- 281
- 282
- 283
- 284
- 285
- 286
- 287
- 288
- 289
- 290
- 291
- 292
- 293
- 294
- 295
- 296
- 297
- 298
- 299
- 300
- 301
- 302
- 303
- 304
- 305
- 306
- 307
- 308
- 309
- 310
- 311
- 312
- 313
- 314
- 315
- 316
- 317
- 318
- 319
- 320
- 321
- 322
- 323
- 324
- 325
- 326
- 327
- 328
- 329
- 330
- 331
- 332
- 333
- 334
- 335
- 336
- 337
- 338
- 339
- 340
- 341
- 342
- 343
- 344
- 345
- 346
- 347
- 348
- 349
- 350
- 351
- 352
- 353
- 354
- 355
- 356
- 357
- 358
- 359
- 360
- 361
- 362
- 363
- 364
- 365
- 366
- 367
- 368
- 369
- 370
- 371
- 372
- 373
- 374
- 375
- 376
- 377
- 378
- 379
- 380
- 381
- 382
- 383
- 384
結果:
wsad可以控制上下左右,鼠標控制攝像頭方向,滾輪可以拉伸:?
總結
以上是生活随笔為你收集整理的OpenGL--摄像机的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 零知识证明(zero-knowledge
- 下一篇: 硬盘克隆大师从入门到精通