opengl之鼠标拾取(五)

我很懒,直接看代码吧,相信你没问题。

头文件:

#ifndef PICKENTITY_H
#define PICKENTITY_H

#include "base_render.h"
#include <memory>
namespace View3D{

class PickEntity:public QObject, public BaseRender
{
    Q_OBJECT
public:
    PickEntity();
    ~PickEntity();

    void inputVertices(
            GLfloat* vertices_t,
            uint32_t num_t,
            GLuint* tri_indexs_t,
            uint32_t num_tri_t);

    inline void setDrawId(uint32_t id_t){
        m_draw_id = id_t;}

    virtual void entityInitializeGL() override;
    virtual void bindData() override;
    virtual void entityPaintGL() override;

public slots:
    void rePicked(QPoint m_pos_t);


public:
    int pickedID;

private:
    uint32_t m_draw_id;
    GLfloat* vertices_ptr;
    uint32_t num_vertices;
    GLuint* indexes_ptr;
    uint32_t num_tri;

    QOpenGLShaderProgram pickingProgram;
    std::vector<GLuint> VBO, VAO, EBO;
    std::vector<uint32_t> num_tri_vect;

    QPoint mouse_pos;
    bool m_if_picked;

    bool redraw;
};

}

#endif // PICKENTITY_H

实现:

#include "pick_entity.h"
#include <sstream>
namespace View3D{

/*****************************************************/
PickEntity::PickEntity():
    vertices_ptr(nullptr),
    num_vertices(0),
    indexes_ptr(nullptr),
    num_tri(0){
    colorset = QVector3D(1.0f, 0.2f, 1.0f);
    redraw = false;
    m_if_picked = false;
    mouse_pos.setX(0);
    mouse_pos.setY(0);
    pickedID = -1;
    m_draw_id = 0;
}

PickEntity::~PickEntity(){
    if(redraw)
    {
        for(int i = 0; i < VAO.size(); i++)
        {
            glDeleteVertexArrays(1, &(VAO[i]));
            glDeleteBuffers(1, &(VBO[i]));
            glDeleteBuffers(1, &(EBO[i]));
        }
    }
}

/*****************************************************/
void PickEntity::inputVertices(
        GLfloat* vertices_t,
        uint32_t num_t,
        GLuint* tri_indexs_t,
        uint32_t num_tri_t){

    vertices_ptr = vertices_t;
    num_vertices = num_t;
    indexes_ptr = tri_indexs_t;
    num_tri = num_tri_t;

    num_tri_vect.push_back(num_tri);

    GLuint id_t(0);
    VBO.push_back(id_t);
    VAO.push_back(id_t);
    EBO.push_back(id_t);
}

/*****************************************************/
void PickEntity::entityInitializeGL(){
    initializeOpenGLFunctions();

    // Create and compile our GLSL program from the shaders
    bool success = pickingProgram.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/pick.vert");
    if (!success) {
       qDebug() << "shaderProgram addShaderFromSourceFile failed!" << pickingProgram.log();
       return;
    }
    success = pickingProgram.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/pick.frag");
    if (!success) {
       qDebug() << "shaderProgram addShaderFromSourceFile failed!" << pickingProgram.log();
       return;
    }
    success = pickingProgram.link();
    if(!success) {
       qDebug() << "shaderProgram link failed!" << pickingProgram.log();
    }
}

/*****************************************************/
void PickEntity::bindData()
{
    //vao
    glGenVertexArrays(1, &VAO.back());
    glBindVertexArray(VAO.back());

    // Load it into a VBO
    //GLuint vertexbuffer;
    glGenBuffers(1, &VBO.back());
    glBindBuffer(GL_ARRAY_BUFFER, VBO.back());
    glBufferData(GL_ARRAY_BUFFER, num_vertices * sizeof(float), vertices_ptr, GL_STATIC_DRAW);

    // Generate a buffer for the indices as well
    //GLuint elementbuffer;
    glGenBuffers(1, &EBO.back());
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO.back());
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, num_tri * sizeof(unsigned int), indexes_ptr, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (void*)0);
    glEnableVertexAttribArray(0);

    redraw = true;
}

/*****************************************************/
void PickEntity::entityPaintGL(){
    pickingProgram.bind();

    // (Instead of picking each frame if the mouse button is down,
    // you should probably only check if the mouse button was just released)
    if (!m_if_picked){

        QMatrix4x4 MVP = projection * view * model;
        // Send our transformation to the currently bound shader,
        // in the "MVP" uniform
        pickingProgram.setUniformValue("MVP", MVP);

        for(int i = 0; i < VAO.size(); i++)
        {
            // Convert "i", the integer mesh ID, into an RGB color
            int r = (i & 0x000000FF) >>  0;
            int g = (i & 0x0000FF00) >>  8;
            int b = (i & 0x00FF0000) >> 16;

            // OpenGL expects colors to be in [0,1], so divide by 255. r/255.0f
            pickingProgram.setUniformValue("PickingColor", QVector4D(r/255.0f, g/255.0f, b/255.0f, 1.0f));

            glBindVertexArray(VAO[i]);
            // Draw the triangles !
            glDrawElements(GL_TRIANGLES, num_tri_vect[i], GL_UNSIGNED_INT, 0);
        }

        glFlush();
        glFinish();

        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
        unsigned char data[4];
        glReadPixels(mouse_pos.x(), Widget->height()-mouse_pos.y(), 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, data);
        //
        // Convert the color back to an integer ID
        pickedID = data[0] + data[1] * 256 + data[2] * 256 * 256;
        qDebug() << "Pixel:" << data[0]<<" "<< data[1] <<" "<<data[2];

        QString message("background");
        if (pickedID == 0x00ffffff){ // Full white, must be the background !
            message = "background";
        }else{
            std::stringstream ss;
            ss << "mesh " << pickedID;
            std::string rr = ss.str();
            message = QString::fromLocal8Bit(QByteArray::fromRawData(rr.c_str(), rr.size()));
        }
        qDebug() << "message:" << message << mouse_pos.x()<<" "<< mouse_pos.y();
    }

    pickingProgram.release();
    m_if_picked =false;
}

/*****************************************************/
void PickEntity::rePicked(QPoint m_pos_t){
    mouse_pos.setX(m_pos_t.x());
    mouse_pos.setY(m_pos_t.y());
    m_if_picked = true;
}


}
原文地址:https://www.cnblogs.com/lovebay/p/15608881.html