如何从屏幕坐标获取对象坐标?

时间:2015-05-20 04:55:56

标签: opengl

我正试图从鼠标位置获取对象空间坐标。我有一些标准的渲染代码,效果很好。

问题在于鼠标选择代码。我尝试过很多东西并经历了类似的问题,但我似乎无法理解为什么它不起作用。

我希望结果根据鼠标在对象上的位置返回[-1,1]中的x,y坐标。我确实得到了[-1,1]内的分数,但是它们非常偏斜,例如(2.63813e-012,-1,300)。

取消投影代码:

int z;
glReadPixels(mouse_pos_[0], int( navWidget->height() - mouse_pos_[1]), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &z);
glm::vec3 win(mouse_pos_[0], navWidget->height() - mouse_pos_[1], z);
glm::vec4 viewport(0, 0, navWidget->width(), navWidget->height());
auto result_vec3 = glm::unProject(win, view * model1, proj, viewport);

auto result = glm::normalize(glm::vec2(result_vec3.x, result_vec3.y)); // < -- I normalize here since that gave good results without the translate


bool left_image = true;

    if (!(result.x <= length_per_side && result.x >= -length_per_side &&
        result.y <= length_per_side && result.y >= -length_per_side)) {
// do stuff
        }
    }

渲染代码:

float fov = 2*(atan((camProjModule->camResY()/2*camProjModule->camPixSizeY()) /
    camProjModule->camFocalLength()) / M_PI * 180.0);
float znear = 1.0f;
float zfar = 6000.0f;
//float aspect = 1024.f / 683.f;
float aspect = navWidget->width() / navWidget->height();

glm::mat4 proj = glm::perspective(fov, aspect, znear, zfar);
float required_height =(float)( znear * tan((fov / 2.f) * M_PI / 180.f)); 
float eye_distance = znear / required_height * ((float)(navWidget->height()) / 2.f);
eye_distance = 300.f;
glm::mat4 view = glm::lookAt(glm::vec3(0.f, 0.f, 1.f * eye_distance), glm::vec3(0.f, 0.f, 0.f), glm::vec3(0.f, 1.f, 0.f));


glUseProgram(correspond_shader_);
glBindVertexArray(quad_vao_);
glUniform3f(colorLoc, 1.0f, 1.0f, 1.0f);

// draw left
if (left_correspond_texture_) {
    glEnable(GL_TEXTURE_2D);
    glActiveTexture(GL_TEXTURE0 + 0);
    glBindTexture(GL_TEXTURE_2D, left_correspond_texture_);
    glUniform1i(drawTexLoc, left_correspond_texture_);
}

GLint proj_loc = glGetUniformLocation(correspond_shader_, "proj");
GLint view_loc = glGetUniformLocation(correspond_shader_, "view");
GLint draw_tex_loc = glGetUniformLocation(correspond_shader_, "drawTex");

glUniformMatrix4fv(proj_loc, 1, GL_FALSE, glm::value_ptr(proj));
glUniformMatrix4fv(view_loc, 1, GL_FALSE, glm::value_ptr(view));


float ratio = 1024.f / 683.f;
float height = navWidget->height() / 2.f;
float ratio_to_multiply = height / 2.f;

glm::vec3 translation_vector = glm::vec3(0.f, height / 2.f, 0.f); // < --- If I remove this translation I get results that seem to be correct, and can be used after normalizing the x and y

glm::mat4 left_model = glm::scale(glm::translate(glm::mat4(1.f), translation_vector), glm::vec3(ratio * ratio_to_multiply, ratio_to_multiply, 1.f));
glm::mat4 right_model = glm::scale(glm::translate(glm::mat4(1.f), -1.f * translation_vector), glm::vec3(ratio * ratio_to_multiply, ratio_to_multiply, 1.f));

glUniformMatrix4fv(glGetUniformLocation(correspond_shader_, "model"), 1, GL_FALSE, glm::value_ptr(left_model));

glDrawArrays(GL_TRIANGLES, 0, 6); //, GL_UNSIGNED_INT, NULL);

编辑:我认为我的问题需要改进。我正在绘制两个四边形并渲染单独的纹理。我想要做的是将鼠标坐标作为标准化纹理坐标,取决于它是哪个四边形。

2 个答案:

答案 0 :(得分:2)

我看到你正在使用glm库。您可以使用非投影方法获取鼠标坐标/光线方向。

glm::vec2 screenPos(mousePos.x, mousePos.y);
screenPos.y = height - screenPos.y;

float aspect = width / height;
glm::vec4 viewport = glm::vec4(0.0f, 0.0f, width , height);
glm::mat4 proj     = glm::perspective(75.0f, aspect, 0.1f, 10000.0f);

glm::vec3 a (screenPos.x, screenPos.y, 0);
glm::vec3 b (screenPos.x, screenPos.y, 1);

glm::vec3 result  = glm::unProject(a, viewMatrix, proj, viewport);
glm::vec3 result2 = glm::unProject(b, viewMatrix, proj, viewport);

glm::vec3 pickingPos = result;
glm::vec3 pickingDir = result2 - result;

之后,您可以使用方向和位置来检查碰撞

答案 1 :(得分:1)

我认为CrSe的答案也是对的。我已经完成了这个,我可以在模型上选择任何一点:

我从这两点(p1和p2)拍摄了一条光线:

$('.tableItem > a').on('click', function(){
    var $link = $(this);
    console.log("This is my id: "+ $link.attr('id') );
    //do stuff with the link
});

如果此光线和顶点的距离小于阈值,我选择该点。我希望它有用。