我在 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
因此,因为我的 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
现在代码似乎在起始位置工作正常。但是在您使用鼠标并旋转屏幕一点点之后,就再也没有像预期的那样工作了。