健康养生网站模板,做网站需要多少钱一年,外贸建站 台州,网站开发先前台和后台文章目录 Qt的OpenGL窗口GLSL的实现摄像机类的实现简单的漫游器 Qt的OpenGL窗口 Qt主要是使用QOpenGLWidget来实现opengl的功能。 QOpenGLWidget 提供了三个便捷的虚函数#xff0c;可以重载#xff0c;用来重新实现典型的OpenGL任务#xff1a;
paintGL#xff1a;渲染… 文章目录 Qt的OpenGL窗口GLSL的实现摄像机类的实现简单的漫游器 Qt的OpenGL窗口 Qt主要是使用QOpenGLWidget来实现opengl的功能。 QOpenGLWidget 提供了三个便捷的虚函数可以重载用来重新实现典型的OpenGL任务
paintGL渲染OpenGL场景。widget 需要更新时调用。resizeGL设置OpenGL视口、投影等。widget 调整大小或首次显示时调用。initializeGL设置OpenGL资源和状态。第一次调用 resizeGL() / paintGL() 之前调用一次。如果需要从paintGL()以外的位置触发重新绘制典型示例是使用计时器设置场景动画则应调用widget的update()函数来安排更新。调用paintGL()、resizeGL()或initializeGL()时widget 的OpenGL呈现上下文将变为当前。如果需要从其他位置例如在 widget 的构造函数或自己的绘制函数中调用标准OpenGL API函数则必须首先调用makeCurrent()。QOpenGLFunctions_X_X_Core 提供OpenGL X.X版本核心模式的所有功能。是对OpenGL函数的封装initializeOpenGLFunctions初始化OpenGL函数将Qt里的函数指针指向显卡的函数。
#include QOpenGLWidget
#include QOpenGLFunctions_3_3_Core class MyOpenGLWidget : public QOpenGLWidget,QOpenGLFunctions_3_3_Core
{
Q_OBJECT
public:
explicit MyOpenGLWidget (QWidget *parent nullptr);
protected:
virtual void initializeGL();
virtual void resizeGL(int w, int h);
virtual void paintGL();
};void MyOpenGLWidget::initializeGL()
{initializeOpenGLFunctions();
}
void MyOpenGLWidget::resizeGL(int w, int h)
{Q_UNUSED(w);Q_UNUSED(h);
}
void MyOpenGLWidget::paintGL()
{glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}以上是最简单的实现版本。
GLSL的实现 由于是最简单的漫游器所以我们实现的版本只需要一个顶点着色器和一个片段着色器即可。 shapes.vert
#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;
}
shapes.frag
#version 330 core
out vec4 FragColor;
in vec2 texCoord;uniform sampler2D texturewall;
uniform sampler2D texturesmile;
uniform sampler2D textureSmall;uniform float ratio;
void main(){FragColor mix(texture(texturewall,texCoord),texture(texturesmile,texCoord),ratio);
}
摄像机类的实现 这边实现了一个可以对模型进行上下左右移动移动视角放大缩小的操作。 摄像机类初始化了几个变量
// 默认值
const float YAW -90.0f;
const float PITCH 0.0f;
const float SPEED 2.5f;
const float SENSITIVITY 0.1f;
const float ZOOM 45.0f;偏航角默认为90度灵敏度主要用于控制鼠标移动时视角的变化量。
#ifndef CAMERA_H
#define CAMERA_H#includeQMatrix4x4#include vector// 移动方向枚举量. 是一种抽象以避开特定于窗口系统的输入方法
// 我们这里是WSAD
enum Camera_Movement {FORWARD,BACKWARD,LEFT,RIGHT
};// 默认值
const float YAW -90.0f;
const float PITCH 0.0f;
const float SPEED 2.5f;
const float SENSITIVITY 0.1f;
const float ZOOM 45.0f;// 一个抽象的camera类用于处理输入并计算相应的Euler角度、向量和矩阵以便在OpenGL中使用
class Camera
{
public:// camera AttributesQVector3D Position;QVector3D Front;QVector3D Up;QVector3D Right;QVector3D WorldUp;// euler Anglesfloat Yaw;float Pitch;// camera optionsfloat MovementSpeed;float MouseSensitivity;float Zoom;// constructor with vectorsCamera(QVector3D position QVector3D(0.0f, 0.0f, 0.0f), QVector3D up QVector3D(0.0f, 1.0f, 0.0f), float yaw YAW, float pitch PITCH) : Front(QVector3D(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), MouseSensitivity(SENSITIVITY), Zoom(ZOOM){Position position;WorldUp up;Yaw yaw;Pitch pitch;updateCameraVectors();}// constructor with scalar valuesCamera(float posX, float posY, float posZ, float upX, float upY, float upZ, float yaw, float pitch) : Front(QVector3D(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), MouseSensitivity(SENSITIVITY), Zoom(ZOOM){Position QVector3D(posX, posY, posZ);WorldUp QVector3D(upX, upY, upZ);Yaw yaw;Pitch pitch;updateCameraVectors();}// returns the view matrix calculated using Euler Angles and the LookAt MatrixQMatrix4x4 GetViewMatrix(){QMatrix4x4 theMatrix;theMatrix.lookAt(Position, Position Front, Up);return theMatrix;}// 处理从任何类似键盘的输入系统接收的输入。接受摄像机定义枚举形式的输入参数从窗口系统中提取void ProcessKeyboard(Camera_Movement direction, float deltaTime){float velocity MovementSpeed * deltaTime;if (direction FORWARD)Position Front * velocity;if (direction BACKWARD)Position - Front * velocity;if (direction LEFT)Position - Right * velocity;if (direction RIGHT)Position Right * velocity;}// 处理从鼠标输入系统接收的输入。需要x和y方向上的偏移值。void ProcessMouseMovement(float xoffset, float yoffset, bool constrainPitch true){xoffset * MouseSensitivity;yoffset * MouseSensitivity;Yaw xoffset;Pitch yoffset;// 确保当投球超出边界时屏幕不会翻转if (constrainPitch){if (Pitch 89.0f)Pitch 89.0f;if (Pitch -89.0f)Pitch -89.0f;}// 使用更新的Euler角度更新前、右和上矢量updateCameraVectors();}// 处理从鼠标滚轮事件接收的输入。仅需要在垂直车轮轴上输入void ProcessMouseScroll(float yoffset){Zoom - (float)yoffset;if (Zoom 1.0f)Zoom 1.0f;if (Zoom 75.0f)Zoom 75.0f;}private:// 根据相机的更新的Euler角度计算前矢量void updateCameraVectors(){// calculate the new Front vectorfloat PI3.1415926;QVector3D front;front.setX(cos(Yaw*PI/180.0) * cos(Pitch*PI/180.0));front.setY( sin(Pitch*PI/180.0));front.setZ(sin(Yaw*PI/180.0) * cos(Pitch*PI/180.0));front.normalize();Front front;// also re-calculate the Right and Up vectorRight QVector3D::crossProduct(Front, WorldUp);// 标准化向量因为向上或向下看得越多向量的长度就越接近0这会导致移动速度变慢。Right.normalize();Up QVector3D::crossProduct(Right, Front);Up.normalize();}
};
#endif
简单的漫游器 漫游器的实现主要是通过Qt的窗口事件触发后将触发产生的位置偏量给摄像机类进行计算从摄像机类中得到视图矩阵将模型的位置进行改变。 myopenglwidget.h #ifndef MYOPENGLWIDGET_H
#define MYOPENGLWIDGET_H#include QOpenGLWidget
#include QOpenGLFunctions_3_3_Core
#include QOpenGLShaderProgram
#include QOpenGLTexture
#include QTimer
#include QElapsedTimer
#include camera.hclass MyOpenGLWidget : public QOpenGLWidget,QOpenGLFunctions_3_3_Core
{Q_OBJECT
public:enum Shape{None,Circle,Rect,Triangle};explicit MyOpenGLWidget(QWidget *parent nullptr);~MyOpenGLWidget();void DrawShape(Shape shape);void setWireFrameMode(bool enterWireframe);void onTimeout();
protected:virtual void initializeGL();virtual void resizeGL(int w, int h);virtual void paintGL();
signals:
private:Shape m_shape;QOpenGLShaderProgram shaderProgram;QOpenGLTexture *textureWall;QOpenGLTexture *textureSmile;QOpenGLTexture *textureSmall;QTimer *m_timer;QElapsedTimer m_time;Camera m_camera;// QWidget interface
protected:void keyPressEvent(QKeyEvent *event) override;void mouseMoveEvent(QMouseEvent *event) override;void wheelEvent(QWheelEvent *event) override;
};#endif // MYOPENGLWIDGET_H
myopenglwidget.cpp
#include myopenglwidget.h
#include QImage
#include QKeyEventfloat 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
};QVectorQVector3D 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)
};#define TIMEOUT 100unsigned int indices[] { // note that we start from 0!0, 1, 3, // first triangle1, 2, 3 // second triangle
};unsigned int VBO, VAO ,EBO;float ratio 0.5;
QPoint deltaPos;MyOpenGLWidget::MyOpenGLWidget(QWidget *parent): QOpenGLWidget{parent}
{setFocusPolicy(Qt::StrongFocus);setMouseTracking(true);m_timer new QTimer(this);connect(m_timer,QTimer::timeout,this,MyOpenGLWidget::onTimeout);m_timer-start(TIMEOUT);m_time.start();m_camera.Position QVector3D(0.0,0.0,3.0);
}MyOpenGLWidget::~MyOpenGLWidget()
{if(!isValid()) return;makeCurrent();glDeleteBuffers(1,VBO);glDeleteBuffers(1,EBO);glDeleteVertexArrays(1,VAO);doneCurrent();
}void MyOpenGLWidget::DrawShape(Shape shape)
{m_shapeshape;update();
}void MyOpenGLWidget::setWireFrameMode(bool enterWireframe)
{makeCurrent();if(enterWireframe)glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);elseglPolygonMode(GL_FRONT_AND_BACK,GL_FILL);update();doneCurrent();
}void MyOpenGLWidget::onTimeout()
{update();
}void MyOpenGLWidget::initializeGL()
{initializeOpenGLFunctions();//创建VBO和VAO对象并赋予IDglGenVertexArrays(1,VAO);glGenBuffers(1,VBO);//绑定VAO和VBO对象glBindVertexArray(VAO);glBindBuffer(GL_ARRAY_BUFFER,VBO);//为当前绑定到target的缓冲区对象创建一个新的数据存储。//如果data不是NULL则使用来自此指针的数据初始化数据存储glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL_STATIC_DRAW);//告知显卡如何解析缓冲里的属性值glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,5*sizeof(float),(void *)0);//开启VAO管理的第一个属性值glEnableVertexAttribArray(0);//告知显卡如何解析缓冲里的属性值glVertexAttribPointer(1,2,GL_FLOAT,GL_FALSE,5*sizeof(float),(void *)(3*sizeof(float)));//开启VAO管理的第三个属性值glEnableVertexAttribArray(1);glBindBuffer(GL_ARRAY_BUFFER,0);bool success;shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex,:Shaders/shapes.vert);shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment,:Shaders/shapes.frag);success shaderProgram.link();if(!success){qDebug()Error:shaderProgram.log();}shaderProgram.bind();shaderProgram.setUniformValue(ratio,ratio);shaderProgram.setUniformValue(texturewall,0);shaderProgram.setUniformValue(texturesmile,1);shaderProgram.setUniformValue(textureSmall,2);unsigned int EBO;glGenBuffers(1, EBO);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);glEnable(GL_BLEND);glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);textureWall new QOpenGLTexture(QImage(:Images/images/wall.jpg).mirrored());textureSmile new QOpenGLTexture(QImage(:Images/images/awesomeface.png).mirrored());textureSmall new QOpenGLTexture(QImage(:Images/images/small.png).mirrored());glBindVertexArray(0);}void MyOpenGLWidget::resizeGL(int w, int h)
{Q_UNUSED(w);Q_UNUSED(h);
}void MyOpenGLWidget::paintGL()
{QMatrix4x4 model;QMatrix4x4 view;QMatrix4x4 projection;viewm_camera.GetViewMatrix();glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glEnable(GL_DEPTH_TEST);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);shaderProgram.bind();projection.perspective(m_camera.Zoom,(float)width()/(height()),0.1,100.0);shaderProgram.setUniformValue(projection, projection);shaderProgram.setUniformValue(view, view);glBindVertexArray(VAO);//glDrawArrays(GL_TRIANGLES, 0, 3);switch(m_shape){case Rect:textureWall-bind(0);textureSmile-bind(1);textureSmall-bind(2);//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);foreach (auto item, cubePositions){model.setToIdentity();model.translate(item);shaderProgram.setUniformValue(model, model);glDrawArrays(GL_TRIANGLES,0,36);}break;case None:break;case Triangle:break;case Circle:break;}}void MyOpenGLWidget::keyPressEvent(QKeyEvent *event)
{float deltatimeTIMEOUT / 1000.0;switch(event-key()){case Qt::Key_Up:ratio 0.1;break;case Qt::Key_Down:ratio - 0.1;break;case Qt::Key_W: m_camera.ProcessKeyboard(FORWARD,deltatime);break;case Qt::Key_S: m_camera.ProcessKeyboard(BACKWARD,deltatime);break;case Qt::Key_D: m_camera.ProcessKeyboard(RIGHT,deltatime);break;case Qt::Key_A: m_camera.ProcessKeyboard(LEFT,deltatime);break;}if(ratio 1) ratio 1;if(ratio 0) ratio 0;makeCurrent();shaderProgram.bind();shaderProgram.setUniformValue(ratio,ratio);update();doneCurrent();
}void MyOpenGLWidget::mouseMoveEvent(QMouseEvent *event)
{static QPoint lastPos(width()/2,height()/2);auto currentPosevent-pos();deltaPoscurrentPos-lastPos;lastPoscurrentPos;m_camera.ProcessMouseMovement(deltaPos.x(),-deltaPos.y());update();
}void MyOpenGLWidget::wheelEvent(QWheelEvent *event)
{ m_camera.ProcessMouseScroll(event-angleDelta().y()/120);update();
}
完整代码链接