1

ユーザーがマウスのクリックで選択できるはずの 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 ジオメトリはまったく良くないので、光線の始点と終点として 2 つの点を計算し、一度に 1 つの次元を削除して 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 

これで、コードは開始位置で正常に動作するようになりました。しかし、少しでもマウスを使って画面を回転させると、期待どおりに何も機能しなくなります。

4

1 に答える 1

3

こんにちは、この種の問題には多くの解決策があります。

レイ キャスティングは最高の手法の 1 つですが、多くのジオメトリの知識が必要であり、まったく簡単ではありません。

さらに、gluUnProject は、モバイル デバイス用の ES などの他の OpenGL 実装では使用できません (ただし、行列操作関数で記述することはできます)。

個人的には、非常に柔軟で非常に高速なコンピューティングが可能なカラー ピッキング ソリューションを好みます。

アイデアは、選択可能なもの (パフォーマンスを向上させるために選択可能なもののみ) を、オフスクリーン バッファーに特定の一意の色でレンダリングすることです。

次に、ユーザーがクリックした座標のピクセルの色を取得し、対応する 3D オブジェクトを選択します。

乾杯 マウリツィオ・ベネデッティ

于 2012-01-05T09:12:48.710 に答える