在之前的文章中講到了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