学习笔记2--与OpenGL窗口中的立方体进行简单的交互
2017-02-27 21:08
549 查看
对于任何应用程序,交互都是必须的,本文将在上一篇笔记的基础上,再添加些交互功能。
添加的交互功能是较为常见的:让OpenGL窗口中的渲染的立方体响应鼠标事件,实现对立方体的旋转、放缩、移动。
要实现以上交互功能,主要解决两个问题:一个是界面如何响应鼠标输入事件,这主要重写Qt中窗口部件的mouseMoveEvent、wheelEvent、mousePressEvent等类似的函数来实现对鼠标事件的捕捉;另一个是如何将捕捉到的鼠标事件体现到OpenGL渲染的立方体上,这主要用到坐标变换、OpenGL的坐标系统(局部坐标、世界坐标、观察坐标、裁剪坐标、屏幕坐标)、摄像机以及坐标系统和摄像机的关系。
本文不打算介绍关于Qt和OpenGL的相关知识,对于Qt可以查看帮助文档,对于OpenGL中关于桌边系统和摄像机知识,参考:https://learnopengl-cn.github.io/01%20Getting%20started/08%20Coordinate%20Systems/
本例的程序将继续在上一篇笔记的基础上添加:
openglwindow.h:仅需添加需要重写的虚函数的声明即可;
#ifndef OPENGLWINDOW_H
#define OPENGLWINDOW_H
#include <QOpenGLWidget>
#include <QOpenGLFunctions_3_3_Core>
class openglwindow : public QOpenGLWidget,
protected QOpenGLFunctions_3_3_Core
{
Q_OBJECT
public:
openglwindow(QWidget *parent = 0);
~openglwindow();
void initializeGL();
void resizeGL(int width, int height);
void paintGL();
protected:
void mouseMoveEvent(QMouseEvent *event);
void wheelEvent(QWheelEvent *event);
void mousePressEvent(QMouseEvent *event);
};
#endif // OPENGLWINDOW_H
openglwindow.cpp:
(1) 添加头文件(包括鼠标事件、glm库用于坐标变换);
(2) 定义鼠标事件先关的一些全局变量;
(3) 改变着色器源码,添加uniform变量,用来实现传递转换矩阵;
(4) 对openglwindow.h中的鼠标事件虚函数进行重写(具体见源代码);
(5) 在paintGL函数中定义三个矩阵,用来存储观察矩阵、投影矩阵和模型矩阵,并将该值导入到着色器中的uniform变量中;
(6) 最后别忘了添加update函数到paintGL函数中,调用该函数实现将鼠标事件的信息实时传入到着色器中。
#include "openglwindow.h"
#include <iostream>
#include <QMouseEvent>
//OpenGL Mathematics 用来进行数学变换
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
/*******************************************************************************
* 鼠标操作的一些设置
******************************************************************************/
//相机位置及朝向,用来构造ViewMatrix,进行“世界空间”到“观察空间”的转换
glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f); //相机位置
glm::vec3 worldCentrol = glm::vec3(0.0f, 0.0f, 0.0f); //世界坐标原点,相机始终朝向这个方向
glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f); //相机的顶部始终朝向y轴
//构建ModelMatrix,进行“局部空间”到“世界空间”的转换
glm::vec3 transVec = glm::vec3(0.0f, 0.0f, 0.0f); //局部坐标在世界坐标中的平移量
GLfloat yaw = 0.0f; //偏航角
GLfloat pitch = 0.0f; //俯仰角
GLfloat lastX = 0; //光标上次x值
GLfloat lastY = 0; //光标上次y值
/*******************************************************************************
* 着色器、着色器程序、VAO(顶点数组对象)、VBO(顶点缓冲对象)、EBO(索引缓冲对象)
******************************************************************************/
const GLuint NumVertexShader = 1; //顶点着色器的数目
const GLuint NumFragmentShader = 1; //片段着色器的数目
const GLuint NumShaderProgram = 1; //着色器程序的数目
const GLuint NumVAO = 1; //VAO的数目
const GLuint NumVBO = 1; //VBO的数目
const GLuint NumEBO = 1; //EBO的数目
GLuint IDVertexShader[NumVertexShader];
GLuint IDFragmentShader[NumFragmentShader];
GLuint IDShaderProgram[NumShaderProgram];
GLuint IDVAO[NumVAO];
GLuint IDVBO[NumVBO];
GLuint IDEBO[NumEBO];
/*******************************************************************************
* 着色器源码
******************************************************************************/
const GLchar *vertexShaderSource =
"#version 330 core\n"
"layout(location = 0) in vec3 vPosition;\n"
"layout(location = 1) in vec3 vColor;\n"
"uniform mat4 model;\n"
"uniform mat4 view;\n"
"uniform mat4 projection;\n"
"out vec3 Color;\n"
"void main()\n"
"{\n"
"gl_Position = projection * view * model * vec4(vPosition, 1.0);\n"
"Color = vColor;\n"
"}\n";
const GLchar *fragmentShaderSource =
"#version 330 core\n"
"in vec3 Color;\n"
"out vec4 fColor;\n"
"void main()\n"
"{\n"
"fColor = vec4(Color, 1.0f);\n"
"}\n";
openglwindow::openglwindow(QWidget *parent)
:QOpenGLWidget(parent)
{
//设置OpenGL的版本信息
QSurfaceFormat format;
format.setRenderableType(QSurfaceFormat::OpenGL);
format.setProfile(QSurfaceFormat::CoreProfile);
format.setVersion(3,3);
setFormat(format);
}
openglwindow::~openglwindow()
{
}
void openglwindow::initializeGL()
{
//初始化OpenGL函数
initializeOpenGLFunctions();
//设置全局变量
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
/******************************* 顶点着色器创建 *******************************/
/* 第一个顶点着色器 */
IDVertexShader[0] = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(IDVertexShader[0], 1, &vertexShaderSource, nullptr);
glCompileShader(IDVertexShader[0]);
//检查编译是否出错
GLint success;
GLchar infoLog[512];
glGetShaderiv(IDVertexShader[0], GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(IDVertexShader[0], 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}
/******************************* 片段着色器创建 *******************************/
/* 第一个片元着色器 */
IDFragmentShader[0] = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(IDFragmentShader[0], 1, &fragmentShaderSource, nullptr);
glCompileShader(IDFragmentShader[
c9f4
0]);
//检查编译是否出错
glGetShaderiv(IDFragmentShader[0], GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(IDFragmentShader[0], 512, NULL, infoLog);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
}
/********************************* 链接着色器 *********************************/
/* 第一个着色器程序 */
IDShaderProgram[0] = glCreateProgram();
glAttachShader(IDShaderProgram[0], IDVertexShader[0]);
glAttachShader(IDShaderProgram[0], IDFragmentShader[0]);
glLinkProgram(IDShaderProgram[0]);
//检查链接错误
glGetProgramiv(IDShaderProgram[0], GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(IDShaderProgram[0], 512, NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
}
//删除着色器对象(生成着色器程序之后不再需要)
glDeleteShader(IDVertexShader[0]);
glDeleteShader(IDFragmentShader[0]);
/******************************** 设置顶点数据 ********************************/
//彩色正方体
GLfloat vertices[] =
{
-0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 1.0f,
0.5f, 0.5f, -0.5f, 0.8f, 0.5f, 0.2f,
-0.5f, 0.5f, -0.5f, 0.2f, 0.8f, 0.5f
};
GLuint indices[] =
{
0, 1, 2, 2, 3, 0, //前
4, 5, 6, 6, 7, 4, //后
0, 4, 7, 7, 3, 0, //左
1, 5, 6, 6, 2, 1, //右
0, 4, 5, 5, 1, 0, //上
3, 7, 6, 6, 2, 3 //下
};
/****************************************************************************/
/**************************** VAO\VBO\顶点属性指针 ****************************/
/****************************************************************************/
/* 创建相关对象 */
glGenVertexArrays(NumVAO, IDVAO);
glGenBuffers(NumVBO, IDVBO);
glGenBuffers(NumEBO, IDEBO);
/* 显示立方体 */
glBindVertexArray(IDVAO[0]); //开始记录状态信息
glBindBuffer(GL_ARRAY_BUFFER, IDVBO[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IDEBO[0]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3*sizeof(GLfloat)));
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0); //结束记录状态信息
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //在VAO后解绑,是为了不让VAO把解绑EBO的信息包含进入
/* 显示立方体 */
/* 固定属性区域 */
glEnable(GL_DEPTH_TEST); //开启深度测试
}
void openglwindow::paintGL()
{
//清理屏幕
glClear(GL_COLOR_BUFFER_BIT);
//实现参数的刷新
update();
//渲染彩色正方体
glUseProgram(IDShaderProgram[0]);
glm::mat4 view;
glm::mat4 projection;
glm::mat4 model;
GLint modelLoc = glGetUniformLocation(IDShaderProgram[0], "model");
GLint viewLoc = glGetUniformLocation(IDShaderProgram[0], "view");
GLint projLoc = glGetUniformLocation(IDShaderProgram[0], "projection");
view = glm::lookAt(cameraPos, worldCentrol, cameraUp);
projection = glm::perspective(glm::radians(45.0f), 4.0f / 3.0f, 0.1f, 100000.0f);
model = glm::translate(model, transVec);
model = glm::rotate(model, glm::radians(pitch), glm::vec3(1.0f, 0.0f, 0.0f)); //按住左键,上下拖动鼠标让立方体绕x轴旋转
model = glm::rotate(model, glm::radians(yaw), glm::vec3(0.0f, 1.0f, 0.0f)); //按住左键,左右拖动鼠标让立方体绕y轴旋转
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glBindVertexArray(IDVAO[0]);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
//强制刷新缓冲区,保证命令被执行
glFlush();
}
void openglwindow::resizeGL(int width, int height)
{
//未使用
Q_UNUSED(width);
Q_UNUSED(height);
}
void openglwindow::mouseMoveEvent(QMouseEvent *event)
{
//鼠标左键用来实现对物体的旋转功能
if(event->buttons() == Qt::LeftButton)
{
//计算yaw,pitch值的改变量
GLfloat xoffset = event->x() - lastX;
GLfloat yoffset = event->y() - lastY;
lastX = event->x();
lastY = event->y();
GLfloat sensitivity = 0.4f; //旋转时的灵敏度
xoffset *= sensitivity;
yoffset *= sensitivity;
yaw += xoffset;
pitch += yoffset;
//可以用来设置俯仰角的上下界
if (pitch > 89.0f)
pitch = 89.0f;
if (pitch < -89.0f)
pitch = -89.0f;
}
//鼠标右键用来实现对移动物体(即局部坐标在世界坐标中的移动)
else if(event->buttons() == Qt::RightButton)
{
//计算x,y方向的偏移量
GLfloat xoffset = event->x() - lastX;
GLfloat yoffset = event->y() - lastY;
lastX = event->x();
lastY = event->y();
GLfloat sensitivity = 0.01f; //移动时的灵敏度
xoffset *= sensitivity;
yoffset *= sensitivity;
//仅需在x-y平面内移动即可
transVec += glm::vec3(xoffset, -yoffset, 0.0f);
}
}
//滚轮实现对物体的放大缩小,摄像机距离远近(放大缩小)
void openglwindow::wheelEvent(QWheelEvent *event)
{
GLfloat sensitivity = 0.0005f;
cameraPos *= (1.0f - event->delta() * sensitivity);
}
void openglwindow::mousePressEvent(QMouseEvent *event)
{
//记录点击光标时的位置
lastX = event->x();
lastY = event->y();
}
运行结果:
现在可以看到在上一篇中绘制的立方体的全貌了。
编译环境及版本:Win10企业版+Qt 5.7.1(MSVC 2015, 32bit)+OpenGL3.3 Core Profile
添加的交互功能是较为常见的:让OpenGL窗口中的渲染的立方体响应鼠标事件,实现对立方体的旋转、放缩、移动。
要实现以上交互功能,主要解决两个问题:一个是界面如何响应鼠标输入事件,这主要重写Qt中窗口部件的mouseMoveEvent、wheelEvent、mousePressEvent等类似的函数来实现对鼠标事件的捕捉;另一个是如何将捕捉到的鼠标事件体现到OpenGL渲染的立方体上,这主要用到坐标变换、OpenGL的坐标系统(局部坐标、世界坐标、观察坐标、裁剪坐标、屏幕坐标)、摄像机以及坐标系统和摄像机的关系。
本文不打算介绍关于Qt和OpenGL的相关知识,对于Qt可以查看帮助文档,对于OpenGL中关于桌边系统和摄像机知识,参考:https://learnopengl-cn.github.io/01%20Getting%20started/08%20Coordinate%20Systems/
本例的程序将继续在上一篇笔记的基础上添加:
openglwindow.h:仅需添加需要重写的虚函数的声明即可;
#ifndef OPENGLWINDOW_H
#define OPENGLWINDOW_H
#include <QOpenGLWidget>
#include <QOpenGLFunctions_3_3_Core>
class openglwindow : public QOpenGLWidget,
protected QOpenGLFunctions_3_3_Core
{
Q_OBJECT
public:
openglwindow(QWidget *parent = 0);
~openglwindow();
void initializeGL();
void resizeGL(int width, int height);
void paintGL();
protected:
void mouseMoveEvent(QMouseEvent *event);
void wheelEvent(QWheelEvent *event);
void mousePressEvent(QMouseEvent *event);
};
#endif // OPENGLWINDOW_H
openglwindow.cpp:
(1) 添加头文件(包括鼠标事件、glm库用于坐标变换);
(2) 定义鼠标事件先关的一些全局变量;
(3) 改变着色器源码,添加uniform变量,用来实现传递转换矩阵;
(4) 对openglwindow.h中的鼠标事件虚函数进行重写(具体见源代码);
(5) 在paintGL函数中定义三个矩阵,用来存储观察矩阵、投影矩阵和模型矩阵,并将该值导入到着色器中的uniform变量中;
(6) 最后别忘了添加update函数到paintGL函数中,调用该函数实现将鼠标事件的信息实时传入到着色器中。
#include "openglwindow.h"
#include <iostream>
#include <QMouseEvent>
//OpenGL Mathematics 用来进行数学变换
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
/*******************************************************************************
* 鼠标操作的一些设置
******************************************************************************/
//相机位置及朝向,用来构造ViewMatrix,进行“世界空间”到“观察空间”的转换
glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f); //相机位置
glm::vec3 worldCentrol = glm::vec3(0.0f, 0.0f, 0.0f); //世界坐标原点,相机始终朝向这个方向
glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f); //相机的顶部始终朝向y轴
//构建ModelMatrix,进行“局部空间”到“世界空间”的转换
glm::vec3 transVec = glm::vec3(0.0f, 0.0f, 0.0f); //局部坐标在世界坐标中的平移量
GLfloat yaw = 0.0f; //偏航角
GLfloat pitch = 0.0f; //俯仰角
GLfloat lastX = 0; //光标上次x值
GLfloat lastY = 0; //光标上次y值
/*******************************************************************************
* 着色器、着色器程序、VAO(顶点数组对象)、VBO(顶点缓冲对象)、EBO(索引缓冲对象)
******************************************************************************/
const GLuint NumVertexShader = 1; //顶点着色器的数目
const GLuint NumFragmentShader = 1; //片段着色器的数目
const GLuint NumShaderProgram = 1; //着色器程序的数目
const GLuint NumVAO = 1; //VAO的数目
const GLuint NumVBO = 1; //VBO的数目
const GLuint NumEBO = 1; //EBO的数目
GLuint IDVertexShader[NumVertexShader];
GLuint IDFragmentShader[NumFragmentShader];
GLuint IDShaderProgram[NumShaderProgram];
GLuint IDVAO[NumVAO];
GLuint IDVBO[NumVBO];
GLuint IDEBO[NumEBO];
/*******************************************************************************
* 着色器源码
******************************************************************************/
const GLchar *vertexShaderSource =
"#version 330 core\n"
"layout(location = 0) in vec3 vPosition;\n"
"layout(location = 1) in vec3 vColor;\n"
"uniform mat4 model;\n"
"uniform mat4 view;\n"
"uniform mat4 projection;\n"
"out vec3 Color;\n"
"void main()\n"
"{\n"
"gl_Position = projection * view * model * vec4(vPosition, 1.0);\n"
"Color = vColor;\n"
"}\n";
const GLchar *fragmentShaderSource =
"#version 330 core\n"
"in vec3 Color;\n"
"out vec4 fColor;\n"
"void main()\n"
"{\n"
"fColor = vec4(Color, 1.0f);\n"
"}\n";
openglwindow::openglwindow(QWidget *parent)
:QOpenGLWidget(parent)
{
//设置OpenGL的版本信息
QSurfaceFormat format;
format.setRenderableType(QSurfaceFormat::OpenGL);
format.setProfile(QSurfaceFormat::CoreProfile);
format.setVersion(3,3);
setFormat(format);
}
openglwindow::~openglwindow()
{
}
void openglwindow::initializeGL()
{
//初始化OpenGL函数
initializeOpenGLFunctions();
//设置全局变量
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
/******************************* 顶点着色器创建 *******************************/
/* 第一个顶点着色器 */
IDVertexShader[0] = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(IDVertexShader[0], 1, &vertexShaderSource, nullptr);
glCompileShader(IDVertexShader[0]);
//检查编译是否出错
GLint success;
GLchar infoLog[512];
glGetShaderiv(IDVertexShader[0], GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(IDVertexShader[0], 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}
/******************************* 片段着色器创建 *******************************/
/* 第一个片元着色器 */
IDFragmentShader[0] = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(IDFragmentShader[0], 1, &fragmentShaderSource, nullptr);
glCompileShader(IDFragmentShader[
c9f4
0]);
//检查编译是否出错
glGetShaderiv(IDFragmentShader[0], GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(IDFragmentShader[0], 512, NULL, infoLog);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
}
/********************************* 链接着色器 *********************************/
/* 第一个着色器程序 */
IDShaderProgram[0] = glCreateProgram();
glAttachShader(IDShaderProgram[0], IDVertexShader[0]);
glAttachShader(IDShaderProgram[0], IDFragmentShader[0]);
glLinkProgram(IDShaderProgram[0]);
//检查链接错误
glGetProgramiv(IDShaderProgram[0], GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(IDShaderProgram[0], 512, NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
}
//删除着色器对象(生成着色器程序之后不再需要)
glDeleteShader(IDVertexShader[0]);
glDeleteShader(IDFragmentShader[0]);
/******************************** 设置顶点数据 ********************************/
//彩色正方体
GLfloat vertices[] =
{
-0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 1.0f,
0.5f, 0.5f, -0.5f, 0.8f, 0.5f, 0.2f,
-0.5f, 0.5f, -0.5f, 0.2f, 0.8f, 0.5f
};
GLuint indices[] =
{
0, 1, 2, 2, 3, 0, //前
4, 5, 6, 6, 7, 4, //后
0, 4, 7, 7, 3, 0, //左
1, 5, 6, 6, 2, 1, //右
0, 4, 5, 5, 1, 0, //上
3, 7, 6, 6, 2, 3 //下
};
/****************************************************************************/
/**************************** VAO\VBO\顶点属性指针 ****************************/
/****************************************************************************/
/* 创建相关对象 */
glGenVertexArrays(NumVAO, IDVAO);
glGenBuffers(NumVBO, IDVBO);
glGenBuffers(NumEBO, IDEBO);
/* 显示立方体 */
glBindVertexArray(IDVAO[0]); //开始记录状态信息
glBindBuffer(GL_ARRAY_BUFFER, IDVBO[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IDEBO[0]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3*sizeof(GLfloat)));
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0); //结束记录状态信息
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //在VAO后解绑,是为了不让VAO把解绑EBO的信息包含进入
/* 显示立方体 */
/* 固定属性区域 */
glEnable(GL_DEPTH_TEST); //开启深度测试
}
void openglwindow::paintGL()
{
//清理屏幕
glClear(GL_COLOR_BUFFER_BIT);
//实现参数的刷新
update();
//渲染彩色正方体
glUseProgram(IDShaderProgram[0]);
glm::mat4 view;
glm::mat4 projection;
glm::mat4 model;
GLint modelLoc = glGetUniformLocation(IDShaderProgram[0], "model");
GLint viewLoc = glGetUniformLocation(IDShaderProgram[0], "view");
GLint projLoc = glGetUniformLocation(IDShaderProgram[0], "projection");
view = glm::lookAt(cameraPos, worldCentrol, cameraUp);
projection = glm::perspective(glm::radians(45.0f), 4.0f / 3.0f, 0.1f, 100000.0f);
model = glm::translate(model, transVec);
model = glm::rotate(model, glm::radians(pitch), glm::vec3(1.0f, 0.0f, 0.0f)); //按住左键,上下拖动鼠标让立方体绕x轴旋转
model = glm::rotate(model, glm::radians(yaw), glm::vec3(0.0f, 1.0f, 0.0f)); //按住左键,左右拖动鼠标让立方体绕y轴旋转
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glBindVertexArray(IDVAO[0]);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
//强制刷新缓冲区,保证命令被执行
glFlush();
}
void openglwindow::resizeGL(int width, int height)
{
//未使用
Q_UNUSED(width);
Q_UNUSED(height);
}
void openglwindow::mouseMoveEvent(QMouseEvent *event)
{
//鼠标左键用来实现对物体的旋转功能
if(event->buttons() == Qt::LeftButton)
{
//计算yaw,pitch值的改变量
GLfloat xoffset = event->x() - lastX;
GLfloat yoffset = event->y() - lastY;
lastX = event->x();
lastY = event->y();
GLfloat sensitivity = 0.4f; //旋转时的灵敏度
xoffset *= sensitivity;
yoffset *= sensitivity;
yaw += xoffset;
pitch += yoffset;
//可以用来设置俯仰角的上下界
if (pitch > 89.0f)
pitch = 89.0f;
if (pitch < -89.0f)
pitch = -89.0f;
}
//鼠标右键用来实现对移动物体(即局部坐标在世界坐标中的移动)
else if(event->buttons() == Qt::RightButton)
{
//计算x,y方向的偏移量
GLfloat xoffset = event->x() - lastX;
GLfloat yoffset = event->y() - lastY;
lastX = event->x();
lastY = event->y();
GLfloat sensitivity = 0.01f; //移动时的灵敏度
xoffset *= sensitivity;
yoffset *= sensitivity;
//仅需在x-y平面内移动即可
transVec += glm::vec3(xoffset, -yoffset, 0.0f);
}
}
//滚轮实现对物体的放大缩小,摄像机距离远近(放大缩小)
void openglwindow::wheelEvent(QWheelEvent *event)
{
GLfloat sensitivity = 0.0005f;
cameraPos *= (1.0f - event->delta() * sensitivity);
}
void openglwindow::mousePressEvent(QMouseEvent *event)
{
//记录点击光标时的位置
lastX = event->x();
lastY = event->y();
}
运行结果:
现在可以看到在上一篇中绘制的立方体的全貌了。
编译环境及版本:Win10企业版+Qt 5.7.1(MSVC 2015, 32bit)+OpenGL3.3 Core Profile
相关文章推荐
- SilverLight学习笔记--如何创建弹出子窗口并与之交互
- kinect 2.0 SDK学习笔记(七)--matlab自带相机标定程序对kinect进行简单标定
- OpenGL_Qt学习笔记之_01(创建一个OpenGL窗口)
- OpenGl学习笔记1——建立一个可以支持OpenGL的窗口
- [置顶] OpenGL学习笔记之创建窗口
- Android NDK (学习笔记五) —— java层和native层进行字符串的交互处理
- 用glew,glfw实现opengl绘制3D学习笔记1-实现一个窗口
- OpenGL学习笔记2013.4.10第一个OpenGL窗口
- 交互设计学习笔记之《如何进行用户研究》【交互设计】
- lua学习笔记--交互模式简单说明
- OpenGL学习笔记 (1) —— 在VS2008下的两个简单例子
- OpenGL学习笔记2 —— 画立方体
- OpenGL_Qt学习笔记之_02(绘制简单平面几何图形)
- 【SSM学习笔记】Mybatis进行简单的CRUD操作
- openGL学习笔记 简单概念
- 学习笔记1--在Qt5中利用OpenGL渲染一个立方体
- LearnOpenGL学习笔记1:创建窗口
- OpenGL学习笔记:(二)简单绘制正方形(基本框架)
- OpenGL_Qt学习笔记之_01(创建一个OpenGL窗口)
- php学习笔记(九) php与web页面进行交互