OpenGL原理与实践——核心模式(四):摄像机变换理论与应用
创始人
2024-02-15 00:26:14
0

目录

变换是什么?对于OpenGL的摄像机又意味着什么?

MVP变换

投影变换

正交投影变换

透视投影变换 

摄像机/投影矩阵的应用

绘制单个立方体——源码及渲染结果

绘制多个立方体——源码及渲染结果

构建摄像机类——实现控制摄像机移动

摄像机坐标系的构成

摄像机坐标系的参数构建

摄像机关键参数提取(移动参数)

摄像机平移功能实现

构建摄像机类——实现控制摄像机旋转

摄像机front向量的xyz

鼠标跟踪控制方法分解 

摄像机旋转功能实现


变换是什么?对于OpenGL的摄像机又意味着什么?

答:就是将三维物体映射到摄像机屏幕的过程。

 在线性代数中,变换=矩阵,任何3D变化都可以通过矩阵来表示。 

MVP变换

那么问题来了,如何将三维物体映射到屏幕空间呢?

答:经过MVP变换。

这里不对MVP变换做过多的展开,详细理论可参考GAMES101的课程。

那么如何变换呢?如何获得物体在观察坐标系下的位置呢?

不失一般性,我们考虑一个简单的情况,即观察坐标系与世界坐标系平行:

  •  首先我们将观察坐标系平移变换到世界坐标系原点,那么会有一个对应的矩阵
  • 我们用同样的矩阵,对物体做一次变换,即可得到物体在观察坐标系下的位置

但更一般的情况是:摄像机空间与世界空间存在一定的角度:

那此时如何得到物体在摄像机空间的相对位置呢?

答:可以将摄像机移动到世界坐标系原点,然后将摄像机坐标系的三个正交基旋转至与世界坐标系重合。

但问题来了,如何获得这个旋转矩阵呢?这个矩阵并不好算。

但我们可以曲线救国,利用矩阵的逆。

既然直接求摄像机空间旋转至世界空间不好求,那我们可以把世界空间旋转至摄像机空间,并获得一个矩阵,然后再求这个矩阵的逆,即为摄像机空间旋转至世界空间的变换矩阵。

投影变换

投影分两种:

投影变换的目标是:将空间中的点P变换到摄像机平面坐标系内,并且做成NDC(标准设备坐标)的形式。NDC为了兼容不同窗口的宽高,让x与y的都同一到(-1,1)范围内,之后各自乘以宽高

正交投影变换

透视投影变换 

 

空间中的点投射到屏幕近剪裁平面的坐标。

过多的数学推导这里不做展示,直接给出结果:

 

 

摄像机/投影矩阵的应用

下载并载入glm第三方库:

类似之前实践的思路,我们需要更改和设置:

  • 设置glm::mat4 初始化view摄像机矩阵和proj投影矩阵
  • 设置好需要绘制的正方体六个面
  • 处理相应锚点并激活,这里不需要索引处理了
  • 在shader中添加设置矩阵的方法
  • 在render()中,利用glm设置相应矩阵,并开启深度测试

绘制单个立方体——源码及渲染结果

#include "Base.h"
#include "Shader.h"
#include "ffImage.h"void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);
void initModel();
void initShader(const char* _vertexPath, const char* _fragPath);
void initTexture();
void render();unsigned int VBO = 0;
unsigned int VAO = 0;
unsigned int EBO = 0;
unsigned int _texture = 0;Shader _shader;
ffImage* _pImage = nullptr;glm::mat4 _viewMatrix(1.0f);
glm::mat4 _projMatrix(1.0f);
int _width = 800;
int _height = 600;int main() {//初始化OpenGL上下文环境,OpenGL是一个状态机,会保存当前状态下的渲染状态以及管线的状态glfwInit(); //,3版本以上glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//用OpenGL核心开发模式glfwWindowHint(GLFW_OPENGL_PROFILE,GLFW_OPENGL_CORE_PROFILE);//创建窗体GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGl Core", nullptr, nullptr);if (window == nullptr) {std::cout << "Failed to create GLFW window" << std::endl;glfwTerminate();return -1;}//把当前上下文绑定至当前窗口glfwMakeContextCurrent(window);//通过glad绑定各种函数指针if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {std::cout << "Failed to initialize GLAD" << std::endl;return -1;}//视口:需要渲染的东西在哪里glViewport(0, 0, _width, _height);//当Frame大小变动,调用回调函数调整视口大小glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);initModel();initShader("vertexShader.glsl", "fragmentShader.glsl");initTexture();//防止窗口结束退出while (!glfwWindowShouldClose(window)) {processInput(window);render();//双缓冲glfwSwapBuffers(window);glfwPollEvents();}//结束,释放资源glfwTerminate();return 0;}void framebuffer_size_callback(GLFWwindow* window, int width, int height) {glViewport(0, 0, width, height);
}void processInput(GLFWwindow* window) {if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {glfwSetWindowShouldClose(window, true);}
}//渲染
void render() {//擦除画布,用定义的颜色填充glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glEnable(GL_DEPTH_TEST);//眼睛(摄像机)位置,看向位置,摄像机上方位置_viewMatrix = glm::lookAt(glm::vec3(3.0f, 3.0f, 3.0f),glm::vec3(0.0f, 0.0f, 0.0f),glm::vec3(0.0f, 1.0f, 0.0f));//透视投影矩阵:视锥角,宽高比,近平面,远平面_projMatrix = glm::perspective(glm::radians(45.0f),(float)_width / (float)_height,0.1f,100.0f);glBindTexture(GL_TEXTURE_2D, _texture);_shader.start();_shader.setMatrix("_viewMatrix", _viewMatrix);_shader.setMatrix("_projMatrix", _projMatrix);glBindVertexArray(VAO);glDrawArrays(GL_TRIANGLES, 0, 36);_shader.end();
}//构建模型数据:VBO,VAO
void initModel() {//float vertices[] = {//	//顶点信息				颜色信息			纹理信息//	0.5f, 0.5f, 0.0f,		1.0f,0.0f,0.0f,		1.0f,1.0f,//	0.5f, -0.5f, 0.0f,	 	0.0f,1.0f,0.0f,		1.0f,0.0f,//	-0.5f, -0.5f, 0.0f,		0.0f,0.0f,1.0f,		0.0f,0.0f,//	-0.5f, 0.5f, 0.0f,		0.0f,1.0f,0.0f,		0.0f,1.0f//};float vertices[] = {//第一个面,六个顶点两个三角形-0.5f, -0.5f, -0.5f,  0.0f, 0.0f,0.5f, -0.5f, -0.5f,  1.0f, 0.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,-0.5f,  0.5f, -0.5f,  0.0f, 1.0f,-0.5f, -0.5f, -0.5f,  0.0f, 0.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,0.5f, -0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 1.0f,0.5f,  0.5f,  0.5f,  1.0f, 1.0f,-0.5f,  0.5f,  0.5f,  0.0f, 1.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,-0.5f,  0.5f,  0.5f,  1.0f, 0.0f,-0.5f,  0.5f, -0.5f,  1.0f, 1.0f,-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,-0.5f,  0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,0.5f, -0.5f, -0.5f,  0.0f, 1.0f,0.5f, -0.5f, -0.5f,  0.0f, 1.0f,0.5f, -0.5f,  0.5f,  0.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,0.5f, -0.5f, -0.5f,  1.0f, 1.0f,0.5f, -0.5f,  0.5f,  1.0f, 0.0f,0.5f, -0.5f,  0.5f,  1.0f, 0.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,-0.5f,  0.5f, -0.5f,  0.0f, 1.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,-0.5f,  0.5f,  0.5f,  0.0f, 0.0f,-0.5f,  0.5f, -0.5f,  0.0f, 1.0f};glGenVertexArrays(1, &VAO);glBindVertexArray(VAO);//之后的VBO便属于了VAO的管理范围glGenBuffers(1, &VBO);//绑定哪一种buffer, glBindBuffer(GL_ARRAY_BUFFER, VBO);//分配显存:分配哪种buffer,分配显存大小,分配地址,使用数据的方式glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//对哪个锚点进行操作:layout=0的锚点,读3个顶点,类型为float,不需要归一化,每次步长为3个float大小,从0处开始读glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(sizeof(float)*3));//打开锚点:激活glEnableVertexAttribArray(0);glEnableVertexAttribArray(1);//解绑glBindBuffer(GL_ARRAY_BUFFER, 0);glBindVertexArray(0);
}//
void initShader(const char* _vertexPath, const char* _fragPath) {_shader.initShader(_vertexPath, _fragPath);
}void initTexture() {_pImage = ffImage::readFromFile("res/wall.jpg");//纹理绑定glGenTextures(1, &_texture);glBindTexture(GL_TEXTURE_2D, _texture);//纹理属性设置glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);//读入图片数据glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _pImage->getWidth(), _pImage->getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE,_pImage->getData());
}
//vertexShader.glsl
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aUV;out vec2 outUV;uniform mat4 _modelMatrix;
uniform mat4 _viewMatrix;
uniform mat4 _projMatrix;void main()
{gl_Position = _projMatrix * _viewMatrix * _modelMatrix * vec4(aPos.x, aPos.y, aPos.z, 1.0);outUV = aUV;
};
//fragmentShader.glsl
#version 330 core
out vec4 FragColor;in vec2 outUV;uniform sampler2D outTexture;void main()
{FragColor = texture(outTexture, outUV) ;
};

 

绘制多个立方体——源码及渲染结果

这里绘制10个立方体,对每一个立方体先进行一个平移操作,并且进行旋转操作

//渲染
void render() {//擦除画布,用定义的颜色填充glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glEnable(GL_DEPTH_TEST);glm::vec3 modelVecs[] = {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)};_viewMatrix = glm::lookAt(glm::vec3(0.0f, 0.0f, 3.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));_projMatrix = glm::perspective(glm::radians(45.0f), (float)_width / (float)_height, 0.1f, 100.0f);glBindTexture(GL_TEXTURE_2D, _texture);for (int i = 0; i < 10; i++){glm::mat4 _modelMatrix(1.0f);//单位阵_modelMatrix = glm::translate(_modelMatrix, modelVecs[i]);//平移_modelMatrix = glm::rotate(_modelMatrix, glm::radians((float)glfwGetTime() * (i + 1) * 10), glm::vec3(0.0f, 1.0f, 0.0f));_shader.start();_shader.setMatrix("_modelMatrix", _modelMatrix);_shader.setMatrix("_viewMatrix", _viewMatrix);_shader.setMatrix("_projMatrix", _projMatrix);glBindVertexArray(VAO);glDrawArrays(GL_TRIANGLES, 0, 36);_shader.end();}
}

 

 

构建摄像机类——实现控制摄像机移动

需要完成的任务:

  • 接受鼠标以及键盘的信息,并做出反馈
  • 提供接口,控制摄像机上下左右观望、前后左右移动

摄像机坐标系的构成

  • 确定位置:Position
  • 确定朝向:与世界坐标系做连线,但相反的方向作为z轴
  • 确定右方:人为规定一个up向量,比如世界坐标的y轴,与摄像机空间z轴做叉乘,得到right向量
  • 确定上方:通过已求得的两个向量right和direction,叉乘获得up向量

摄像机坐标系的参数构建

 

 

摄像机关键参数提取(移动参数)

 

摄像机平移功能实现

摄像机类:

//Camera.h
#pragma once
#include "Base.h"enum class CAMERA_MOVE{MOVE_LEFT,MOVE_RIGHT,MOVE_FRONT,MOVE_BACK
};class Camera
{
private:glm::vec3	m_position;glm::vec3	m_front;glm::vec3	m_up;float		m_speed;glm::mat4	m_vMatrix;public:Camera() {m_position = glm::vec3(1.0f);m_front= glm::vec3(1.0f);m_up = glm::vec3(1.0f);m_speed = 0.01f;m_vMatrix = glm::mat4(1.0f);}~Camera() {}void lookAt(glm::vec3 _pos, glm::vec3 _front, glm::vec3 _up);void update();glm::mat4 getMatrix() { return m_vMatrix; }void move(CAMERA_MOVE _mode);void setspeed(float _speed);
};
//Camera.cpp
#include "Camera.h"void Camera::lookAt(glm::vec3 _pos, glm::vec3 _front, glm::vec3 _up)
{m_position = _pos;m_front = glm::normalize(_front);m_up = _up;m_vMatrix = glm::lookAt(m_position, m_position + m_front, m_up);
}void Camera::update()
{m_vMatrix = glm::lookAt(m_position, m_position + m_front, m_up);
}void Camera::move(CAMERA_MOVE _mode)
{switch (_mode){case CAMERA_MOVE::MOVE_LEFT:m_position -= glm::normalize(glm::cross(m_front, m_up)) * m_speed;break;case CAMERA_MOVE::MOVE_RIGHT:m_position += glm::normalize(glm::cross(m_front, m_up)) * m_speed;break;case CAMERA_MOVE::MOVE_FRONT:m_position += m_speed * m_front;break;case CAMERA_MOVE::MOVE_BACK:m_position -= m_speed * m_front;break;default:break;}
}void Camera::setspeed(float _speed)
{m_speed = _speed;
}

 main.cpp:

#include "Base.h"
#include "Shader.h"
#include "ffImage.h"
#include "Camera.h"void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);
void initModel();
void initShader(const char* _vertexPath, const char* _fragPath);
void initTexture();
void render();unsigned int VBO = 0;
unsigned int VAO = 0;
unsigned int EBO = 0;
unsigned int _texture = 0;Shader _shader;
ffImage* _pImage = nullptr;
Camera	_camera;glm::mat4 _projMatrix(1.0f);
int _width = 800;
int _height = 600;int main() {//初始化OpenGL上下文环境,OpenGL是一个状态机,会保存当前状态下的渲染状态以及管线的状态glfwInit(); //,3版本以上glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//用OpenGL核心开发模式glfwWindowHint(GLFW_OPENGL_PROFILE,GLFW_OPENGL_CORE_PROFILE);//创建窗体GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGl Core", nullptr, nullptr);if (window == nullptr) {std::cout << "Failed to create GLFW window" << std::endl;glfwTerminate();return -1;}//把当前上下文绑定至当前窗口glfwMakeContextCurrent(window);//通过glad绑定各种函数指针if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {std::cout << "Failed to initialize GLAD" << std::endl;return -1;}//视口:需要渲染的东西在哪里glViewport(0, 0, _width, _height);//当Frame大小变动,调用回调函数调整视口大小glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);_camera.lookAt(glm::vec3(0.0f, 0.0f, 3.0f), glm::vec3(0.0f, 0.0f, -1.0f), glm::vec3(0.0f, 1.0f, 0.0f));_camera.setspeed(0.01f);initModel();initShader("vertexShader.glsl", "fragmentShader.glsl");initTexture();//防止窗口结束退出while (!glfwWindowShouldClose(window)) {processInput(window);render();//双缓冲glfwSwapBuffers(window);glfwPollEvents();}//结束,释放资源glfwTerminate();return 0;}void framebuffer_size_callback(GLFWwindow* window, int width, int height) {glViewport(0, 0, width, height);
}void processInput(GLFWwindow* window) {if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {glfwSetWindowShouldClose(window, true);}if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) {_camera.move(CAMERA_MOVE::MOVE_FRONT);}if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) {_camera.move(CAMERA_MOVE::MOVE_BACK);}if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) {_camera.move(CAMERA_MOVE::MOVE_LEFT);}if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) {_camera.move(CAMERA_MOVE::MOVE_RIGHT);}
}//渲染
void render() {//擦除画布,用定义的颜色填充glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glEnable(GL_DEPTH_TEST);glm::vec3 modelVecs[] = {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)};_camera.update();_projMatrix = glm::perspective(glm::radians(45.0f), (float)_width / (float)_height, 0.1f, 100.0f);glBindTexture(GL_TEXTURE_2D, _texture);for (int i = 0; i < 10; i++){glm::mat4 _modelMatrix(1.0f);//单位阵_modelMatrix = glm::translate(_modelMatrix, modelVecs[i]);//平移_modelMatrix = glm::rotate(_modelMatrix, glm::radians((float)glfwGetTime() * (i + 1) * 10), glm::vec3(0.0f, 1.0f, 0.0f));//绕y轴旋转_shader.start();_shader.setMatrix("_modelMatrix", _modelMatrix);_shader.setMatrix("_viewMatrix", _camera.getMatrix());_shader.setMatrix("_projMatrix", _projMatrix);glBindVertexArray(VAO);glDrawArrays(GL_TRIANGLES, 0, 36);_shader.end();}
}//构建模型数据:VBO,VAO
void initModel() {//float vertices[] = {//	//顶点信息				颜色信息			纹理信息//	0.5f, 0.5f, 0.0f,		1.0f,0.0f,0.0f,		1.0f,1.0f,//	0.5f, -0.5f, 0.0f,	 	0.0f,1.0f,0.0f,		1.0f,0.0f,//	-0.5f, -0.5f, 0.0f,		0.0f,0.0f,1.0f,		0.0f,0.0f,//	-0.5f, 0.5f, 0.0f,		0.0f,1.0f,0.0f,		0.0f,1.0f//};float vertices[] = {//第一个面,六个顶点两个三角形-0.5f, -0.5f, -0.5f,  0.0f, 0.0f,0.5f, -0.5f, -0.5f,  1.0f, 0.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,-0.5f,  0.5f, -0.5f,  0.0f, 1.0f,-0.5f, -0.5f, -0.5f,  0.0f, 0.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,0.5f, -0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 1.0f,0.5f,  0.5f,  0.5f,  1.0f, 1.0f,-0.5f,  0.5f,  0.5f,  0.0f, 1.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,-0.5f,  0.5f,  0.5f,  1.0f, 0.0f,-0.5f,  0.5f, -0.5f,  1.0f, 1.0f,-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,-0.5f,  0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,0.5f, -0.5f, -0.5f,  0.0f, 1.0f,0.5f, -0.5f, -0.5f,  0.0f, 1.0f,0.5f, -0.5f,  0.5f,  0.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,0.5f, -0.5f, -0.5f,  1.0f, 1.0f,0.5f, -0.5f,  0.5f,  1.0f, 0.0f,0.5f, -0.5f,  0.5f,  1.0f, 0.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,-0.5f,  0.5f, -0.5f,  0.0f, 1.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,-0.5f,  0.5f,  0.5f,  0.0f, 0.0f,-0.5f,  0.5f, -0.5f,  0.0f, 1.0f};glGenVertexArrays(1, &VAO);glBindVertexArray(VAO);//之后的VBO便属于了VAO的管理范围glGenBuffers(1, &VBO);//绑定哪一种buffer, glBindBuffer(GL_ARRAY_BUFFER, VBO);//分配显存:分配哪种buffer,分配显存大小,分配地址,使用数据的方式glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//对哪个锚点进行操作:layout=0的锚点,读3个顶点,类型为float,不需要归一化,每次步长为3个float大小,从0处开始读glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(sizeof(float)*3));//打开锚点:激活glEnableVertexAttribArray(0);glEnableVertexAttribArray(1);//解绑glBindBuffer(GL_ARRAY_BUFFER, 0);glBindVertexArray(0);
}//
void initShader(const char* _vertexPath, const char* _fragPath) {_shader.initShader(_vertexPath, _fragPath);
}void initTexture() {_pImage = ffImage::readFromFile("res/wall.jpg");//纹理绑定glGenTextures(1, &_texture);glBindTexture(GL_TEXTURE_2D, _texture);//纹理属性设置glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);//读入图片数据glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _pImage->getWidth(), _pImage->getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE,_pImage->getData());
}

结果:

 

构建摄像机类——实现控制摄像机旋转

摄像机front向量的xyz

front.y:

front.x 和 front.z:

计算方式:

鼠标跟踪控制方法分解 

摄像机旋转功能实现

  • 在主函数中设置鼠标模式,同时绑定回调函数
  • 在摄像机类中添加相应属性及方法
  • 根据之前的理论,编写代码计算个方向向量,并归一化
  • 在鼠标移动时,计算pitch和yaw角度的变化
//Camera.cpp
#include "Camera.h"void Camera::lookAt(glm::vec3 _pos, glm::vec3 _front, glm::vec3 _up)
{m_position = _pos;m_front = glm::normalize(_front);m_up = _up;m_vMatrix = glm::lookAt(m_position, m_position + m_front, m_up);
}void Camera::update()
{m_vMatrix = glm::lookAt(m_position, m_position + m_front, m_up);
}void Camera::move(CAMERA_MOVE _mode)
{switch (_mode){case CAMERA_MOVE::MOVE_LEFT:m_position -= glm::normalize(glm::cross(m_front, m_up)) * m_speed;break;case CAMERA_MOVE::MOVE_RIGHT:m_position += glm::normalize(glm::cross(m_front, m_up)) * m_speed;break;case CAMERA_MOVE::MOVE_FRONT:m_position += m_speed * m_front;break;case CAMERA_MOVE::MOVE_BACK:m_position -= m_speed * m_front;break;default:break;}
}void Camera::setspeed(float _speed)
{m_speed = _speed;
}void Camera::pitch(float _yOffset)
{m_pitch += _yOffset * m_sensitivity;if (m_pitch >= 89.0f) {m_pitch = 89.0f;}if (m_pitch <= -89.0f) {m_pitch = -89.0f;}m_front.y = sin(glm::radians(m_pitch));m_front.x = cos(glm::radians(m_yaw)) * cos(glm::radians(m_pitch));m_front.z = sin(glm::radians(m_yaw)) * cos(glm::radians(m_pitch));m_front = glm::normalize(m_front);update();
}void Camera::yaw(float _xOffset)
{m_yaw += _xOffset * m_sensitivity;m_front.y = sin(glm::radians(m_pitch));m_front.x = cos(glm::radians(m_yaw)) * cos(glm::radians(m_pitch));m_front.z = sin(glm::radians(m_yaw)) * cos(glm::radians(m_pitch));m_front = glm::normalize(m_front);update();
}void Camera::setSensitivity(float _s)
{m_sensitivity = _s;
}void Camera::onMouseMove(double _xpos, double _ypos)
{if (m_firseMove) {m_xpos = m_xpos;m_ypos = m_ypos;m_firseMove = false;return;}float _xOffset = _xpos - m_xpos;float _yOffset = -(_ypos - m_ypos);m_xpos = _xpos;m_ypos = _ypos;pitch(_yOffset);yaw(_xOffset);
}

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
客厅放八骏马摆件可以吗(家里摆... 今天给各位分享客厅放八骏马摆件可以吗的知识,其中也会对家里摆八骏马摆件好吗进行解释,如果能碰巧解决你...
苏州离哪个飞机场近(苏州离哪个... 本篇文章极速百科小编给大家谈谈苏州离哪个飞机场近,以及苏州离哪个飞机场近点对应的知识点,希望对各位有...