使用 SFML 从 2d 点到 3d 的现代 opengl 转换
Modern opengl conversion from 2d point to 3d using SFML
我想创建一个游戏,其中我有一个立方体,每个立方体上有 n*n 个正方形 face.I 使用 c++、现代 opengl、sfml 和 glm。立方体上有一对颜色相同的正方形。这个游戏的目标是为每个颜色相同且路径不重叠的方块创建一条从 square1 到 square2 的路径。你也可以在这个立方体上有 "walls",不能形成路径的正方形。用户应该能够随心所欲地旋转立方体,当他按下其中一个方块时,它应该会改变颜色。为了做到这一点,我知道我必须使用深度缓冲区在屏幕上的 2d 点和世界中的 3d 坐标之间进行转换。但它不起作用,我不知道 why.Pls 帮助。
这是我的代码(我刚刚开始这个项目):
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);
}
我只是想让我的转换工作,我将来会很好地构造立方体,组织我的代码等。
我可以在您的代码中发现几个问题:
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 范围。但是,您使用的是 WIDHT
和 HEIGHT
,而不是函数的 width
和 height
参数。这无关紧要,因为您用这些值称它为 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 x
和 y
作为 get_gl_depth
的输入,这确实希望获得 window space(像素)坐标,实际上这些参数也使用 int
。所以你最终得到的是对 glReadPixels
的无效调用(x
或 y
否定),或者你得到左下角 2x2 像素区域中的像素深度。
return viewProjectionInverse*point3D; }
您忘记将结果除以结果向量的 w
坐标。
我想创建一个游戏,其中我有一个立方体,每个立方体上有 n*n 个正方形 face.I 使用 c++、现代 opengl、sfml 和 glm。立方体上有一对颜色相同的正方形。这个游戏的目标是为每个颜色相同且路径不重叠的方块创建一条从 square1 到 square2 的路径。你也可以在这个立方体上有 "walls",不能形成路径的正方形。用户应该能够随心所欲地旋转立方体,当他按下其中一个方块时,它应该会改变颜色。为了做到这一点,我知道我必须使用深度缓冲区在屏幕上的 2d 点和世界中的 3d 坐标之间进行转换。但它不起作用,我不知道 why.Pls 帮助。 这是我的代码(我刚刚开始这个项目): 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);
}
我只是想让我的转换工作,我将来会很好地构造立方体,组织我的代码等。
我可以在您的代码中发现几个问题:
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 范围。但是,您使用的是 WIDHT
和 HEIGHT
,而不是函数的 width
和 height
参数。这无关紧要,因为您用这些值称它为 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 x
和 y
作为 get_gl_depth
的输入,这确实希望获得 window space(像素)坐标,实际上这些参数也使用 int
。所以你最终得到的是对 glReadPixels
的无效调用(x
或 y
否定),或者你得到左下角 2x2 像素区域中的像素深度。
return viewProjectionInverse*point3D; }
您忘记将结果除以结果向量的 w
坐标。