【问题标题】:Modern opengl conversion from 2d point to 3d using SFML使用 SFML 从 2d 点到 3d 的现代 opengl 转换
【发布时间】:2017-04-26 10:57:12
【问题描述】:

我想创建一个游戏,其中我有一个立方体,每个面上都有 n*n 个正方形。我使用 c++、现代 opengl、sfml 和 glm。立方体上有一对颜色相同的正方形。该游戏的目标是为每个具有相同颜色且不重叠路径的正方形创建从 square1 到 square2 的路径。你也可以在这个立方体上有“墙”,不能形成路径的正方形。用户应该能够随心所欲地旋转立方体,并且当他按下其中一个方块时,它应该改变它的颜色。为了做到这一点,我知道我必须使用深度缓冲区在屏幕上的 2d 点和世界上的 3d 坐标之间进行转换。但它不起作用,我不知道为什么。请帮忙。 这是我的代码(我刚开始这个项目): 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;
}

着色器非常标准: 顶点:

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

片段:

#version 330 core
in vec2 TexCoord;

out vec4 color;

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

我只希望我的转换能够正常工作,将来会很好地为立方体纹理化、组织我的代码等。

【问题讨论】:

    标签: c++ opengl 3d sfml


    【解决方案1】:

    我可以在您的代码中发现几个问题:

    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;
    

    在这里,您正在转换为 NDC 范围。但是,您使用的是WIDHTHEIGHT,而不是函数的widthheight 参数。这无关紧要,因为您将这些值称为 excalt,但一开始就很奇怪。

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

    您现在使用 [-1,1] 范围内的 NDC xy 作为 get_gl_depth 的输入,它确实希望获得窗口空间(像素)坐标,实际上还使用 int那些参数。所以你最终得到的要么是对 glReadPixels 的无效调用(xy 负数),要么你在左下角 2x2 像素区域中得到一个像素的深度。

        return viewProjectionInverse*point3D; }
    

    您忘记将结果除以结果向量的w 坐标。

    【讨论】:

    • 我不太明白你说的最后一句话。我必须将结果的所有 3 个组成部分除以 w 吗?
    • 是的。这种变换适用于齐次坐标,它将您感兴趣的 3d 空间嵌入到 4 维空间中。但是你对 4 维结果感兴趣,但对它的 3d 表示感兴趣,所以你必须转换回来。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多