概述
效果,按下wasdqr可以平移,鼠标拖动可以旋转,滑轮可以缩放
照相机类头文件
#pragma once
#include <QVector3D>
#include <QMatrix4x4>
#include <QKeyEvent>
enum Camera_Movement {
FORWARD,//前
BACKWARD,//后
LEFT,//左
RIGHT,//右
UP,//上
DOWN//下
};
const float YAW = -90.0f;
const float PITCH = 0.0f;
const float SPEED = 1.0f;
const float SENSITIVITY = 0.01f;
const float ZOOM = 45.0f;
class Camera {
public:
//相机位置,相机的上轴,yaw关于y轴的旋转向左向右看的程度,pitch关于x轴的旋转,向上向下看的俯仰角
Camera(QVector3D position = QVector3D(0.0f, 0.0f, 0.0f), QVector3D up = QVector3D(0.0f, 1.0f, 0.0f),
float yaw = YAW, float pitch = PITCH);
~Camera();
QMatrix4x4 getViewMatrix();
void processMouseMovement(float xoffset, float yoffset, bool constraintPitch = true);
void processMouseScroll(float yoffset);
void processInput(float dt);
QVector3D position;//摄像机位置向量
QVector3D worldUp;//世界坐标的上轴
QVector3D front;//摄像机的方向向量,其实就是-position
QVector3D up;//上向量
QVector3D right;//右向量
//俯仰角
float picth;
//偏航角
float yaw;
float movementSpeed;//鼠标速度
float mouseSensitivity;//鼠标灵敏度
float zoom;缩放 之前有一个函数projection.perspective定义了视角的缩放,在那边会用到
bool keys[1024];
private:
void updateCameraVectors();
void processKeyboard(Camera_Movement direction, float deltaTime);
};
照相机类源文件
#include "Camera.h"
#include <QDebug>
//传参
Camera::Camera(QVector3D position, QVector3D up, float yaw, float pitch) :
position(position),
worldUp(up),
front(-position),
picth(pitch),
yaw(yaw),
movementSpeed(SPEED),
mouseSensitivity(SENSITIVITY),
zoom(ZOOM) {
this->updateCameraVectors();
for (uint i = 0; i != 1024; ++i)
keys[i] = false;
}
Camera::~Camera()
{
}
// Returns the view matrix calculated using Euler Angles and the LookAt Matrix
QMatrix4x4 Camera::getViewMatrix()
{
QMatrix4x4 view;
//(const QVector3D& eye, const QVector3D& center, const QVector3D& up);
view.lookAt(this->position, this->position + this->front, this->up);
return view;
}
//键盘按下事件
void Camera::processKeyboard(Camera_Movement direction, float deltaTime)
{
float 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;
if (direction == UP)
this->position += this->worldUp * velocity;
if (direction == DOWN)
this->position -= this->worldUp * velocity;
}
//鼠标移动事件
void Camera::processMouseMovement(float xoffset, float yoffset, bool constraintPitch)
{
xoffset *= this->mouseSensitivity;
yoffset *= this->mouseSensitivity;
this->yaw += xoffset;
this->picth += yoffset;
if (constraintPitch) {
if (this->picth > 89.0f)
this->picth = 89.0f;
if (this->picth < -89.0f)
this->picth = -89.0f;
}
this->updateCameraVectors();
}
// 该参数表示竖直滚动大小,因为45时默认的视野值,所以把缩放级别限制在1到45
void Camera::processMouseScroll(float yoffset)
{
//小于45°时
if (this->zoom >= 1.0f && this->zoom <= 45.0f)
this->zoom -= yoffset;
if (this->zoom > 45.0f)
this->zoom = 45.0f;
if (this->zoom < 1.0f)
this->zoom = 1.0f;
}
//按键移动
void Camera::processInput(float dt)
{
if (keys[Qt::Key_W])
processKeyboard(FORWARD, dt);
if (keys[Qt::Key_S])
processKeyboard(BACKWARD, dt);
if (keys[Qt::Key_A])
processKeyboard(LEFT, dt);
if (keys[Qt::Key_D])
processKeyboard(RIGHT, dt);
if (keys[Qt::Key_E])
processKeyboard(UP, dt);
if (keys[Qt::Key_Q])
processKeyboard(DOWN, dt);
}
void Camera::updateCameraVectors()
{
转动需要
// 通过俯仰角和偏航角得到新的xyz位置
QVector3D front;
front.setX(cos(this->yaw) * cos(this->picth));
front.setY(sin(this->picth));
front.setZ(sin(this->yaw) * cos(this->picth));
this->front = front.normalized();
移动需要
//利用世界上轴和相机向量叉乘获得右轴
//右轴等于上向量,鼠标向左的时候我们希望它向右移动,所以是front叉乘worldUp反之就反着叉乘
this->right = QVector3D::crossProduct(this->front, this->worldUp).normalized();
//同上
this->up = QVector3D::crossProduct(this->right, this->front).normalized();
}
什么地方用到了照相机类
在构造函数中初始化其指针
在PaintGL函数中
在事件重载的函数中
OpenGL类头文件
#pragma once
#include <QOpenGLWidget>
#include <QOpenGLShaderProgram>
#include <QOpenGLFunctions>
#include <QOpenGLVertexArrayObject>
#include <QOpenGLBuffer>
#include <QOpenGLTexture>
#include "Camera.h"
class QtFunctionWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
public:
QtFunctionWidget(QWidget *parent = nullptr);
~QtFunctionWidget() Q_DECL_OVERRIDE;
protected:
virtual void initializeGL() Q_DECL_OVERRIDE;
virtual void resizeGL(int w, int h) Q_DECL_OVERRIDE;
virtual void paintGL() Q_DECL_OVERRIDE;
void keyPressEvent(QKeyEvent *event) Q_DECL_OVERRIDE;
void keyReleaseEvent(QKeyEvent *event) Q_DECL_OVERRIDE;
void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE;
private:
QOpenGLShaderProgram shaderProgram;
QOpenGLBuffer vbo;
QOpenGLVertexArrayObject vao;
QOpenGLTexture *texture1 = nullptr;
QOpenGLTexture *texture2 = nullptr;
QTimer* m_pTimer = nullptr;
int m_nTimeValue = 0;
// camera
std::unique_ptr<Camera> camera;//相机指针 两个unique_ptr指针不能指向同一个对象,不能复制只能移动
bool m_bLeftPressed;
QPoint m_lastPos;//上次的点
};
OpenGL类源文件
#include "QtFunctionWidget.h"
#include <QDebug>
#include <QTimer>
QtFunctionWidget::QtFunctionWidget(QWidget *parent) : QOpenGLWidget(parent),
vbo(QOpenGLBuffer::VertexBuffer)
{
camera = std::make_unique<Camera>(QVector3D(5.0f, 0.0f, 10.0f));//创建并且返回unique_ptr对象
m_bLeftPressed = false;
//重绘
m_pTimer = new QTimer(this);
connect(m_pTimer, &QTimer::timeout, this, [=] {
m_nTimeValue += 1;
update();
});
m_pTimer->start(40);
}
QtFunctionWidget::~QtFunctionWidget() {
//多线程调用保护
makeCurrent();
//glDeleteBuffers
vbo.destroy();
//glDeleteVertexArrays
vao.destroy();
delete texture1;
delete texture2;
//退出保护
doneCurrent();
}
void QtFunctionWidget::initializeGL() {
this->initializeOpenGLFunctions();
bool success = shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex, "textures.vert");
if (!success) {
qDebug() << "shaderProgram addShaderFromSourceFile failed!" << shaderProgram.log();
return;
}
success = shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment, "textures.frag");
if (!success) {
qDebug() << "shaderProgram addShaderFromSourceFile failed!" << shaderProgram.log();
return;
}
success = shaderProgram.link();
if (!success) {
qDebug() << "shaderProgram link failed!" << shaderProgram.log();
}
//VAO,VBO data
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
};
//绑定vao
QOpenGLVertexArrayObject::Binder vaoBind(&vao);
//创建vbo
vbo.create();
//绑定vbo
vbo.bind();
//分配数组内存空间
vbo.allocate(vertices, sizeof(vertices));
//和glVertexAttribPointer有区别
//glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer)
// void setAttributeBuffer(int location, GLenum type, int offset, int tupleSize, int stride = 0);//不需要填是否标准化
shaderProgram.setAttributeBuffer(0, GL_FLOAT, 0, 3, sizeof(GLfloat) * 5);//位置0,数据类型float,起始从0开始,元组大小为3个,步长为5个float
shaderProgram.enableAttributeArray(0);
shaderProgram.setAttributeBuffer(1, GL_FLOAT, sizeof(GLfloat) * 3, 2, sizeof(GLfloat) * 5);
shaderProgram.enableAttributeArray(1);
vbo.release();//vbo操作完毕,接下来就没有对vbo内存的操作了
//纹理一
texture1 = new QOpenGLTexture(QImage("container.jpg"), QOpenGLTexture::GenerateMipMaps);
if (!texture1->isCreated()) {
qDebug() << "Failed to load texture";
}
//纹理的样式
texture1->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat);
texture1->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat);
texture1->setMinificationFilter(QOpenGLTexture::Linear);
texture1->setMagnificationFilter(QOpenGLTexture::Linear);
//纹理二
texture2 = new QOpenGLTexture(QImage("awesomeface.png").mirrored(true, true), QOpenGLTexture::GenerateMipMaps);
if (!texture2->isCreated()) {
qDebug() << "Failed to load texture";
}
texture2->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat);
texture2->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat);
texture2->setMinificationFilter(QOpenGLTexture::Linear);
texture2->setMagnificationFilter(QOpenGLTexture::Linear);
// tell opengl for each sampler to which texture unit it belongs to (only has to be done once)
shaderProgram.bind();//纹理的值传递给着色器
shaderProgram.setUniformValue("texture1", 0);//0代表第一个纹理
shaderProgram.setUniformValue("texture2", 1);//1代表第二个纹理
glEnable(GL_DEPTH_TEST);//开启深度测试
}
void QtFunctionWidget::resizeGL(int w, int h) {
glViewport(0, 0, w, h);
}
//位置数组
static QVector3D cubePositions[] = {
QVector3D(0.0f, 0.0f, 0.0f),
QVector3D(2.0f, 5.0f, -15.0f),
QVector3D(-1.5f, -2.2f, -2.5f),
QVector3D(-3.8f, -2.0f, -12.3f),
QVector3D(2.4f, -0.4f, -3.5f),
QVector3D(-1.7f, 3.0f, -7.5f),
QVector3D(1.3f, -2.0f, -2.5f),
QVector3D(1.5f, 2.0f, -2.5f),
QVector3D(1.5f, 0.2f, -1.5f),
QVector3D(-1.3f, 1.0f, -1.5f)
};
void QtFunctionWidget::paintGL() {
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
camera->processInput(1.0f);//本来参数是用来计算电脑两帧之间的时间的,这里用1代替
//绑定纹理
glActiveTexture(GL_TEXTURE0);
texture1->bind();
glActiveTexture(GL_TEXTURE1);
texture2->bind();
//想要着色器调用我们的c++程序就需要先bind
shaderProgram.bind();
QMatrix4x4 projection;
//perspective的第一个参数是缩放参数
projection.perspective(camera->zoom, 1.0f * width() / height(), 0.1f, 100.f);
shaderProgram.setUniformValue("projection", projection);
//通过照相机对象的内置函数获取视图数组
shaderProgram.setUniformValue("view", camera->getViewMatrix());
{//绑定vao
QOpenGLVertexArrayObject::Binder vaoBind(&vao);
for (unsigned int i = 0; i < 10; i++) {
// 对每个物体都要计算model矩阵
QMatrix4x4 model;
model.translate(cubePositions[i]);//平移
float angle = (i + 1.0f) * m_nTimeValue;
model.rotate(angle, QVector3D(1.0f, 0.3f, 0.5f));//旋转
shaderProgram.setUniformValue("model", model);//把数据传递给着色器
glDrawArrays(GL_TRIANGLES, 0, 36);
}
}
//解除绑定
texture1->release();
texture2->release();
shaderProgram.release();
}
//键盘按下事件
//keys是一个bool的数组,通过以下两个函数来判断键盘是否按下
void QtFunctionWidget::keyPressEvent(QKeyEvent *event)
{
int key = event->key();
if (key >= 0 && key < 1024)
camera->keys[key] = true;
}
void QtFunctionWidget::keyReleaseEvent(QKeyEvent *event)
{
int key = event->key();
if (key >= 0 && key < 1024)
camera->keys[key] = false;
}
//鼠标是否按下事件
void QtFunctionWidget::mousePressEvent(QMouseEvent *event)
{
//按下该键把参数设置成true
if (event->button() == Qt::LeftButton) {
m_bLeftPressed = true;
m_lastPos = event->pos();
}
}
//鼠标释放函数,把该值设置成false
void QtFunctionWidget::mouseReleaseEvent(QMouseEvent *event)
{
Q_UNUSED(event);//Q_UNUSED() 没有实质性的作用,用来避免编译器警告
m_bLeftPressed = false;
}
//鼠标移动事件
void QtFunctionWidget::mouseMoveEvent(QMouseEvent *event)
{
//如果鼠标按下了就触发鼠标移动事件
if (m_bLeftPressed) {
int xpos = event->pos().x();
int ypos = event->pos().y();
//x,y移动的距离
int xoffset = xpos - m_lastPos.x();
int yoffset = m_lastPos.y() - ypos;//qt的y坐标往下是正,opengl y坐标往上是正,openGL远点在中间,QT在左上角
//重置上一次的移动位置
m_lastPos = event->pos();
camera->processMouseMovement(xoffset, yoffset);
}
}
//滚轮事件
void QtFunctionWidget::wheelEvent(QWheelEvent *event)
{
QPoint offset = event->angleDelta();
camera->processMouseScroll(offset.y() / 20.0f);
}
顶点着色器
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;
out vec2 TexCoord;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main(){
gl_Position = projection * view * model * vec4(aPos, 1.0f);
TexCoord = aTexCoord;
}
片段着色器
#version 330 core
out vec4 FragColor;
in vec2 TexCoord;
uniform sampler2D texture1;
uniform sampler2D texture2;
void main()
{
FragColor = mix(texture2D(texture1, TexCoord), texture2D(texture2, TexCoord), 0.2f);
}
最后
以上就是疯狂蜗牛为你收集整理的8. 摄像机类实现的全部内容,希望文章能够帮你解决8. 摄像机类实现所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复