2012-01-05 39 views
1

我在3D空间中有许多球体,用户应该可以用鼠标点击来选择球体。现在我已经看到了一些使用gluUnProject的例子,所以我给了它一个镜头。所以,我有(请纠正我的每一步,如果我错了,因为我不是100%肯定它的任何部分):opengl用鼠标选择球体

def compute_pos(x, y, z): 
    ''' 
    Compute the 3d opengl coordinates for 3 coordinates. 
    @param x,y: coordinates from canvas taken with mouse position 
    @param z: coordinate for z-axis 
    @return; (gl_x, gl_y, gl_z) tuple corresponding to coordinates in OpenGL context 
    ''' 
    modelview = numpy.matrix(glGetDoublev(GL_MODELVIEW_MATRIX)) 
    projection = numpy.matrix(glGetDoublev(GL_PROJECTION_MATRIX)) 
    viewport = glGetIntegerv(GL_VIEWPORT) 

    winX = float(x) 
    winY = float(viewport[3] - float(y)) 
    winZ = z 
    return gluUnProject(winX, winY, winZ, modelview, projection, viewport) 

接着,将鼠标点击的x和y与球体的中心位置:

def is_picking(x, y, point): 
    ray_start = compute_pos(x, y, -1) 
    ray_end = compute_pos(x, y, 1) 
    d = _compute_2d_distance((ray_start[0], ray_start[1]), 
          (ray_end[0], ray_end[1]), 
          (point[0], point[1])) 
    if d > CUBE_SIZE: 
     return False 

    d = _compute_2d_distance((ray_start[0], ray_start[2]), 
          (ray_end[0], ray_end[2]), 
          (point[0], point[2])) 
    if d > CUBE_SIZE: 
     return False 

    d = _compute_2d_distance((ray_start[1], ray_start[2]), 
          (ray_end[1], ray_end[2]), 
          (point[1], point[2])) 
    if d > CUBE_SIZE: 
     return False 
    return True 

,是因为我的3D几何形状都不好,我计算两个点作为射线起点和终点,将进入2D 3倍消除了一个维度一段时间,并计算我的线条和球体中心之间的距离。如果这些距离中的任何一个比我的球体射线大,那么它不会被点击。我认为距离的公式是正确的,但以防万一:

def _compute_2d_distance(p1, p2, target): 
''' 
Compute the distance between the line defined by two points and a target point. 
@param p1: first point that defines the line 
@param p2: second point that defines the line 
@param target: the point to which distance needs to be computed 
@return: distance from point to line 
''' 
    if p2[0] != p1[0]: 
     if p2[1] == p1[1]: 
      return abs(p2[0] - p1[0]) 
     a = (p2[1] - p1[1])/(p2[0] - p1[0]) 
     b = -1 
     c = p1[1] + p1[0] * (p2[1] - p1[1])/(p2[0] - p1[0]) 
     d = abs(a * target[0] + b * target[1] + c)/math.sqrt(a * a + b * b) 
     return d 
    if p2[0] == p1[0]: 
     d = abs(p2[1] - p1[1]) 
     return d 
    return None 

现在代码似乎在开始位置正常工作。但是,在使用鼠标和旋转屏幕之后,即使稍微有点了,也不会再像预期的那样工作了。

回答

3

嗨,这种问题有很多解决方案。

光线投射是最好的之一,但它涉及大量的几何知识,它根本不容易。

此外gluUnProject在其他OpenGL实现中不可用,例如用于移动设备的ES(尽管您可以将它写入矩阵操作函数中)。

我个人比较喜欢颜色选择解决方案,它非常灵活,计算速度非常快。

这个想法是使用屏幕外缓冲区上给定的唯一颜色来呈现可选择的(只有可选择的性能提升)。

然后,在用户点击的坐标处获取像素的颜色,然后选择相应的3D对象。

干杯 莫里吉奥贝尼戴提

+0

感谢您的输入,但是我真的不知道如何/如果我能将这我的解决方案。所有可选球体需要具有相同的颜色。 – Bogdan 2012-01-05 10:28:21

+0

当然,你可以轻松实现这一点。 为了达到这个目的,您在标准渲染框架中使用自己的颜色渲染球体,并在那里完成选择后,通过以平面着色方式渲染预先指定颜色的对象来渲染通道并没有灯。比描述要容易得多。 – 2012-01-05 11:06:13

+0

“Maurizio Benedetti”是正确的颜色选择器是最好的方式。您也可以使用对象的指针作为颜色值。当然,如果你制作一个64位的应用程序,你必须使用64位纹理或者在两个32位纹理之间分割指针。 – zezba9000 2012-01-05 11:56:04