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; } }