Qt OpenGL 鼠标拾取实现
在之前的文章中讲到了OpenGL鼠标拾取操作的例子,工作中需要在Qt中实现,下面的程序演示了QT中opengl的拾取例子。
本例子在Qt5.12和Qt Creator4.8.0上测试,使用的是QOpenGLWidget类,在窗口的正中央有红绿两个三角形组成一个正方形,分别点击不同的三角形部分进行对象拾取。
相关代码如下:
opengl_widget.h
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
#ifdef _MSC_VER
#pragma once #endif #ifndef _OPENGL_WIDGET_H_ #define _OPENGL_WIDGET_H_ #include <vector> #include <QtWidgets/qopenglwidget.h> class OpenGLWidget : public QOpenGLWidget { Q_OBJECT public: explicit OpenGLWidget(QWidget *parent = nullptr); virtual ~OpenGLWidget(); protected: virtual void initializeGL() override; virtual void paintGL() override; virtual void resizeGL(int w, int h) override; virtual void mousePressEvent(QMouseEvent *ev) override; virtual void mouseMoveEvent(QMouseEvent *ev) override; virtual void mouseReleaseEvent(QMouseEvent *ev) override; private: void drawObjects() const; using uint = unsigned int; static const int selectBufferSize = 100; std::vector<uint> selectBuffer = std::vector<uint>(selectBufferSize); }; // class OpenGLWidget #endif // _OPENGL_WIDGET_H_ |
opengl_widget.cpp
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
#include "opengl_widget.h"
#include <gl/GLU.h> #include <QtGui/qevent.h> OpenGLWidget::OpenGLWidget(QWidget *parent) : QOpenGLWidget(parent) { } OpenGLWidget::~OpenGLWidget() { } void OpenGLWidget::initializeGL() { glEnable(GL_DEPTH_TEST); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); } void OpenGLWidget::resizeGL(int w, int h) { glViewport(0, 0, w, h); } void OpenGLWidget::paintGL() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); int renderMode; glGetIntegerv(GL_RENDER_MODE, &renderMode); if (renderMode != GL_SELECT) { // Matrix setting glMatrixMode(GL_PROJECTION); glLoadIdentity(); const float aspect = static_cast<float>(width()) / height(); gluPerspective(45.0, aspect, 1.0, 1000.0); } glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); drawObjects(); } void OpenGLWidget::mousePressEvent(QMouseEvent *ev) { // Selection buffer std::fill(selectBuffer.begin(), selectBuffer.end(), 0); glSelectBuffer(selectBufferSize, &selectBuffer[0]); // Draw for selection buffer glRenderMode(GL_SELECT); // Matrix setting glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); int viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); gluPickMatrix(ev->x(), height() - ev->y(), 5, 5, viewport); const float aspect = static_cast<float>(viewport[2]) / viewport[3]; gluPerspective(45.0, aspect, 1.0, 1000.0); // Draw paintGL(); // Reset matrix setting glMatrixMode(GL_PROJECTION); glPopMatrix(); // Revert render mode int hits = glRenderMode(GL_RENDER); // Show selection printf("%d hits\n", hits); if (hits > 0) { int id = 0; for (int i = 0; i < hits; i++) { printf("Level: %u\n", selectBuffer[id + 0]); printf(" Min: %f\n", (double)selectBuffer[id + 1] / UINT_MAX); printf(" Max: %f\n", (double)selectBuffer[id + 2] / UINT_MAX); printf(" ID: %u\n", selectBuffer[id + 3]); id += 4; } } } void OpenGLWidget::mouseMoveEvent(QMouseEvent *ev) { } void OpenGLWidget::mouseReleaseEvent(QMouseEvent *ev) { } void OpenGLWidget::drawObjects() const { // Prepare for selection glInitNames(); glPushName(0); // First glColor3f(1.0f, 0.0f, 0.0f); glLoadName(1); glBegin(GL_TRIANGLES); glVertex3f(-1.0f, -1.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 0.0f); glEnd(); // Second glColor3f(0.0f, 1.0f, 0.0f); glLoadName(2); glBegin(GL_TRIANGLES); glVertex3f(-1.0f, -1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 0.0f); glEnd(); } |
运行测试:
程序中使用了printf作为输出,但是其不能直接打印在Qt的应用程序输出窗口,需要进程结束后才会打印,可以使用qDebug来替代printf。
在测试过程中,我遇到了无论点击屏幕哪里,都会将所有的对象选中的情况,查找一些资料对比试验后,提醒要注意gluLookAt、gluPerspective的调用位置。
仅供参考,出自github:https://github.com/tatsy/QtOpenGLMousePick
希望大家能把自己的所学和他人一起分享,不要去鄙视别人索取时的贪婪,因为最应该被鄙视的是不肯分享时的吝啬。