Qt使用OpenGL實(shí)現(xiàn)繪制3D圖形
前言
OpenGL是一個(gè)跨平臺(tái)的、用來渲染3D圖形的標(biāo)準(zhǔn)API,Qt對(duì)OpenGL提供了強(qiáng)大的支持。Qt4時(shí)代的QtOpenGL模塊在Qt5中已經(jīng)不再建議使用,OpenGL相關(guān)的類被移到了QtGUI模塊。QtWidgets模塊中的QOpenGLWidget類提供了一個(gè)可以渲染OpenGL圖形的部件,通過該部件可以輕松地將OpenGL圖形整合到Qt應(yīng)用程序中。
項(xiàng)目效果

一、Qt下使用OpenGL繪制圖形介紹
QOpenGLWidget類是一個(gè)用來渲染OpenGL圖形的部件,它提供了在Qt應(yīng)用程序中顯示 OpenGL圖形的功能。這個(gè)類使用起來很簡單,只需要繼承該類,然后像使用其他QWidget 部件一樣來使用它即可。QGLWidget 提供了3個(gè)方便的虛函數(shù),可以在子類中重新實(shí)現(xiàn)它們來執(zhí)行典型的 OpenGL任務(wù):
- initializeGL():設(shè)置 OpenGL資源和狀態(tài),該函數(shù)只在第一次調(diào)用resizeGL()或paintGL()前被調(diào)用一次;
- resizeGL():設(shè)置OpenGL的視口投影等,每次部件改變大小時(shí)都會(huì)調(diào)用該函數(shù);
- paintGL():渲染OpenGL 場景,每當(dāng)部件需要更新時(shí)都會(huì)調(diào)用該函數(shù)。
這里介紹下Qt下一些類的使用和OpenGL中重要的概念或名稱,
QOpenGLShader:用來創(chuàng)建和編譯著色器。著色器是使用 OpenGL著色語言(OpenGL Shading Language,GLSL)編寫的一個(gè)小型函數(shù)。繪圖時(shí)需要至少指定兩個(gè)著色器;頂點(diǎn)著色器(vertexshader)和片段著色器(fragmentshader,也稱為片元著色器)
QOpenGLShaderProgram:用來創(chuàng)建并設(shè)置著色器程序,可以鏈接多個(gè)著色器,并在OpenGL當(dāng)前環(huán)境(current context,也稱為當(dāng)前上下文)中綁定著色器程序
QAbstractOpenGLFunctions:是一個(gè)類族的基類,類族中的類涉及了所有 OpenGL 版本,并為相應(yīng)版本 OpenGL 的所有函數(shù)提供了訪問接口
QOpenGLBuffer:用來創(chuàng)建并管理OpenGL緩存對(duì)象
QOpenGLTexture:封裝了一個(gè)OpenGL紋理對(duì)象,可以使用該類來設(shè)置紋理
二、示例完整代碼
1.MyOpenGL.pro
QT += widgets
HEADERS += \
myopenglwidget.h
SOURCES += \
main.cpp \
myopenglwidget.cpp
2.myopenglwidget.h
#ifndef MYOPENGLWIDGET_H
#define MYOPENGLWIDGET_H
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLBuffer>
#include <QOpenGLTexture>
#include <QOpenGLShaderProgram>
#include <QKeyEvent>
class QOpenGLTexture;
class QOpenGLShaderProgram;
class MyOpenGLWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
Q_OBJECT
public:
explicit MyOpenGLWidget(QWidget *parent = 0);
protected:
void initializeGL();
void paintGL();
void resizeGL(int width,int height);
void keyPressEvent(QKeyEvent *event);
private:
QOpenGLShaderProgram *program;
QOpenGLBuffer vbo;
QOpenGLTexture *textures[2];
GLfloat translate,xRot,yRot,zRot;
};
#endif // MYOPENGLWIDGET_H
3.myopenglwidget.cpp
#include "myopenglwidget.h"
MyOpenGLWidget::MyOpenGLWidget(QWidget *parent)
: QOpenGLWidget(parent)
{
//初始化變量
translate = -6.0;
xRot = zRot = 0.0;
yRot = -30.0;
}
void MyOpenGLWidget::initializeGL()
{
//初始化紋理變量
for(int i=0;i<2;i++)
{
textures[i] = new QOpenGLTexture(QImage(QString("../MyOpenGL/side%1.jpg").arg(i+1)).mirrored());
}
//為當(dāng)前環(huán)境初始化OpenGL環(huán)境
initializeOpenGLFunctions();
//開啟深度測試
glEnable(GL_DEPTH_TEST);
//下列著色器使用書中代碼運(yùn)行報(bào)錯(cuò),進(jìn)行了修正
//創(chuàng)建頂點(diǎn)著色器
QOpenGLShader *vshader = new QOpenGLShader(QOpenGLShader::Vertex,this);
const char *vsrc = "#version 330\n"
"in vec4 vPosition;\n"
"in vec2 vTexCoord;\n"
"out vec2 texCoord;\n"
"uniform mat4 matrix;\n"
"void main()\n"
"{\n"
" texCoord = vTexCoord;\n"
" gl_Position = matrix * vPosition;\n"
"}\n";
vshader->compileSourceCode(vsrc);
//創(chuàng)建片段著色器
QOpenGLShader *fshader = new QOpenGLShader(QOpenGLShader::Fragment,this);
const char *fsrc = "#version 330\n"
"uniform sampler2D tex;\n"
"in vec2 texCoord;\n"
"out vec4 fColor;\n"
"void main()\n"
"{\n"
" fColor = texture(tex,texCoord);\n"
"}\n";
fshader->compileSourceCode(fsrc);
//創(chuàng)建著色器程序
program = new QOpenGLShaderProgram;
program->addShader(vshader);
program->addShader(fshader);
program->link();
program->bind();
}
void MyOpenGLWidget::paintGL()
{
//設(shè)置視口為正方形
int w = width();
int h = height();
int side = qMin(w,h);
glViewport((w-side)/2,(h-side)/2,side,side);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//頂點(diǎn)位置
GLfloat vertices[2][4][3] =
{
{{-0.8f,0.8f,0.8f},{-0.8f,-0.8f,0.8f},{0.8f,-0.8f,0.8f},{0.8f,0.8f,0.8f}},
{{0.8f,0.8f,0.8f},{0.8f,-0.8f,0.8f},{0.8f,-0.8f,-0.8f},{0.8f,0.8f,-0.8f}}
};
//添加緩存
vbo.create();
vbo.bind();
vbo.allocate(vertices,48*sizeof(GLfloat));
GLuint vPosition = program->attributeLocation("vPosition");
//glVertexAttribPointer(vPosition,2,GL_FLOAT,GL_FALSE,0,vertices);
program->setAttributeBuffer(vPosition,GL_FLOAT,0,3,0);
glEnableVertexAttribArray(vPosition);
//頂點(diǎn)著色
GLfloat coords[2][4][2] =
{
{{0.0f,1.0f},{0.0f,0.0f},{1.0f,0.0f},{1.0f,1.0f}},
{{0.0f,1.0f},{0.0f,0.0f},{1.0f,0.0f},{1.0f,1.0f}}
};
vbo.write(24*sizeof(GLfloat),coords,16*sizeof(GLfloat));
GLuint vTexCoord = program->attributeLocation("vTexCoord");
program->setAttributeBuffer(vTexCoord,GL_FLOAT,24*sizeof(GLfloat),2,0);
glEnableVertexAttribArray(vTexCoord);
program->setUniformValue("tex",0);
//頂點(diǎn)變換
QMatrix4x4 matrix;
matrix.perspective(45.0f,(GLfloat)w/(GLfloat)h,0.1f,100.0f);
matrix.translate(0,0,translate);
matrix.rotate(xRot,1.0,0.0,0.0);
matrix.rotate(yRot,0.0,1.0,0.0);
matrix.rotate(zRot,0.0,0.0,1.0);
program->setUniformValue("matrix",matrix);
//繪制函數(shù)
for(int i=0;i<2;i++)
{
textures[i]->bind();
glDrawArrays(GL_TRIANGLE_FAN,i*4,4);
}
}
void MyOpenGLWidget::resizeGL(int,int)
{
}
//按鍵事件
void MyOpenGLWidget::keyPressEvent(QKeyEvent *event)
{
switch(event->key())
{
case Qt::Key_Up:
xRot -= 10;
break;
case Qt::Key_Down:
xRot += 10;
break;
case Qt::Key_Left:
yRot -= 10;
break;
case Qt::Key_Right:
yRot += 10;
break;
case Qt::Key_PageUp:
zRot -= 10;
break;
case Qt::Key_PageDown:
zRot += 10;
break;
case Qt::Key_Space:
translate += 1;
break;
case Qt::Key_Alt:
translate -= 1;
break;
default:
break;
}
update();
QOpenGLWidget::keyPressEvent(event);
}
4.main.cpp
#include <QApplication>
#include "myopenglwidget.h"
int main(int argc,char *argv[])
{
QApplication app(argc,argv);
MyOpenGLWidget w;
w.resize(400,300);
w.show();
return app.exec();
}
到此這篇關(guān)于Qt使用OpenGL實(shí)現(xiàn)繪制3D圖形的文章就介紹到這了,更多相關(guān)Qt OpenGL繪制3D圖形內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
如何實(shí)現(xiàn)在C++中調(diào)用C函數(shù)
這篇文章主要介紹了如何實(shí)現(xiàn)在C++中調(diào)用C函數(shù)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-08-08
VisualStudio2019配置OpenCV4.5.0的方法示例
這篇文章主要介紹了VisualStudio2019配置OpenCV4.5.0的方法示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03
C++中std::vector Vs std::deque VS std::li
本文對(duì)比了C++中vector、deque和list的核心差異,重點(diǎn)分析內(nèi)存布局、性能特性及迭代器失效規(guī)則,建議優(yōu)先使用vector(緩存友好、高效遍歷),deque適用于雙端操作,list僅在需穩(wěn)定迭代器或O(1)節(jié)點(diǎn)移動(dòng)時(shí)使用,強(qiáng)調(diào)避免頻繁小分配與迭代器失效風(fēng)險(xiǎn)2025-09-09
基于Qt播放器的實(shí)現(xiàn)詳解(支持Rgb,YUV格式)
這篇文章主要為大家詳細(xì)介紹了如何利用Qt實(shí)現(xiàn)簡易的播放器,可以支持支持Rgb,YUV格式。文中的示例代碼講解詳細(xì),感興趣的小伙伴可以嘗試一下2022-12-12
C語言實(shí)現(xiàn)超市信息管理系統(tǒng)課程設(shè)計(jì)
這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)超市信息管理系統(tǒng)課程設(shè)計(jì),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
C語言實(shí)現(xiàn)帶頭雙向環(huán)形鏈表
這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)帶頭雙向環(huán)形鏈表,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-11-11

