2015-05-20 226 views
0

我想从鼠标位置获取对象空间坐标。我有一些标准的渲染代码,效果很好。如何从屏幕坐标获取对象坐标?

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

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

Unproject代码:

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

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

+0

你是什么意思的对象坐标?你想挑选一个点吗? –

+0

https://www.opengl.org/wiki/Vertex_Transformation是一个很好的步行通过gl管道。只是做倒退!你的代码中的规范化肯定是错误的。确保首先正确设置窗口 - >标准化设备。此外,请确保使用投影矩阵为w = 1的透视这一事实,因为只有这样才能将其反转。 – starmole

+0

@GoodLuck我想在对象上选取一个相对于对象坐标的点。 –

回答

1

我看到你正在使用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

那么,我将如何获取光线与物体碰撞的对象(模型)坐标。 –

+0

带上您的模型顶点并创建一个AABB或创建一个球体。之后,进行AABB射线碰撞或球面射线碰撞。为了调试,确保渲染射线(1行:第一个点:结果,第二个:结果+射线*号)。 – CrSe

1

我觉得CRSE的答案是正确的了。我这样做,我可以选择在模型中的任意一点:

我拍这两个点线(P1和P2):

Glu.gluUnProject(tempx, viewport[3] - tempy, 0, modelMatrix, projMatrix, viewport, out x1, out y1, out z1); 
      p = new Point(x1, y1, z1); 
      Glu.gluUnProject(tempx, viewport[3] - tempy, 1, modelMatrix, projMatrix, viewport, out x1, out y1, out z1); 
      p1 = new Point(x1, y1, z1); 

如果距离BTW这个射线和一个顶点小于一个门槛,我选择了这一点。我希望它是有用的。