效果:
还是先了解下OpenGL吧
OpenGL(Open Graphics Library)是一种跨平台的图形渲染API,用于创建高性能的2D和3D图形应用程序。
绘制基本图形:OpenGL可以绘制诸如点、线、三角形等基本图形。它使用顶点数据指定图形的形状和位置。
着色器:OpenGL使用着色器来计算图形的颜色和光照。着色器是一段程序代码,运行在GPU上,可以以高效的方式计算图形的颜色。
纹理:OpenGL可以使用纹理来添加图形的细节和纹理。纹理是一个图像,可以应用到图形表面上。
变换:OpenGL可以使用矩阵变换来旋转、缩放、平移等操作。使用矩阵变换可以改变图形的位置、大小和方向。
深度测试:OpenGL可以使用深度测试来确定哪些图形在前面和哪些图形在后面。深度测试可以避免图形重叠和混合。
帧缓冲:OpenGL使用帧缓冲来存储渲染的图像。帧缓冲是一个内存区域,可以用于存储图形渲染结果。
扩展:OpenGL支持许多扩展,可以提供额外的功能,例如多重采样、纹理压缩、着色器语言等。
我们主要使用三个OpenGL窗口部件的成员函数
void initializeGL();
void resizeGL(int w, int h);
void paintGL();
void initializeGL()
该函数用于初始化OpenGL上下文,其中包括OpenGL的状态信息、纹理、着色器等。在该函数中,我们可以设置OpenGL的一些状态,比如背景颜色、深度测试、光照等等。该函数只会在OpenGL上下文第一次被创建时调用一次。
void resizeGL(int w, int h)
该函数用于调整OpenGL窗口的大小。在该函数中,我们可以根据窗口大小调整OpenGL的视口、投影矩阵等参数。该函数在窗口大小发生变化时被调用。
void paintGL()
该函数用于绘制OpenGL窗口的内容,即在窗口中绘制图形或者场景。在该函数中,我们可以使用OpenGL的各种绘制函数,比如绘制点、线、面等等,也可以使用着色器进行高级渲染。该函数在窗口需要重绘时被调用,比如窗口大小发生变化、用户交互等事件触发重绘。
QGLWidget还有很多成员函数:
void makeCurrent();//将OpenGL上下文设置为当前上下文。
void doneCurrent();//释放当前的OpenGL上下文。
void swapBuffers();//交换前后缓冲区,将绘制的图像显示在窗口中。
void setAutoBufferSwap(bool on);//设置是否自动交换前后缓冲区。
void setMouseTracking(bool enable);//设置是否开启鼠标跟踪功能。
void updateGL();//强制重绘OpenGL窗口。
void setFormat(const QGLFormat &format);//设置OpenGL的格式。
const QGLFormat& format() const;//获取OpenGL的格式。
void setViewport(int x, int y, int width, int height);//设置OpenGL的视口。
void setProjectionMatrix(const QMatrix4x4 &matrix);//设置OpenGL的投影矩阵。
void setModelViewMatrix(const QMatrix4x4 &matrix);//设置OpenGL的模型视图矩阵。
void setClearColor(const QColor &color);//设置OpenGL的背景颜色。
void setDepthTest(bool enable);//设置是否开启深度测试。
void setLighting(bool enable);//设置是否开启光照。
void setTextureEnabled(bool enable);//设置是否开启纹理。
void setTexture(const QImage &image);//设置OpenGL的纹理。
void setShaderProgram(QGLShaderProgram *program);//设置OpenGL的着色器程序。
void setPointSize(float size);//设置OpenGL绘制点的大小。
void setLineWidth(float width);//设置OpenGL绘制线的宽度。
void drawPoint(const QPointF &point);//绘制一个点。
void drawLine(const QPointF &p1, const QPointF &p2);//绘制一条线。
void drawRect(const QRectF &rect);//绘制一个矩形。
void drawEllipse(const QRectF &rect):绘制一个椭圆。
void drawPolygon(const QPolygonF &polygon);绘制一个多边形。
void drawText(const QPointF &point, const QString &text);//绘制一段文本。
void renderText(int x, int y, int z, const QString &text, const QFont &font = QFont());//渲染一段文本。
根据鼠标移动的距离dx和dy更新m_rotation(旋转角度)变量,根据m_rotation.x()和m_rotation.y()创建四元数xRot和yRot,
void OpenGLWidget::rotate(int dx, int dy)
{
m_rotation.setX(m_rotation.x() + dy);
m_rotation.setY(m_rotation.y() + dx);
QQuaternion xRot = QQuaternion::fromAxisAndAngle(1, 0, 0, m_rotation.x());//x、y、z坐标和旋转角度
QQuaternion yRot = QQuaternion::fromAxisAndAngle(0, 1, 0, m_rotation.y());
m_transform.setToIdentity();
m_transform.translate(m_translation);
m_transform.rotate(xRot * yRot);
}
使用m_transform.setToIdentity()函数将变换矩阵重置为单位矩阵,然后使用m_transform.translate()函数添加平移变换,将立方体平移到正确的位置。
void OpenGLWidget::translate(int dx, int dy)
{
m_translation.setX(m_translation.x() + dx * 0.01);
m_translation.setY(m_translation.y() - dy * 0.01);
//将变换矩阵重置为单位矩阵
m_transform.setToIdentity();
//将立方体平移到正确的位置
m_transform.translate(m_translation);
//将旋转变换矩阵应用到m_transform中
m_transform.rotate(QQuaternion::fromAxisAndAngle(1, 0, 0, m_rotation.x()));
m_transform.rotate(QQuaternion::fromAxisAndAngle(0, 1, 0, m_rotation.y()));
}
按下记录坐标位置,左键调用rotate()右键则调运translate();
void OpenGLWidget::mousePressEvent(QMouseEvent *event)
{
m_lastPos = event->pos();
}
void OpenGLWidget::mouseMoveEvent(QMouseEvent *event)
{
int dx = event->x() - m_lastPos.x();
int dy = event->y() - m_lastPos.y();
if (event->buttons() & Qt::LeftButton) {
rotate(dx, dy);
} else if (event->buttons() & Qt::RightButton) {
translate(dx, dy);
}
m_lastPos = event->pos();
update();
}
#ifndef OPENGLWIDGET_H
#define OPENGLWIDGET_H
#include
#include
#include
class OpenGLWidget : public QGLWidget
{
public:
OpenGLWidget(QWidget *parent = 0);
~OpenGLWidget();
protected:
void initializeGL();
void resizeGL(int w, int h);
void paintGL();
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
private:
QVector3D m_rotation;
QVector3D m_translation;
QMatrix4x4 m_transform;
QPoint m_lastPos;
void drawCube();
void rotate(int dx, int dy);
void translate(int dx, int dy);
};
#endif // OPENGLWIDGET_H
#include "openglwidget.h"
OpenGLWidget::OpenGLWidget(QWidget *parent): QGLWidget(parent)
{
QGLFormat format;
format.setVersion(2, 1);
format.setProfile(QGLFormat::CoreProfile);
setFormat(format);
setWindowTitle(tr("MyOpenGL"));
resize(640, 480);
drawCube();
}
OpenGLWidget::~OpenGLWidget()
{
}
void OpenGLWidget::initializeGL()
{
qDebug()<<glGetString(GL_VERSION)<<endl;
glClearColor(1.0, 1.0, 1.0, 0.0);
glColor3f(0.0f, 1.0f, 0.0f);
glEnable(GL_DEPTH_TEST);
glEnable(GL_POINT_SMOOTH);
glPointSize(12.0);
}
void OpenGLWidget::resizeGL(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, (float)w/(float)h, 0.1, 100.0);
glMatrixMode(GL_MODELVIEW);
}
void OpenGLWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
glPushMatrix();
glMultMatrixf(m_transform.constData());
drawCube();
glPopMatrix();
}
void OpenGLWidget::mousePressEvent(QMouseEvent *event)
{
m_lastPos = event->pos();
}
void OpenGLWidget::mouseMoveEvent(QMouseEvent *event)
{
int dx = event->x() - m_lastPos.x();
int dy = event->y() - m_lastPos.y();
if (event->buttons() & Qt::LeftButton) {
rotate(dx, dy);
} else if (event->buttons() & Qt::RightButton) {
translate(dx, dy);
}
m_lastPos = event->pos();
update();
}
void OpenGLWidget::drawCube()
{
glBegin(GL_POINTS);
glVertex3f(-1.0, -1.0, 1.0);
glVertex3f(1.0, -1.0, 1.0);
glVertex3f(1.0, 1.0, 1.0);
glVertex3f(-1.0, 1.0, 1.0);
glVertex3f(-1.0, -1.0, -1.0);
glVertex3f(1.0, -1.0, -1.0);
glVertex3f(1.0, 1.0, -1.0);
glVertex3f(-1.0, 1.0, -1.0);
glEnd();
glBegin(GL_LINE_LOOP);
glVertex3f(-1.0, -1.0, 1.0);
glVertex3f(1.0, -1.0, 1.0);
glVertex3f(1.0, 1.0, 1.0);
glVertex3f(-1.0, 1.0, 1.0);
glEnd();
glBegin(GL_LINE_LOOP);
glVertex3f(-1.0, -1.0, -1.0);
glVertex3f(1.0, -1.0, -1.0);
glVertex3f(1.0, 1.0, -1.0);
glVertex3f(-1.0, 1.0, -1.0);
glEnd();
glBegin(GL_LINES);
glVertex3f(-1.0, -1.0, 1.0);
glVertex3f(-1.0, -1.0, -1.0);
glVertex3f(1.0, -1.0, 1.0);
glVertex3f(1.0, -1.0, -1.0);
glVertex3f(1.0, 1.0, 1.0);
glVertex3f(1.0, 1.0, -1.0);
glVertex3f(-1.0, 1.0, 1.0);
glVertex3f(-1.0, 1.0, -1.0);
glEnd();
}
void OpenGLWidget::rotate(int dx, int dy)
{
m_rotation.setX(m_rotation.x() + dy);
m_rotation.setY(m_rotation.y() + dx);
QQuaternion xRot = QQuaternion::fromAxisAndAngle(1, 0, 0, m_rotation.x());
QQuaternion yRot = QQuaternion::fromAxisAndAngle(0, 1, 0, m_rotation.y());
m_transform.setToIdentity();
m_transform.translate(m_translation);
m_transform.rotate(xRot * yRot);
}
void OpenGLWidget::translate(int dx, int dy)
{
m_translation.setX(m_translation.x() + dx * 0.01);
m_translation.setY(m_translation.y() - dy * 0.01);
m_transform.setToIdentity();
m_transform.translate(m_translation);
m_transform.rotate(QQuaternion::fromAxisAndAngle(1, 0, 0, m_rotation.x()));
m_transform.rotate(QQuaternion::fromAxisAndAngle(0, 1, 0, m_rotation.y()));
}