QT+OpenGL实现可鼠标拖动旋转正方体

效果:

还是先了解下OpenGL吧

OpenGL的基础知识:

OpenGL(Open Graphics Library)是一种跨平台的图形渲染API,用于创建高性能的2D和3D图形应用程序。
绘制基本图形:OpenGL可以绘制诸如点、线、三角形等基本图形。它使用顶点数据指定图形的形状和位置。
着色器:OpenGL使用着色器来计算图形的颜色和光照。着色器是一段程序代码,运行在GPU上,可以以高效的方式计算图形的颜色。
纹理:OpenGL可以使用纹理来添加图形的细节和纹理。纹理是一个图像,可以应用到图形表面上。
变换:OpenGL可以使用矩阵变换来旋转、缩放、平移等操作。使用矩阵变换可以改变图形的位置、大小和方向。
深度测试:OpenGL可以使用深度测试来确定哪些图形在前面和哪些图形在后面。深度测试可以避免图形重叠和混合。
帧缓冲:OpenGL使用帧缓冲来存储渲染的图像。帧缓冲是一个内存区域,可以用于存储图形渲染结果。
扩展:OpenGL支持许多扩展,可以提供额外的功能,例如多重采样、纹理压缩、着色器语言等。

QGLWidget成员函数

我们主要使用三个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();
}

.h文件

#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

.c文件

#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()));
}


你可能感兴趣的:(Qt,qt,c++,开发语言)