Qt OpenGL 通过鼠标和键盘移动三维物体(设置相机)

16 篇文章 13 订阅

设置相机:
在这里插入图片描述

#pragma once
#include <QVector3D>
#include <QMatrix4x4>

class CubeCamera {
public:
	CubeCamera();
	CubeCamera(QVector3D position,float pitch, float yaw, QVector3D wordUp);
	~CubeCamera();

	QMatrix4x4 getViewMatrix();

	void wheel(int detal);
	float&getZoom() {
		return _zoom;
	}

	void keyPress(int key);
	void mouseMove(float detalX, float detalY);

private:
	void updateCameraVector();
private:
	float _pitch = 0.0;
	float _yaw = 0.0;
	QVector3D _wordUp;
	QVector3D _right;

	QVector3D _position = QVector3D(0.0, 0.0, -3.0);
	QVector3D _up = QVector3D(0.0, 1.0, 0.0);
	QVector3D _front = QVector3D(0.0, 0.0, 0.0);


	float _zoom = 45.0;
	float _zoomStep = 2.0;
};


#include "CubeCamera.h"

CubeCamera::CubeCamera() {
}


CubeCamera::CubeCamera(QVector3D position, float pitch, float yaw, QVector3D wordUp) {
	_position = position;
	_pitch = pitch;
	_yaw = yaw;
	_wordUp = wordUp;

	updateCameraVector();
}

CubeCamera::~CubeCamera() {
}

QMatrix4x4 CubeCamera::getViewMatrix() {
	QMatrix4x4 viewMatrix;
	viewMatrix.lookAt(_position, _position + _front, _up);
	return viewMatrix;
}

void CubeCamera::wheel(int detal) {
	if (detal < 0){
		_zoom += _zoomStep;
		if (_zoom >= 60.0){
			_zoom = 60.0;
		}
	} else {
		_zoom -= _zoomStep;
		if (_zoom <= 1.0){
			_zoom = 1.0;
		}
	}
}

void CubeCamera::keyPress(int key) {
	if (key == Qt::Key_A) {
		_position += _right * 0.1;
	} else if (key == Qt::Key_D) {
		_position -= _right * 0.1;
	} else if (key == Qt::Key_W) {
		_position -= _wordUp * 0.1;
	} else if (key == Qt::Key_S) {
		_position += _wordUp * 0.1;
	} else if (key == Qt::Key_E) {
		_position += _front *0.1;
	} else if (key == Qt::Key_Q) {
		_position -= _front *0.1;
	}
}

void CubeCamera::mouseMove(float xoffset, float yoffset) {
	xoffset *= 0.005;
	yoffset *= 0.005;
	qDebug() << xoffset<< yoffset;

	_yaw -= xoffset;
	_pitch += yoffset;

	if (_pitch > 89.0f)
		_pitch = 89.0f;
	if (_pitch < -89.0f)
		_pitch = -89.0f;

	updateCameraVector();
}

void CubeCamera::updateCameraVector() {
	QVector3D front;
	front.setX(cos(_yaw) * cos(_pitch));
	front.setY(sin(_pitch));
	front.setZ(sin(_yaw) * cos(_pitch));
	_front = front.normalized();

	_right = QVector3D::crossProduct(_front, _wordUp).normalized();

	_up = QVector3D::crossProduct(_right, _front).normalized();
}

#pragma once

#include <QOpenGLWindow>
#include <QOpenGLExtraFunctions>
#include <QDebug>
#include <QOpenGLTexture>
#include <QElapsedTimer>
#include <QOpenGLShader>
#include <QOpenGLShaderProgram>

class RotateCubeWnd : public QOpenGLWindow{
	Q_OBJECT

public:
	RotateCubeWnd();
	~RotateCubeWnd();

protected:
	void initializeGL()override;
	void paintGL()override;

	void keyPressEvent(QKeyEvent *event);
	void mouseMoveEvent(QMouseEvent *event);
	void wheelEvent(QWheelEvent *event);
	void mousePressEvent(QMouseEvent *event);
	void mouseReleaseEvent(QMouseEvent *event);
private slots:
	void slotTimeOut();
private:
	GLuint _VBO, _VAO;
	class QOpenGLFunctions_3_3_Core* _openGLCore;
	QOpenGLShaderProgram _shaderProgram;//着色器程序,所里系统所有的着色器

	class QOpenGLTexture *_texture1;

	QMatrix4x4 model,view, projection;
	class QTimer* _timer = nullptr;
	double _angle = 30.0;

	class CubeCamera* _cubeCamera = nullptr;

	bool _lBtnDown = false;
	QPoint _lBtnDownPos;
};

#include "RotateCubeWnd.h"
#include <QKeyEvent>
#include <QMouseEvent>
#include <QWheelEvent>
#include <QTimer>
#include <QOpenGLFunctions_3_3_Core>
#include "CubeCamera.h"

RotateCubeWnd::RotateCubeWnd(){
	_timer = new QTimer;
	_timer->start(20);
	connect(_timer, SIGNAL(timeout()), this, SLOT(slotTimeOut()));

	_cubeCamera = new CubeCamera(QVector3D(0.0, 0.0, -4.0), 0.0, 90.0, QVector3D(0.0, 1.0, 0.0));
}

RotateCubeWnd::~RotateCubeWnd(){
}

void RotateCubeWnd::initializeGL() {
	_openGLCore = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_3_Core>();
	
	//开启深度测试
	_openGLCore->glEnable(GL_DEPTH_TEST);
	_openGLCore->glDepthFunc(GL_LESS);

	GLfloat vertexData[] = {
		//  X     Y     Z    U     V
		// 下
	   -1.0f,-1.0f,-1.0f,   0.0f, 0.0f,
		1.0f,-1.0f,-1.0f,   1.0f, 0.0f,
	   -1.0f,-1.0f, 1.0f,   0.0f, 1.0f,
		1.0f,-1.0f,-1.0f,   1.0f, 0.0f,
		1.0f,-1.0f, 1.0f,   1.0f, 1.0f,
	   -1.0f,-1.0f, 1.0f,   0.0f, 1.0f,
		// 上
	   -1.0f, 1.0f,-1.0f,   0.0f, 0.0f,
	   -1.0f, 1.0f, 1.0f,   0.0f, 1.0f,
		1.0f, 1.0f,-1.0f,   1.0f, 0.0f,
		1.0f, 1.0f,-1.0f,   1.0f, 0.0f,
	   -1.0f, 1.0f, 1.0f,   0.0f, 1.0f,
		1.0f, 1.0f, 1.0f,   1.0f, 1.0f,
		// 前
	   -1.0f,-1.0f, 1.0f,   1.0f, 0.0f,
		1.0f,-1.0f, 1.0f,   0.0f, 0.0f,
	   -1.0f, 1.0f, 1.0f,   1.0f, 1.0f,
		1.0f,-1.0f, 1.0f,   0.0f, 0.0f,
		1.0f, 1.0f, 1.0f,   0.0f, 1.0f,
	   -1.0f, 1.0f, 1.0f,   1.0f, 1.0f,
		// 后
	   -1.0f,-1.0f,-1.0f,   0.0f, 0.0f,
	   -1.0f, 1.0f,-1.0f,   0.0f, 1.0f,
		1.0f,-1.0f,-1.0f,   1.0f, 0.0f,
		1.0f,-1.0f,-1.0f,   1.0f, 0.0f,
	   -1.0f, 1.0f,-1.0f,   0.0f, 1.0f,
		1.0f, 1.0f,-1.0f,   1.0f, 1.0f,
		// 左
	   -1.0f,-1.0f, 1.0f,   0.0f, 1.0f,
	   -1.0f, 1.0f,-1.0f,   1.0f, 0.0f,
	   -1.0f,-1.0f,-1.0f,   0.0f, 0.0f,
	   -1.0f,-1.0f, 1.0f,   0.0f, 1.0f,
	   -1.0f, 1.0f, 1.0f,   1.0f, 1.0f,
	   -1.0f, 1.0f,-1.0f,   1.0f, 0.0f,
		// 右
		1.0f,-1.0f, 1.0f,   1.0f, 1.0f,
		1.0f,-1.0f,-1.0f,   1.0f, 0.0f,
		1.0f, 1.0f,-1.0f,   0.0f, 0.0f,
		1.0f,-1.0f, 1.0f,   1.0f, 1.0f,
		1.0f, 1.0f,-1.0f,   0.0f, 0.0f,
		1.0f, 1.0f, 1.0f,   0.0f, 1.0f
	};

	_openGLCore->glGenVertexArrays(1, &_VAO);
	_openGLCore->glGenBuffers(1, &_VBO);

	_openGLCore->glBindVertexArray(_VAO);

	_openGLCore->glBindBuffer(GL_ARRAY_BUFFER, _VBO);
	_openGLCore->glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);

	// 位置属性
	_openGLCore->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
	_openGLCore->glEnableVertexAttribArray(0);
	// 坐标属性
	_openGLCore->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
	_openGLCore->glEnableVertexAttribArray(1);

	//垂直镜像mirrored
	_texture1 = new QOpenGLTexture(QImage("E:/Projects/QtGuiTest/OPenGLApp/RotateCube/a.jpg").mirrored());
	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);
	

	_shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex, "E:/Projects/QtGuiTest/OPenGLApp/RotateCube/RotateCube.vert");
	_shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment, "E:/Projects/QtGuiTest/OPenGLApp/RotateCube/RotateCube.frag");
	_shaderProgram.link();

	_shaderProgram.bind();
	_shaderProgram.setUniformValue("textureImg", 0);

	model.rotate(45.0, QVector3D(1.0, 1.0, 1.0));
	model.scale(0.5);

	view = _cubeCamera->getViewMatrix();
}

void RotateCubeWnd::paintGL() {
	_openGLCore->glClearColor(0.4f, 0.4f, 0.4f, 1.0f);
	_openGLCore->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	_openGLCore->glActiveTexture(GL_TEXTURE0);
	_texture1->bind();

	_shaderProgram.bind();

#if 0
	QMatrix4x4 view;
	/*
	第一个参数相当于改变摄像头的观察位置,有规律的改变这个值就能起到从不同角度观察物体的效果。
	而改变第二个参数则相当于改变世界坐标系的原点,整个世界坐标系上的物体将随之移动。
	*/
	view.lookAt(QVector3D(0.0f, 0.0f, -3.0f), QVector3D(0.0, 0.0, 0.0), QVector3D(0.0, 1.0, 0.0));
	view.rotate(_angle, QVector3D(0.0, 1.0, 0.0));
#else
	QMatrix4x4 view = _cubeCamera->getViewMatrix();
#endif

	QMatrix4x4 projection;
	projection.perspective(_cubeCamera->getZoom(), width() / height(), 0.1, 100);


	_shaderProgram.setUniformValue("model", model);
	_shaderProgram.setUniformValue("view", view);
	_shaderProgram.setUniformValue("projection", projection);
	/*
	立方体6个面,每个面有2个三角形,每个三角形有3个顶点,所以需要绘制的顶点数是:6 × 2 × 3 = 36
	*/
	_openGLCore->glDrawArrays(GL_TRIANGLES, 0, 36);

	update();

}

void RotateCubeWnd::keyPressEvent(QKeyEvent *event) {
	_cubeCamera->keyPress(event->key());
	
}

void RotateCubeWnd::mouseMoveEvent(QMouseEvent *event) {
	if (_lBtnDown){
		float xpos = static_cast<float>(event->pos().x());
		float ypos = static_cast<float>(event->pos().y());

		float xoffset = _lBtnDownPos.x() - xpos;
		float yoffset = _lBtnDownPos.y() - ypos; 

		_lBtnDownPos = event->pos();

		_cubeCamera->mouseMove(xoffset, yoffset);
	}
}

void RotateCubeWnd::wheelEvent(QWheelEvent *event) {
	_cubeCamera->wheel(event->delta());
	update();
}

void RotateCubeWnd::mousePressEvent(QMouseEvent *event) {
	if (event->button() == Qt::LeftButton){
		_lBtnDown = true;
		_lBtnDownPos = event->pos();
	}
}

void RotateCubeWnd::mouseReleaseEvent(QMouseEvent *event) {
	if (event->button() == Qt::LeftButton) {
		_lBtnDown = false;
	}
}

void RotateCubeWnd::slotTimeOut() {
	_angle += 1.0;
	//update();
}

#include "OPenGLApp.h"
#include <QtWidgets/QApplication>

#include <QtOpenGL/QtOpenGL>
#include "MyOpenGLWnd.h"
#include "EBOWnd.h"
#include "HelloShader.h"
#include "HelloShaderSelf.h"
#include "TextureWnd.h"
#include "CameraWnd.h"
#include "QOpenGLLight.h"
#include "RotateCube/RotateCubeWnd.h"

int main(int argc, char *argv[]) {
	QApplication a(argc, argv);

	RotateCubeWnd window;
	window.setTitle(QStringLiteral("这是一个OpenGL窗口"));
	window.resize(800, 800);

	window.show();
	return a.exec();
}

顶点着色器:

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTextureCoord;
out vec3 outColor;
out vec2 textureCoord;

//矩阵必须初始化,初始化单位矩阵,否则GLSL语言中默认矩阵是0矩阵
uniform mat4 trans = mat4(1.0);

uniform mat4 model = mat4(1.0);
uniform mat4 view = mat4(1.0);
uniform mat4 projection = mat4(1.0);

void main(){
	gl_Position = projection * view * model * vec4(aPos, 1.0);
	textureCoord = aTextureCoord;
}

片段着色器:

#version 330 core
out vec4 fragColor;
in vec3 outColor;//从顶点着色器中传过来的颜色
in vec2 textureCoord;
uniform sampler2D textureImg;
void main(){
	fragColor = texture(textureImg, textureCoord);
}

aaa

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wb175208

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值