[LearnOpenGL]照相机的变换、坐标系、摄像机
前言
跟着LearnOpenGL上学着做项目,的确对于知识掌握得更清晰一些了。
第一个项目
第一个项目,是关于简单的熟悉矩阵变换的,创建了10个立方体,代码如下。
// 视图矩阵,看作是一个照相机
glm::mat4 view;
view = glm::translate(view, glm::vec3(0.0f, 0.0f, -6.0f));
view = glm::rotate(view, glm::radians(15.0f), glm::vec3(0.0f, 0.0f, 1.0f));
// 模型矩阵
glm::mat4 projection;
projection = glm::perspective(glm::radians(45.0f), static_cast<GLfloat>(WIDTH) / static_cast<GLfloat>(HEIGHT), 0.001f, 100.0f);
glUniformMatrix4fv(glGetUniformLocation(shader.program, "view"), 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(glGetUniformLocation(shader.program, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
while (!glfwWindowShouldClose(window))
{
glfwPollEvents();
// 因为已经涉及到了3d,所以需要开启深度测试,并且要每一帧都要清除颜色缓存和深度缓存
glClearColor(0.298f, 0.451f, 0.773f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindVertexArray(VAO);
// 创建10个正方体
for (GLuint i = 0; i < 10; ++i) {
glm::mat4 model;
model = glm::translate(model, cubePositions[i]);
if (i % 2) {
// 固定的旋转的角度
model = glm::rotate(model, glm::radians(20.0f * i), glm::vec3(0.0f, 0.3f, 0.5f));
}
else {
// 随时间旋转的角度
model = glm::rotate(model, glm::radians<GLfloat>(glfwGetTime() * 20.0f), glm::vec3(0.0f, 1.0f, 0.5f));
}
glUniformMatrix4fv(glGetUniformLocation(shader.program, "model"), 1, GL_FALSE, glm::value_ptr(model));
// 一个四边形由两个三角形组成,两个三角形则包括了6个索引,所以6个面则需要36个索引
glDrawArrays(GL_TRIANGLES, 0, 36);
}
glBindVertexArray(0);
glfwSwapBuffers(window);
}
第二个项目
这个项目稍微复杂,涉及到了坐标系,摄像机的知识。
#include <iostream>
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "SOIL.h"
#include "Shader.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
const GLuint WIDTH = 800, HEIGHT = 600;
GLfloat mixValue = 0.2f;
//------------------------------------2.----------------------------------
glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f);
// 为什么是负的呢,因为要知道摄像机指向的是z轴的负方向
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);
//------------------------------------3.----------------------------------
bool keys[1024];//用来存储哪些按键被按下
//------------------------------------4.----------------------------------
GLfloat deltaTime = 0.0f; //当前帧和上一帧的时间差
GLfloat lastFrame = 0.0f; //上一帧时间
//------------------------------------5.----------------------------------
GLfloat yaw = -90.0f; // Yaw is initialized to -90.0 degrees since a yaw of 0.0 results in a direction vector pointing to the right (due to how Eular angles work) so we initially rotate a bit to the left.
//为偏航角
GLfloat pitch = 0.0f; //为俯仰角
GLfloat lastX = WIDTH / 2.0;
GLfloat lastY = HEIGHT / 2.0;
bool firstMouse = true;
GLfloat fov = 1.0f;
void isDoMovement() {
//------------------------------------3.----------------------------------
// GLfloat speed = 0.2f;
//------------------------------------4.----------------------------------
GLfloat speed = 5.0f * deltaTime;
// 照相机向z轴负方向移动
if (keys[GLFW_KEY_W]) {
cameraPos += cameraFront * speed;
}
// 照相机向z轴正方向移动
else if (keys[GLFW_KEY_S]) {
cameraPos -= cameraFront * speed;
}
// 照相机向x轴负方向
else if (keys[GLFW_KEY_A]) {
//cross表示叉乘,求出对于参数中的两个向量都垂直的向量,求完了以后还需要进行归一化得到向量
cameraPos -= glm::normalize(glm::cross(cameraFront, cameraUp)) * speed;
}
// 照相机向x轴正方向
else if (keys[GLFW_KEY_D]) {
cameraPos += glm::normalize(glm::cross(cameraFront, cameraUp)) * speed;
}
}
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) {
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
glfwSetWindowShouldClose(window, GL_TRUE);
}
// if (key == GLFW_KEY_UP && action == GLFW_PRESS)
// {
// mixValue += 0.1f;
// if (mixValue >= 1.0f)
// mixValue = 1.0f;
// }
// if (key == GLFW_KEY_DOWN && action == GLFW_PRESS)
// {
// mixValue -= 0.1f;
// if (mixValue <= 0.0f)
// mixValue = 0.0f;
// }
//------------------------------------2.----------------------------------
// GLfloat speed = 0.2f;
//
// // 照相机向z轴负方向移动
// if (key == GLFW_KEY_W) {
// cameraPos += cameraFront * speed;
// }
// // 照相机向z轴正方向移动
// else if (key == GLFW_KEY_S) {
// cameraPos -= cameraFront * speed;
// }
// // 照相机向x轴负方向
// else if (key == GLFW_KEY_A) {
// //cross表示叉乘,求出对于参数中的两个向量都垂直的向量,求完了以后还需要进行归一化得到向量
// cameraPos -= glm::normalize(glm::cross(cameraFront, cameraUp)) * speed;
// }
// // 照相机向x轴正方向
// else if (key == GLFW_KEY_D) {
// cameraPos += glm::normalize(glm::cross(cameraFront, cameraUp)) * speed;
// }
//------------------------------------3.----------------------------------
// 在第三种方法中,这个函数用来监听
// 先判断有没有按下,不再按下的时候,把该按下的按键进行重置
if(action == GLFW_PRESS) {
// 照相机向z轴负方向移动
if (key == GLFW_KEY_W) {
keys[key] = true;
}
// 照相机向z轴正方向移动
else if (key == GLFW_KEY_S) {
keys[key] = true;
}
// 照相机向x轴负方向
else if (key == GLFW_KEY_A) {
//cross表示叉乘,求出对于参数中的两个向量都垂直的向量,求完了以后还需要进行归一化得到向量
keys[key] = true;
}
// 照相机向x轴正方向
else if (key == GLFW_KEY_D) {
keys[key] = true;
}
}
else if(action == GLFW_RELEASE) {
keys[key] = false;
}
}
//------------------------------------5.----------------------------------
// 其中的xpos和ypos代表的是鼠标x和y的位置,摄像头上下左右指向
void mouse_callback(GLFWwindow* window, double xpos, double ypos) {
// 第一次移动鼠标
if(firstMouse)
{
//对上一帧x和y的方向上的位置进行赋值
lastX = xpos;
lastY = ypos;
firstMouse = false;
}
GLfloat xoffset = xpos - lastX;//计算x轴上的偏移量
GLfloat yoffset = lastY - ypos;//计算y轴上的偏移量
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));//同求z的原理
front.y = sin(glm::radians(pitch)); // 以xz作为一个平面,y轴向上,形成一个三角形,可以用sin求出俯仰角的移动
front.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch));// cos则可以求出xz平面,其中xz平面,z轴向上,x轴向右,可以根据sin偏航角计算出z
cameraFront = glm::normalize(front); //归一化
}
//摄像头靠近或者进行远离
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{
if(fov >= 1.0f && fov <= 45.0f)
fov -= yoffset * 0.05f; //如果在规定的fov范围,可以进行减小,超过则进行重置
if(fov <= 1.0f)
fov = 1.0f;
if(fov >= 45.0f)
fov = 45.0f;
}
int main() {
glfwInit();
// 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, "OpenGL", 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);
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
glfwSetScrollCallback(window, scroll_callback);
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK)
{
std::cout << "Failed to initialize GLEW" << std::endl;
return -1;
}
glViewport(0, 0, WIDTH, HEIGHT);
// ¯ÂȉÂ˚
Shader shader("/Users/staff/Desktop/practise/fgh/fgh/vertexShader.vsh", "/Users/staff/Desktop/practise/fgh/fgh/fragmentShader.fsh");
// ÚÂÍÒÚÛ‡ 1
GLuint texture1;
glGenTextures(1, &texture1);
glBindTexture(GL_TEXTURE_2D, texture1);
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("/Users/staff/Desktop/practise/fgh/fgh/wall.jpg", &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);
// ÚÂÍÒÚÛ‡ 2
GLuint texture2;
glGenTextures(1, &texture2);
glBindTexture(GL_TEXTURE_2D, texture2);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
image = SOIL_load_image("/Users/staff/Desktop/practise/fgh/fgh/awesomeface.png", &width, &height, 0, SOIL_LOAD_RGBA);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
SOIL_free_image_data(image);
glBindTexture(GL_TEXTURE_2D, 0);
// 6个面上的顶点信息
GLfloat vertices[] = {
// Positions // Texture Coords //colors
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f
};
GLuint VBO, VAO, EBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
GLuint _positionSlot = glGetAttribLocation(shader.program, "position");
GLuint _colorSlot = glGetAttribLocation(shader.program, "color");
GLuint _textureCoordsSlot = glGetAttribLocation(shader.program, "texCoord");
//GLuint _textureSlot = glGetUniformLocation(shader.program, "ourTexture");
glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(_positionSlot);
glVertexAttribPointer(_textureCoordsSlot, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(_textureCoordsSlot);
glVertexAttribPointer(_colorSlot, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat)));
glEnableVertexAttribArray(_colorSlot);
glBindVertexArray(0);
// 10个立方体的位置
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)
};
while (!glfwWindowShouldClose(window))
{
glfwPollEvents();
//------------------------------------4.----------------------------------
GLfloat curTime = glfwGetTime();
deltaTime = curTime - lastFrame;
lastFrame = curTime;
//------------------------------------3.----------------------------------
isDoMovement();
// 因为已经涉及到了3d,所以需要开启深度测试,并且要每一帧都要清除颜色缓存和深度缓存
glClearColor(0.298f, 0.451f, 0.773f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
shader.use();
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture1);
glUniform1i(glGetUniformLocation(shader.program, "ourTexture1"), 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture2);
glUniform1i(glGetUniformLocation(shader.program, "ourTexture2"), 1);
glUniform1f(glGetUniformLocation(shader.program, "mixValue"), mixValue);
//----------------------------------------1.-------------------------------------------
glm::mat4 view;
// 照相机向量
// GLfloat radius = 20.0f;
// GLfloat camX = sinf(glfwGetTime()) * radius;
// GLfloat camZ = cosf(glfwGetTime()) * radius;
// // 首先要知道lookAt函数的参数的意思,分别是eye,center,up,分别代表的是摄像机的位置向量,目标,上向量
// // 这里实现的是照相机绕着顶点(0,0,0)进行旋转
// view = glm::lookAt(glm::vec3(camX, 0.0f, camZ), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
//----------------------------------------2.-------------------------------------------
//view = glm::lookAt(cameraPos, glm::vec3(0.0f, 0.0f, 0.0f), cameraUp);
//----------------------------------------5.-------------------------------------------
view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);
// 模型矩阵
glm::mat4 projection;
// projection = glm::perspective(glm::radians(45.0f), static_cast<GLfloat>(WIDTH) / static_cast<GLfloat>(HEIGHT), 0.001f, 100.0f);
//----------------------------------------5.-------------------------------------------
projection = glm::perspective(fov, (GLfloat)WIDTH/(GLfloat)HEIGHT, 0.1f, 100.0f);
glUniformMatrix4fv(glGetUniformLocation(shader.program, "view"), 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(glGetUniformLocation(shader.program, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
glBindVertexArray(VAO);
// 创建10个正方体
for (GLuint i = 0; i < 10; ++i) {
glm::mat4 model;
model = glm::translate(model, cubePositions[i]);
if (i % 2) {
// 固定的旋转的角度
model = glm::rotate(model, glm::radians(20.0f * i), glm::vec3(0.0f, 0.3f, 0.5f));
}
else {
// 随时间旋转的角度
model = glm::rotate(model, glm::radians<GLfloat>(glfwGetTime() * 20.0f), glm::vec3(0.0f, 1.0f, 0.5f));
}
glUniformMatrix4fv(glGetUniformLocation(shader.program, "model"), 1, GL_FALSE, glm::value_ptr(model));
// 一个四边形由两个三角形组成,两个三角形则包括了6个索引,所以6个面则需要36个索引
glDrawArrays(GL_TRIANGLES, 0, 36);
}
glBindVertexArray(0);
glfwSwapBuffers(window);
}
// Û‰‡ÎˇÂÏ, Á‡‚¯‡ÂÏ
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
glfwTerminate();
return 0;
}
这里面的1,2,3,4,5分别是版本的演化;
- 其中1是最开始的版本:增加了照相机向量,不过是固定的;
- 其中2是增加了摄像机移动的功能;
- 其中3是因为2无法实现同时按下两个按键进行移动的功能,因为用数组进行记录,最后统一处理;
- 其中4是因为3中的移动距离在每个机器上都不太一样,有的会在同一时间段内比其他人绘制更多帧,导致运动速度会变得大,造成效果不好,因此,增加时间差,记录时间差,乘以固定的值,如果时间差变大时,意味着上一帧渲染时间多,那就会得到更高的移动速度,否之,则相反。这样就会和上一帧平衡了。这就好比走路和跑步,跑步的移动速度肯定是要高于走路,总不能要求走路和跑步的移动速度是一样的吧。
- 其中5则在之前的基础上增加了上下左右移动摄像机,以及通过滚轮实现靠近和远离的功能。这里面涉及到了许多的数学知识,不过不是很难,仔细看看教程还是能看懂的。
第二个项目的延伸
之所以说是延伸是因为,第二个项目所有东西都堆在了一起,耦合程度高,因此教程把这些都封装了起来。
.h文件
#pragma once
#include <vector>
#include <GL/glew.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
enum Camera_Movement {
FORWARD,
BACKWARD,
LEFT,
RIGHT
};
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;
class Camera {
public:
glm::vec3 Position;
glm::vec3 Front;
glm::vec3 Up;
glm::vec3 Right;
glm::vec3 WorldUp;
GLfloat Yaw;
GLfloat Pitch;
GLfloat MovementSpeed;
GLfloat MouseSensitivity;
GLfloat Zoom;
Camera(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);
Camera(GLfloat posX, GLfloat posY, GLfloat posZ, GLfloat upX, GLfloat upY, GLfloat upZ, GLfloat yaw, GLfloat pitch);
glm::mat4 GetViewMatrix();
// 处理按键事件
void ProcessKeyboard(Camera_Movement direction, GLfloat deltaTime);
// 处理鼠标移动事件
void ProcessMouseMovement(GLfloat xoffset, GLfloat yoffset, GLboolean constrainPitch = true);
// 处理鼠标滚动事件
void ProcessMouseScroll(GLfloat yoffset);
private:
void updateCameraVectors();
};
.cpp文件
#include "Camera.h"
Camera::Camera(glm::vec3 position, glm::vec3 up, GLfloat yaw, GLfloat pitch)
: Front(glm::vec3(0.0f, 0.0f, -1.0f))
, MovementSpeed(SPEED)
, MouseSensitivity(SENSITIVTY)
, Zoom(ZOOM)
{
Position = position;
WorldUp = up;
Yaw = yaw;
Pitch = pitch;
updateCameraVectors();
}
Camera::Camera(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)
{
Position = glm::vec3(posX, posY, posZ);
WorldUp = glm::vec3(upX, upY, upZ);
Yaw = yaw;
Pitch = pitch;
updateCameraVectors();
}
glm::mat4 Camera::GetViewMatrix() {
return glm::lookAt(Position, Position + Front, Up);
}
void Camera::ProcessKeyboard(Camera_Movement direction, GLfloat deltaTime) {
GLfloat velocity = MovementSpeed * deltaTime;
if (direction == FORWARD)
Position += glm::normalize(glm::cross(WorldUp, Right)) * velocity;
if (direction == BACKWARD)
Position -= glm::normalize(glm::cross(WorldUp, Right)) * velocity;
if (direction == LEFT)
Position -= Right * velocity;
if (direction == RIGHT)
Position += Right * velocity;
}
void Camera::ProcessMouseMovement(GLfloat xoffset, GLfloat yoffset, GLboolean constrainPitch) {
xoffset *= MouseSensitivity;
yoffset *= MouseSensitivity;
Yaw += xoffset;
Pitch += yoffset;
if (constrainPitch) {
if (Pitch > 89.0f)
Pitch = 89.0f;
if (Pitch < -89.0f)
Pitch = -89.0f;
}
updateCameraVectors();
}
void Camera::ProcessMouseScroll(GLfloat yoffset) {
if (Zoom >= 1.0f && Zoom <= 45.0f)
Zoom -= yoffset;
if (Zoom <= 1.0f)
Zoom = 1.0f;
if (Zoom >= 45.0f)
Zoom = 45.0f;
}
void Camera::updateCameraVectors() {
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));
Front = glm::normalize(front);
Right = glm::normalize(glm::cross(Front, WorldUp));
Up = glm::normalize(glm::cross(Right, Front));
}
[LearnOpenGL]照相机的变换、坐标系、摄像机的更多相关文章
- Codeforces Gym 100531J Joy of Flight 变换坐标系
Joy of Flight 题目连接: http://codeforces.com/gym/100531/attachments Description Jacob likes to play wit ...
- OPENGL_变换与坐标系
参考:http://blog.csdn.net/kandyer/article/details/12449973 坐标系 世界坐标系:绝对坐标 物体坐标系:以物体自身为原点的坐标系 摄像机坐标系:以摄 ...
- 理解SVG坐标系统和变换: transform属性
SVG元素可以通过缩放,移动,倾斜和旋转来变换-类似HTML元素使用CSS transform来变换.然而,当涉及到坐标系时这些变换所产生的影响必然有一定差别.在这篇文章中我们讨论SVG的transf ...
- View Transform(视图变换)详解
http://www.cnblogs.com/graphics/archive/2012/07/12/2476413.html 什么是View Transform 我们可以用照相机的原理来阐释3D图形 ...
- (转)View Transform(视图变换)详解
原文作者讲得太好了,唯有这篇让我对视图矩阵了解的清晰了很多. --------------------------------------------------------------------- ...
- 【3D研发笔记】之【数学相关】(一):坐标系
现在开始学习3D基础相关的知识,本系列的数学相关笔记是基于阅读书籍<3D数学基础:图形与游戏开发>而来,实现代码使用AS3,项目地址是:https://github.com/hammerc ...
- OpenGL 的空间变换(下):空间变换
通过本文的上篇 OpenGL 的空间变换(上):矩阵在空间几何中的应用 ,我们了解到矩阵的基础概念.并且掌握了矩阵在空间几何中的应用.接下来,我们将结合矩阵来了解 OpenGL 的空间变换. 在使用 ...
- DirectX11 With Windows SDK--10 摄像机类
前言 DirectX11 With Windows SDK完整目录:http://www.cnblogs.com/X-Jun/p/9028764.html 由于考虑后续的项目需要有一个比较好的演示环境 ...
- OpenGL坐标系的理解
搬运自: https://learnopengl-cn.github.io/01%20Getting%20started/08%20Coordinate%20Systems/#3d 为了将坐标从一个坐 ...
随机推荐
- Mysql_Learning_Notes_mysql系统结构_2
Mysql_Learning_Notes_mysql系统结构_2 三层体系结构,启动方式,日志类型及解析方法,mysql 升级 连接层 通信协议处理\线程处理\账号认证(用户名和密码认证)\安全检查等 ...
- Linux下简单粗暴使用rsync实现文件同步备份【转】
这篇来说说如何安全的备份,还有一点不同的是上一篇是备份服务器拉取数据,这里要讲的是主服务器如何推送数据实现备份. 一.备份服务器配置rsync文件 vim /etc/rsyncd.conf #工作中指 ...
- 2013 NEERC
2013 NEERC Problem A. ASCII Puzzle 题目描述:完成一个拼图. solution 暴搜,但好像挺难打的,但听说因为题目限制比较多,其实很多奇怪的情况都不存在. Prob ...
- OpenStack Benchmark - Rally
作为以基于OpenStack的云平台的基准测试工具 -- Rally, 其功能不仅是测试云的性能&&稳定性, 还可以安装OpenStack,以及以良好的表现形式(web 页面)展现测试 ...
- Mac上删除不了的文件,Windows上也粉碎不了怎么办?
推荐一个Mac上的软件:Tuxera Disk Manager 用法很简单:选择删除文件原来所在的文件进行维护就可以了. 维护之后,在废纸篓中清除,成功.
- 数据库-mysql触发器
MySQL包含对触发器的支持.触发器是一种与表操作有关的数据库对象,当触发器所在表上出现指定事件时,将调用该对象,即表的操作事件触发表上的触发器的执行. 一:创建触发器 在MySQL中,创建触发器语法 ...
- 【Android开发日记】之入门篇(六)——Android四大组件之Broadcast Receiver
广播接受者是作为系统的监听者存在着的,它可以监听系统或系统中其他应用发生的事件来做出响应.如设备开机时,应用要检查数据的变化状况,此时就可以通过广播来把消息通知给用户.又如网络状态改变时,电量变化时都 ...
- java 二叉树遍历
package com.lever; import java.util.LinkedList;import java.util.Queue; /** * 二叉树遍历 * @author lckxxy ...
- Linux基础 - crontab
列出当前用户设置的定时任务 crontab -l 编辑定时任务 crontab -e 用法 m h dom mon dow * * * * * command 字段详解: *:any m: minut ...
- django使用RestFramework的Token认证
今天实现的想法有点不正规: Django Rest framework的框架的认证,API都运行良好. 现在是要自己写一个function来实现用户的功能. 而不是用Rest 框架里的APIVIEW这 ...