Я получаю неправильные значения при вызове glReadPixels - PullRequest
0 голосов
/ 20 июня 2020

В моей программе я пытаюсь выбрать объект при щелчке правой кнопкой мыши с помощью метода glReadPixels. Окно для рендеринга создается с помощью wxWidgets (путем расширения wxFrame и wxGLCanvas). Однако я получаю неправильные значения. Это учебник, который я использовал

Мне предложили использовать этот подход, поскольку он кажется быстрее и проще, чем литье лучей.

Мой код:

#include "MyGLCanvas.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

BEGIN_EVENT_TABLE(MyGLCanvas, wxGLCanvas)
EVT_PAINT(MyGLCanvas::paintEvent)
EVT_CHAR(MyGLCanvas::onKeyPressed)
EVT_LEFT_DOWN(MyGLCanvas::onLeftMouseDown)
EVT_LEFT_UP(MyGLCanvas::onLeftMouseUp)
EVT_RIGHT_DOWN(MyGLCanvas::onRightMouseDown)
EVT_RIGHT_UP(MyGLCanvas::onRightMouseUp)
EVT_KEY_UP(MyGLCanvas::onKeyUp)
EVT_MOUSEWHEEL(MyGLCanvas::onMouseWheel)
END_EVENT_TABLE()


MyGLCanvas::MyGLCanvas(wxFrame* parent, GLuint width, GLuint height) : wxGLCanvas(parent, wxID_ANY, 0, wxDefaultPosition, wxSize(width, height), 0, wxT("GLCanvas"), wxNullPalette)  // parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, wxT("GLCanvas")
{
    windowHeight = height;
    windowWidth = width;
    this->WarpPointer(windowWidth / 2, windowHeight / 2); // places mouse in the middle of screen
    fpsCamera = new FPSCamera(glm::vec3(0.0f, 0.0f, 5.0f));
    renderTimer = new RenderTimer(this);
    renderTimer->Start();
    glContext = new wxGLContext(this, NULL);
    SetCurrent(*glContext);
    init();
}


MyGLCanvas::~MyGLCanvas()
{
    glDeleteProgram(shaderProgram);
    delete mesh;
    delete renderTimer;
    delete glContext;
    delete fpsCamera;
}

int MyGLCanvas::init()
{
    glewExperimental = GL_TRUE;
    if (glewInit() != GLEW_OK)
    {
        std::cerr << "Glew initialization failed " << std::endl;
        return -1;
    }

    glEnable(GL_DEPTH_TEST);
    glViewport(0, 0, windowWidth, windowHeight);

    mesh = new Mesh();
    mesh->loadOBJ();

    return 0;
}

void MyGLCanvas::paintEvent(wxPaintEvent& evt)
{
    wxPaintDC dc(this);
    draw(dc);
}

void MyGLCanvas::paintNow()
{
    wxClientDC dc(this);
    draw(dc);
}

void MyGLCanvas::onLeftMouseDown(wxMouseEvent& event)
{
    xLastPosition = wxGetMousePosition().x;
    yLastPosition = wxGetMousePosition().y;
    Bind(wxEVT_MOTION, &MyGLCanvas::onMouseMove, this, wxID_ANY);
}

void MyGLCanvas::onLeftMouseUp(wxMouseEvent& event)
{
    Unbind(wxEVT_MOTION, &MyGLCanvas::onMouseMove, this, wxID_ANY);
}

void MyGLCanvas::onRightMouseDown(wxMouseEvent& event)
{
    GLuint index;

    glReadPixels(wxGetMousePosition().x, windowHeight - wxGetMousePosition().y - 1, 1, 1, GL_STENCIL_INDEX, GL_UNSIGNED_INT, &index);
    wxMessageOutputDebug().Printf("index = %i", index); 
}

void MyGLCanvas::onRightMouseUp(wxMouseEvent& event)
{
    wxMessageOutputDebug().Printf("Right mouse up!!");
}

void MyGLCanvas::onMouseMove(wxMouseEvent& event)
{
    if (event.Entering())
    {
        SetFocus();
    }

    GLdouble dxMouse, dyMouse;

    dxMouse = xLastPosition - wxGetMousePosition().x;
    dyMouse = yLastPosition - wxGetMousePosition().y;

    xLastPosition = wxGetMousePosition().x;
    yLastPosition = wxGetMousePosition().y;

    fpsCamera->rotate((GLfloat)dxMouse * MOUSE_SENSITIVITY, (GLfloat)dyMouse * MOUSE_SENSITIVITY);

    event.Skip();
}

void MyGLCanvas::onKeyPressed(wxKeyEvent& event)
{

    switch (event.GetKeyCode())
    {
    case (119):                     // lower case w
        {
            fpsCamera->move(mouseSpeed * fpsCamera->getLook());
            mouseSpeed += 0.1f;
            break;
        }
    case (97):                      // lower case a
        {
            fpsCamera->move(mouseSpeed * -fpsCamera->getRight());
            mouseSpeed += 0.1f;
            break;
        }
    case (115):                     // lower case s
        {
            fpsCamera->move(mouseSpeed * -fpsCamera->getLook());
            mouseSpeed += 0.1f;
            break;
        }
    case (100):                     // lower case d
        {
            fpsCamera->move(mouseSpeed * fpsCamera->getRight());
            mouseSpeed += 0.1f;
            break;
        }
    case (120):                     // lower case x
        {
            fpsCamera->move(mouseSpeed * -fpsCamera->getUp());
            mouseSpeed += 0.1f;
            break;
        }
    case (121):                     // lower case y
        {
            fpsCamera->move(mouseSpeed * fpsCamera->getUp());
            mouseSpeed += 0.1f;
            break;
        }
    default:
        break;
    }
}

void MyGLCanvas::onKeyUp(wxKeyEvent& event)
{
    mouseSpeed = 0.1;
}

void MyGLCanvas::onMouseWheel(wxMouseEvent& event)
{
    GLdouble fov;

    if (event.GetWheelRotation() > 0)
    {
        fov = fpsCamera->getFOV() + ZOOM_SENSITIVITY;
    }
    else
    {
        fov = fpsCamera->getFOV() - ZOOM_SENSITIVITY;
    }

    fov = glm::clamp(fov, 1.0, 120.0);

    fpsCamera->setFOV((GLfloat)fov);
}

void MyGLCanvas::draw(wxDC& dc)
{
    glm::vec3 modelPos = glm::vec3(0.0f, -10.0f, -50.0f);
    glm::mat4 model, view;

    model = glm::translate(model, modelPos);
    view = fpsCamera->getViewMatrix();
    projection = glm::perspective(glm::radians(fpsCamera->getFOV()), (float)(windowWidth / windowHeight), 0.1f, 100.0f);

    glm::mat4 trans;
    // trans = glm::rotate(trans, degree, glm::vec3(0.0f, 1.0f, 0.0f));
    trans = glm::rotate(trans, 30.0f, glm::vec3(0.0f, 1.0f, 0.0f));
    trans = glm::scale(trans, glm::vec3(0.01, 0.01, 0.01));
    
    ShaderProgram shaderProgram;
    shaderProgram.loadShaders("basic.vert", "basic.frag");

    glClearStencil(0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

    shaderProgram.use();
    shaderProgram.setUniform("transform", trans);
    shaderProgram.setUniform("model", model);
    shaderProgram.setUniform("view", view);
    shaderProgram.setUniform("projection", projection);
    shaderProgram.setUniform("color", glm::vec3(0.310f, 0.747f, 0.185f));

    glEnable(GL_STENCIL_TEST);
    glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);

    glStencilFunc(GL_ALWAYS, 1, -1);
    mesh->draw();
    glDisable(GL_STENCIL_TEST);

    //degree += 0.05f;
    SwapBuffers();
}

RenderTimer::RenderTimer(MyGLCanvas* canvas) : wxTimer()
{
    RenderTimer::m_canvas = canvas;
}

void RenderTimer::Notify()
{
    m_canvas->Refresh(false);
};

void RenderTimer::Start()
{
    wxTimer::Start();
};
...