• 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(
    00, 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.01000.0);
        }

        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        gluLookAt(
    0.00.010.00.00.00.00.01.00.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(), 
    55, viewport);
        
    const float aspect = static_cast<float>(viewport[2]) / viewport[3];
        gluPerspective(
    45.0, aspect, 1.01000.0);

        
    // Draw
        paintGL();

        
    // Reset matrix setting
        glMatrixMode(GL_PROJECTION);
        glPopMatrix();

        
    // Revert render mode
        int hits = glRenderMode(GL_RENDER);

        
    // Show selection
        printf("%d hits ", hits);
        
    if (hits > 0)
        {
            
    int id = 0;
            
    for (int i = 0; i < hits; i++)
            {
                printf(
    "Level: %u ", selectBuffer[id + 0]);
                printf(
    "  Min: %f ", (double)selectBuffer[id + 1] / UINT_MAX);
                printf(
    "  Max: %f ", (double)selectBuffer[id + 2] / UINT_MAX);
                printf(
    "   ID: %u ", 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

  • 相关阅读:
    cocos2dx遇到的一些坑
    cocos2dx场景切换的坑
    整合quickx到普通cocos2dx
    Hadoop、spark
    Redis高级特性及应用场景
    wpf相关好资源
    MVVM模式的几个开源框架
    ASP.NET的IIS映射
    NET 开发者必备的工具箱
    C#开源汇总
  • 原文地址:https://www.cnblogs.com/MakeView660/p/10648707.html
Copyright © 2020-2023  润新知