简体   繁体   中英

Modern opengl conversion from 2d point to 3d using SFML

I want to create a game in which i have a cube that is has n*n squares on each face.I use c++, modern opengl, sfml and glm. There are pairs of squares on the cube that have the same color. The goal of this game is to create a path from square1 to square2 for each squares that have the same color without overlaping the paths. You also can have "walls" on this cube, squares that cannot form a path. The user should be able to rotate the cube however he wants to and when he presses click on one of the squares it should change its color. In order to do that i know i have to use the depth buffer to do a conversion between a 2d point on the screen and a 3d coordinate in the world. But it doesnt work and i dont know why.Pls help. This is my code(i just started this project) : main.cpp:

#include "Includes.h"
#include "Shader.h"

#define WIDTH 800
#define HEIGHT 600


using namespace std;


sf::Event event;


GLfloat get_gl_depth(int x, int y);
glm::vec4 get3dPoint(glm::vec2 point2D, int width,int height, glm::mat4 viewMatrix, glm::mat4 projectionMatrix);

int main()
{
    sf::ContextSettings settings;
    settings.depthBits = 24;
    settings.stencilBits = 8;
    settings.antialiasingLevel = 4;
    settings.majorVersion = 3;
    settings.minorVersion = 0;

    sf::Window window(sf::VideoMode(WIDTH, HEIGHT), "OpenGL", sf::Style::Default, settings);

    GLfloat vertices[] = {
        -2.0f, -2.0f, -2.0f,  0.0f, 0.0f,
         2.0f, -2.0f, -2.0f,  1.0f, 0.0f,
         2.0f,  2.0f, -2.0f,  1.0f, 1.0f,
         2.0f,  2.0f, -2.0f,  1.0f, 1.0f,
        -2.0f,  2.0f, -2.0f,  0.0f, 1.0f,
        -2.0f, -2.0f, -2.0f,  0.0f, 0.0f,

        -2.0f, -2.0f,  2.0f,  0.0f, 0.0f,
         2.0f, -2.0f,  2.0f,  1.0f, 0.0f,
         2.0f,  2.0f,  2.0f,  1.0f, 1.0f,
         2.0f,  2.0f,  2.0f,  1.0f, 1.0f,
        -2.0f,  2.0f,  2.0f,  0.0f, 1.0f,
        -2.0f, -2.0f,  2.0f,  0.0f, 0.0f,

        -2.0f,  2.0f,  2.0f,  1.0f, 0.0f,
        -2.0f,  2.0f, -2.0f,  1.0f, 1.0f,
        -2.0f, -2.0f, -2.0f,  0.0f, 1.0f,
        -2.0f, -2.0f, -2.0f,  0.0f, 1.0f,
        -2.0f, -2.0f,  2.0f,  0.0f, 0.0f,
        -2.0f,  2.0f,  2.0f,  1.0f, 0.0f,

         2.0f,  2.0f,  2.0f,  1.0f, 0.0f,
         2.0f,  2.0f, -2.0f,  1.0f, 1.0f,
         2.0f, -2.0f, -2.0f,  0.0f, 1.0f,
         2.0f, -2.0f, -2.0f,  0.0f, 1.0f,
         2.0f, -2.0f,  2.0f,  0.0f, 0.0f,
         2.0f,  2.0f,  2.0f,  1.0f, 0.0f,

        -2.0f, -2.0f, -2.0f,  0.0f, 1.0f,
         2.0f, -2.0f, -2.0f,  1.0f, 1.0f,
         2.0f, -2.0f,  2.0f,  1.0f, 0.0f,
         2.0f, -2.0f,  2.0f,  1.0f, 0.0f,
        -2.0f, -2.0f,  2.0f,  0.0f, 0.0f,
        -2.0f, -2.0f, -2.0f,  0.0f, 1.0f,

        -2.0f,  2.0f, -2.0f,  0.0f, 1.0f,
         2.0f,  2.0f, -2.0f,  1.0f, 1.0f,
         2.0f,  2.0f,  2.0f,  1.0f, 0.0f,
         2.0f,  2.0f,  2.0f,  1.0f, 0.0f,
        -2.0f,  2.0f,  2.0f,  0.0f, 0.0f,
        -2.0f,  2.0f, -2.0f,  0.0f, 1.0f
    };

    glewInit();
    glViewport(0, 0, WIDTH, HEIGHT);
    glEnable(GL_DEPTH_TEST);
    Shader ourShader("shaders/default.vs", "shaders/default.frag");


    GLuint VBO, VAO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);

    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    // Position attribute
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);
    // TexCoord attribute
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(2);

    glBindVertexArray(0); // Unbind VAO


    bool running = true;

    glm::vec3 cubePosition;
    cubePosition.z=-3;
    window.setFramerateLimit(30);

    glm::mat4 model;
    glm::mat4 view;
    glm::mat4 projection;

    while (running)
    {
        model=glm::mat4();
        view=glm::mat4();
        projection=glm::mat4();
        view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));
        projection = glm::perspective(45.0f, (GLfloat)WIDTH / (GLfloat)HEIGHT, 0.1f, 100.0f);

        while (window.pollEvent(event))
        {
            if(sf::Keyboard::isKeyPressed(sf::Keyboard::W))
                cubePosition.y-=0.2;
            if(sf::Keyboard::isKeyPressed(sf::Keyboard::S))
                cubePosition.y+=0.2;
            if(sf::Keyboard::isKeyPressed(sf::Keyboard::A))
                cubePosition.x+=0.2;
            if(sf::Keyboard::isKeyPressed(sf::Keyboard::D))
                cubePosition.x-=0.2;

            if(sf::Mouse::isButtonPressed(sf::Mouse::Left))
            {
                int x=sf::Mouse::getPosition(window).x;
                int y=sf::Mouse::getPosition(window).y;
                glm::vec4 result=get3dPoint(glm::vec2(x,y),WIDTH,HEIGHT,view,projection);
                cout<<result.x<<' '<<result.y<<' '<<result.z<<'\n';
            }

            if (event.type == sf::Event::Closed)
            {
                // end the program
                running = false;
            }
            else if (event.type == sf::Event::Resized)
            {
                // adjust the viewport when the window is resized
                glViewport(0, 0, event.size.width, event.size.height);
            }
        }

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        ourShader.Use();

        GLint modelLoc = glGetUniformLocation(ourShader.Program, "model");
        GLint viewLoc = glGetUniformLocation(ourShader.Program, "view");
        GLint projLoc = glGetUniformLocation(ourShader.Program, "projection");

        glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
        glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));
        glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));

        glBindVertexArray(VAO);
        glDrawArrays(GL_TRIANGLES, 0, 36);

        window.display();
    }
    return 0;
}

glm::vec4 get3dPoint(glm::vec2 point2D, int width,int height, glm::mat4 viewMatrix, glm::mat4 projectionMatrix)
{
    double x = 2.0 * point2D.x / WIDTH - 1;
    double y = - 2.0 * point2D.y / HEIGHT + 1;
    glm::mat4 viewProjectionInverse = glm::inverse(projectionMatrix * viewMatrix);

    glm::vec4 point3D =glm::vec4(x, y, get_gl_depth(x,y),1.0);
    //cout<<point2D.x<<' '<<point2D.y<<' '<<get_gl_depth(point2D.x,point2D.y)<<'\n';

    return viewProjectionInverse*point3D;
}

GLfloat get_gl_depth(int x, int y)
{
  GLfloat depth_z = 0.0f;

  glReadBuffer(GL_FRONT);
  glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth_z);
  return depth_z;
}

And the shaders are quite standard: vertex:

#version 330 core
layout (location = 0) in vec3 position;
layout (location = 2) in vec2 texCoord;

out vec2 TexCoord;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
    gl_Position = projection * view * model * vec4(position, 1.0f);
    TexCoord = vec2(texCoord.x, 1.0 - texCoord.y);
}

fragment:

#version 330 core
in vec2 TexCoord;

out vec4 color;

void main()
{
    color = vec4(1.0,0.0,0.0,1.0);
}

I just want my conversion to work, ill work in the future to texture the cube nicely, to organise my code etc.

I can spot a couple of issues in your code:

 glm::vec4 get3dPoint(glm::vec2 point2D, int width,int height, glm::mat4 viewMatrix, glm::mat4 projectionMatrix) { double x = 2.0 * point2D.x / WIDTH - 1; double y = - 2.0 * point2D.y / HEIGHT + 1; 

Here, you are converting to the NDC range. However, you are using WIDHT and HEIGHT , and not the width and height arguments for the functions. This will not matter, since you call it excalt with these values, but it is weird to begin with.

  glm::mat4 viewProjectionInverse = glm::inverse(projectionMatrix * viewMatrix); glm::vec4 point3D =glm::vec4(x, y, get_gl_depth(x,y),1.0); 

You are now using the NDC x and y in the range [-1,1] as input to get_gl_depth , which does expect to get the window space (pixel) coordinates, and actually also uses int for those parameters. So what you end up is either an invalid call to glReadPixels ( x or y negative), or you get depth of a pixel in the lower left 2x2 pixel area.

  return viewProjectionInverse*point3D; } 

You forgot to devide the result by the w coordinate of the resulting vector.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM