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

转载于:https://www.cnblogs.com/MakeView660/p/10648707.html

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值