目录
1.概述
QGLWidget类是一个用于渲染OpenGL图形的小部件。
QGLWidget提供了显示集成到Qt应用程序中的OpenGL图形的功能。它使用起来非常简单。您可以继承它并像使用其他QWidget一样使用它的子类,除了您可以在使用QPainter和标准OpenGL呈现命令之间进行选择之外。
注意:QGLWidget这个类是遗留Qt OpenGL模块的一部分,和其他QGL类一样,应该在新的应用程序中避免使用。从Qt 5.4开始,推荐使用QOpenGLWidget和QOpenGL类。
QGLWidget提供了三个方便的虚拟函数,你可以在子类中重新实现它们来执行典型的OpenGL任务:
paintGL() -渲染OpenGL场景。在小部件需要更新时调用。
resizeGL() -设置OpenGL视图,投影等。在小部件调整大小时调用(以及在它第一次显示时调用,因为所有新创建的小部件都会自动获取一个调整大小事件)。
initializeGL() -设置OpenGL渲染上下文,定义显示列表等。在第一次调用resizeGL()或paintGL()之前调用一次。
以下是QGLWidget子类的大致轮廓:
class MyGLDrawer : public QGLWidget
{
Q_OBJECT // must include this if you use Qt signals/slots
public:
MyGLDrawer(QWidget *parent)
: QGLWidget(parent) {}
protected:
void initializeGL()
{
// Set up the rendering context, define display lists etc.:
...
glClearColor(0.0, 0.0, 0.0, 0.0);
glEnable(GL_DEPTH_TEST);
...
}
void resizeGL(int w, int h)
{
// setup viewport, projection etc.:
glViewport(0, 0, (GLint)w, (GLint)h);
...
glFrustum(...);
...
}
void paintGL()
{
// draw the scene:
...
glRotatef(...);
glMaterialfv(...);
glBegin(GL_QUADS);
glVertex3f(...);
glVertex3f(...);
...
glEnd();
...
}
};
综上所述,一般我们要做的事情就是重新实现一下initializeGL()、resizeGL(int w, int h)、paintGL()这3个函数。
2.代码实例-顶点绘制方式
main.cpp
#include "opengltest.h"
#include <QtWidgets/QApplication>
#include "myglwidget.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyGLWidget *widget = new MyGLWidget(NULL);
widget->show();
return a.exec();
}
myglwidget.h
#ifndef MYGLWIDGET_H
#define MYGLWIDGET_H
#include <QGLWidget>
class MyGLWidget : public QGLWidget
{
Q_OBJECT
public:
MyGLWidget(QWidget *parent);
~MyGLWidget();
protected:
void initializeGL();
void resizeGL(int w, int h);
void paintGL();
private:
};
#endif // MYGLWIDGET_H
myglwidget.cpp
#include "myglwidget.h"
#include "qapplication.h"
#include "qrect.h"
#include "QDesktopWidget"
MyGLWidget::MyGLWidget(QWidget *parent)
: QGLWidget(parent)
{
}
MyGLWidget::~MyGLWidget()
{
}
void MyGLWidget::initializeGL()
{
//获取屏幕大小
QRect deskRect = QApplication::desktop()->availableGeometry();
//设置窗口的坐标和尺寸,让窗口居中显示
setGeometry(deskRect.width()/2 - 500/2, deskRect.height()/2 - 300/2, 500, 300);
//清除颜色
glClearColor(0.0, 0.0, 0.0, 0);
}
void MyGLWidget::resizeGL(int w, int h)
{
glViewport(0, 0, (GLsizei)w, (GLsizei)h);
}
void MyGLWidget::paintGL()
{
//清屏
glClear(GL_COLOR_BUFFER_BIT);
// 设置两面均为顶点绘制方式
glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
// 设置CCW方向为“正面”,CCW即CounterClockWise,逆时针
glFrontFace(GL_CCW);
//逆时针绘制一个矩形,每个for循环对应一条边
glBegin(GL_POLYGON);
for (int i = 0;i < 125;i++)
{
glVertex2f(-0.5f + (0.5/125)*i, -0.5f);//绘制125个点,连成1条线段
}
for (int i = 0;i < 75;i++)
{
glVertex2f(0.0f, -0.5f + (0.5/75)*i);
}
for (int i = 0;i < 125;i++)
{
glVertex2f(0.0f - (0.5/125)*i, 0.0f);
}
for (int i = 0;i < 75;i++)
{
glVertex2f(-0.5f, 0.0f - (0.5/75)*i);
}
glEnd();
}
代码执行接结果
3.代码实例-线形绘制方式
线形绘制方式,只需要指定四个顶点的位置即可,系统会自动帮我们连成线。代码如下:
void MyGLWidget::paintGL()
{
//清屏
glClear(GL_COLOR_BUFFER_BIT);
// 设置反面为线形模式
glPolygonMode(GL_FRONT, GL_LINE);
glPolygonMode(GL_BACK, GL_LINE);
// 设置CCW方向为“正面”,CCW即CounterClockWise,逆时针
glFrontFace(GL_CCW);
glBegin(GL_POLYGON);
glVertex2f(-0.5f, -0.5f);
glVertex2f(0.0f, -0.5f);
glVertex2f(0.0f, 0.0f);
glVertex2f(-0.5f, 0.0f);
glEnd();
glBegin(GL_POLYGON);
glVertex2f(0.0f, 0.0f);
glVertex2f(0.0f, 0.5f);
glVertex2f(0.5f, 0.5f);
glVertex2f(0.5f, 0.0f);
glEnd();
}
4.坐标系讲解
一般我们将程序界面的中心点作为原点, 左边为X正半轴,上面为Y轴正半轴。然后我们在用代码画点时,用的不是绝对坐标,而是一个比例值。例如上图中(-0.5, -0.5)这个点是X轴负半轴的一半和Y轴负半轴的一半所表示的点,而程序左下角的点是X轴负半轴整个半轴长度和Y轴负半轴整个半轴长度所对应的点。文字描述比较抽象,最好直接看图吧。