opengl 从 window 指向 3d 坐标
opengl from window point to 3d coordinate
对于我的一个大项目,我需要在某个时候在屏幕上绘制一个立方体,我需要知道我是否点击了立方体的一个面。为此,我知道我必须使用深度缓冲区。但是我尝试进行的转换不起作用。这是我的代码:
#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 modelMatrix);
int main()
{
sf::ContextSettings settings;
settings.depthBits = 32;
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.0, -2.0, -2.0, 0.0f, 0.0f,
2.0, -2.0, -2.0, 1.0f, 0.0f,
2.0, 2.0, -2.0, 1.0f, 1.0f,
2.0, 2.0, -2.0, 1.0f, 1.0f,
-2.0, 2.0, -2.0, 0.0f, 1.0f,
-2.0, -2.0, -2.0, 0.0f, 0.0f,
-2.0, -2.0, 2.0, 0.0f, 0.0f,
2.0, -2.0, 2.0, 1.0f, 0.0f,
2.0, 2.0, 2.0, 1.0f, 1.0f,
2.0, 2.0, 2.0, 1.0f, 1.0f,
-2.0, 2.0, 2.0, 0.0f, 1.0f,
-2.0, -2.0, 2.0, 0.0f, 0.0f,
-2.0, 2.0, 2.0, 1.0f, 0.0f,
-2.0, 2.0, -2.0, 1.0f, 1.0f,
-2.0, -2.0, -2.0, 0.0f, 1.0f,
-2.0, -2.0, -2.0, 0.0f, 1.0f,
-2.0, -2.0, 2.0, 0.0f, 0.0f,
-2.0, 2.0, 2.0, 1.0f, 0.0f,
2.0, 2.0, 2.0, 1.0f, 0.0f,
2.0, 2.0, -2.0, 1.0f, 1.0f,
2.0, -2.0, -2.0, 0.0f, 1.0f,
2.0, -2.0, -2.0, 0.0f, 1.0f,
2.0, -2.0, 2.0, 0.0f, 0.0f,
2.0, 2.0, 2.0, 1.0f, 0.0f,
-2.0, -2.0, -2.0, 0.0f, 1.0f,
2.0, -2.0, -2.0, 1.0f, 1.0f,
2.0, -2.0, 2.0, 1.0f, 0.0f,
2.0, -2.0, 2.0, 1.0f, 0.0f,
-2.0, -2.0, 2.0, 0.0f, 0.0f,
-2.0, -2.0, -2.0, 0.0f, 1.0f,
-2.0, 2.0, -2.0, 0.0f, 1.0f,
2.0, 2.0, -2.0, 1.0f, 1.0f,
2.0, 2.0, 2.0, 1.0f, 0.0f,
2.0, 2.0, 2.0, 1.0f, 0.0f,
-2.0, 2.0, 2.0, 0.0f, 0.0f,
-2.0, 2.0, -2.0, 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();
model=glm::translate(model,cubePosition);
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);
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(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 36);
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))
{
float x=sf::Mouse::getPosition(window).x;
float y=sf::Mouse::getPosition(window).y;
float z=1.0;
glReadPixels(x,HEIGHT-y-1,1,1,GL_DEPTH_COMPONENT,GL_FLOAT,&z);
x=2.0*(x/WIDTH)-1;
y=-2.0*(y/HEIGHT)+1;
glm::vec4 v=glm::vec4(x,y,z,1.0);
v=v*glm::inverse(projection*view*model);
v.x/=v.w;
v.y/=v.w;
v.z/=v.w;
cout<<v.x<<' '<<v.y<<' '<<v.z<<' '<<v.w<<'\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);
}
}
window.display();
}
return 0;
}
所以最初立方体绘制在屏幕中央,当我尝试单击左上角(第一个红色像素)时,我应该得到数字 x=-2 ,y=2 但我得到x=0.0150043,y=0.0150043 这还差得远呢。我的错误在哪里?我按照本教程在线阅读了有关此主题的信息:
http://webglfactory.blogspot.ro/2011/05/how-to-convert-world-to-screen.html
投影意味着将世界坐标转换为标准化规范坐标。 NCC 是一个 2x2x2 的立方体 space。从这个 NCC space 到 window 屏幕坐标的转换由 GPU "automagically" 使用您在 glViewport 中传递的参数完成。
所以首先你必须撤消屏幕-NCC 转换。使用 https://www.opengl.org/sdk/docs/man2/xhtml/glViewport.xml 公式。
因为window 坐标是二维的,你无法取回深度坐标。从您的眼睛到 2D window 点及更远的地方有一个无限直线。
对于我的一个大项目,我需要在某个时候在屏幕上绘制一个立方体,我需要知道我是否点击了立方体的一个面。为此,我知道我必须使用深度缓冲区。但是我尝试进行的转换不起作用。这是我的代码:
#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 modelMatrix);
int main()
{
sf::ContextSettings settings;
settings.depthBits = 32;
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.0, -2.0, -2.0, 0.0f, 0.0f,
2.0, -2.0, -2.0, 1.0f, 0.0f,
2.0, 2.0, -2.0, 1.0f, 1.0f,
2.0, 2.0, -2.0, 1.0f, 1.0f,
-2.0, 2.0, -2.0, 0.0f, 1.0f,
-2.0, -2.0, -2.0, 0.0f, 0.0f,
-2.0, -2.0, 2.0, 0.0f, 0.0f,
2.0, -2.0, 2.0, 1.0f, 0.0f,
2.0, 2.0, 2.0, 1.0f, 1.0f,
2.0, 2.0, 2.0, 1.0f, 1.0f,
-2.0, 2.0, 2.0, 0.0f, 1.0f,
-2.0, -2.0, 2.0, 0.0f, 0.0f,
-2.0, 2.0, 2.0, 1.0f, 0.0f,
-2.0, 2.0, -2.0, 1.0f, 1.0f,
-2.0, -2.0, -2.0, 0.0f, 1.0f,
-2.0, -2.0, -2.0, 0.0f, 1.0f,
-2.0, -2.0, 2.0, 0.0f, 0.0f,
-2.0, 2.0, 2.0, 1.0f, 0.0f,
2.0, 2.0, 2.0, 1.0f, 0.0f,
2.0, 2.0, -2.0, 1.0f, 1.0f,
2.0, -2.0, -2.0, 0.0f, 1.0f,
2.0, -2.0, -2.0, 0.0f, 1.0f,
2.0, -2.0, 2.0, 0.0f, 0.0f,
2.0, 2.0, 2.0, 1.0f, 0.0f,
-2.0, -2.0, -2.0, 0.0f, 1.0f,
2.0, -2.0, -2.0, 1.0f, 1.0f,
2.0, -2.0, 2.0, 1.0f, 0.0f,
2.0, -2.0, 2.0, 1.0f, 0.0f,
-2.0, -2.0, 2.0, 0.0f, 0.0f,
-2.0, -2.0, -2.0, 0.0f, 1.0f,
-2.0, 2.0, -2.0, 0.0f, 1.0f,
2.0, 2.0, -2.0, 1.0f, 1.0f,
2.0, 2.0, 2.0, 1.0f, 0.0f,
2.0, 2.0, 2.0, 1.0f, 0.0f,
-2.0, 2.0, 2.0, 0.0f, 0.0f,
-2.0, 2.0, -2.0, 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();
model=glm::translate(model,cubePosition);
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);
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(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 36);
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))
{
float x=sf::Mouse::getPosition(window).x;
float y=sf::Mouse::getPosition(window).y;
float z=1.0;
glReadPixels(x,HEIGHT-y-1,1,1,GL_DEPTH_COMPONENT,GL_FLOAT,&z);
x=2.0*(x/WIDTH)-1;
y=-2.0*(y/HEIGHT)+1;
glm::vec4 v=glm::vec4(x,y,z,1.0);
v=v*glm::inverse(projection*view*model);
v.x/=v.w;
v.y/=v.w;
v.z/=v.w;
cout<<v.x<<' '<<v.y<<' '<<v.z<<' '<<v.w<<'\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);
}
}
window.display();
}
return 0;
}
所以最初立方体绘制在屏幕中央,当我尝试单击左上角(第一个红色像素)时,我应该得到数字 x=-2 ,y=2 但我得到x=0.0150043,y=0.0150043 这还差得远呢。我的错误在哪里?我按照本教程在线阅读了有关此主题的信息: http://webglfactory.blogspot.ro/2011/05/how-to-convert-world-to-screen.html
投影意味着将世界坐标转换为标准化规范坐标。 NCC 是一个 2x2x2 的立方体 space。从这个 NCC space 到 window 屏幕坐标的转换由 GPU "automagically" 使用您在 glViewport 中传递的参数完成。
所以首先你必须撤消屏幕-NCC 转换。使用 https://www.opengl.org/sdk/docs/man2/xhtml/glViewport.xml 公式。
因为window 坐标是二维的,你无法取回深度坐标。从您的眼睛到 2D window 点及更远的地方有一个无限直线。