opengl用鼠标选择球体

时间:2012-01-05 07:58:25

标签: opengl pyopengl

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

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

因为我的三维几何结构并不好,我计算两个点作为光线起点和终点,进入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 

现在代码似乎在起始位置正常工作。但是,在您使用鼠标并旋转屏幕后,即使是一点点,也没有任何工作可以按预期工作了。

1 个答案:

答案 0 :(得分:3)

嗨,有很多解决方案可以解决这类问题。

光线投射是最好的之一,但它涉及很多几何知识,并不容易。

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

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

我们的想法是在屏幕外缓冲区上使用给定的唯一颜色渲染可选择的(仅可选择性能提升)。

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

干杯 Maurizio Benedetti