OpenGL выбрать сферу с помощью мыши - PullRequest
1 голос
/ 05 января 2012

У меня есть несколько сфер в трехмерном пространстве, которые пользователь должен выбрать, щелкнув мышью. Теперь я видел несколько примеров использования 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 Ответ

3 голосов
/ 05 января 2012

Привет, есть много решений для такого рода проблем.

Лучевое литье - одно из лучших, но в нем много знаний о геометрии, и это совсем не просто.

Кроме того, gluUnProject недоступен в других реализациях OpenGL, таких как ES для мобильных устройств (хотя вы можете записать его в функции манипулирования матрицами).

Лично я предпочитаю решение для выбора цвета, которое является достаточно гибким и очень быстрым в плане вычислений.

Идея состоит в том, чтобы визуализировать возможность выбора (только возможность выбора для повышения производительности) с заданным уникальным цветом в внеэкранном буфере.

Затем вы берете цвет пикселя по координатам, выбранным пользователем, и выбираете соответствующий 3D-объект.

Приветствие Маурицио Бенедетти

...