Мой GLKMathUnproject всегда возвращает геометрию, которая находится в центре экрана

Я пытаюсь использовать GLKMathUnproject() перевести экранные координаты в геометрию, но моя процедура всегда возвращает любую геометрию в центре экрана.

Мой непроектированный код выглядит так:

+ (GLKVector3) gluUnproject: (GLKVector3) screenPoint
                     inView: (UIView*) view
            withModelMatrix: (GLKMatrix4) model
                 projection: (GLKMatrix4) projection
{
    CGSize viewSize = view.bounds.size;
    int viewport[4];
    viewport[0] = 0.0f;
    viewport[1] = 0.0f;
    viewport[2] =  viewSize.width;
    viewport[3] =  viewSize.height;

    bool success;
    GLKVector3 result = GLKMathUnproject(screenPoint, model, projection, &viewport[0], &success);

    return result;
}

И мой призыв к этому выглядит так:

- (void) handleSingleTap: (UIGestureRecognizer*) sender
{
    UITapGestureRecognizer *tapper = (UITapGestureRecognizer*) sender;
    CGPoint tapPoint = [tapper locationInView: self.view];

    // Find tapped point on geometry
    MyObject *bd = [worldObjects objectAtIndex: 0];  // the object on which I'm trying to sense the tap.
    // NOTE: bd is planar, along X/Z, with Y=0.  Visually, it's several little
    // ..squares (like a big checkerboard), and I'm trying to determine
    // ..in which square the user tapped.
    // At this point. eyesAt is { someX, y, someZ } and lookAt is { someX, 0, someZ } and
    // ..upVector is { 0, 0, -1 }.  We Zoom our view of the board in/out by
    // ..changing eyesAt.y
    float tapZ = (self.eyesAt.y - self.zNear) / (self.zFar - self.zNear);  // % of the Z-depth.  eyesAt.y = distance to geometry.
    GLKVector3 tapPoint3 = GLKVector3Make(tapPoint.x, tapPoint.y, tapZ);
    GLKVector3 tapAt = [MFglkUtils gluUnproject: tapPoint3 inView: self.view withModelMatrix: bd.modelviewMatrix projection: [self projectionMatrix]];
    // etc., snip -- do stuff with the tapAt point.

Проблема в том, что мой gluUnproject всегда возвращает геометрическую точку того, что находится в середине экрана, независимо от того, где я нажимаю.

РЕДАКТИРОВАТЬ: Проблема "всегда рядом с центром" заключается в том, что возвращаемые значения X/Z всегда очень близки к нулю, и моя геометрия центрирована на начале координат.

Похоже, проблема в моем tapZ значение. Насколько я понимаю, это должно быть значение от 0 до 1, где 0 означает "в плоскости nearZ", а 1 означает "в плоскости farZ", а промежуточные значения представляют собой процент между ними. Экспериментируя с различными tapZ значения, которые я видел:

    // gives very-very small results
    tapZ = (self.eyesAt.y - self.zNear) / (self.zFar - self.zNear); // % deep through the view frustum 

    // gives Z=0, and very small results
    glReadPixels(viewPoint.x, viewPoint.y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &tapZ);

    // gives approximately-correct results
    tapZ = 0.99943;  // found through trial & error

    // gives Z=1, and too-big results
    glReadPixels(viewPoint.x, viewPoint.y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &tapZ);
    tapZ = 1. - tapZ;

Ясно, что мне нужно пройти правильный tapZ ценность, но я не понимаю, как к этому прийти!

1 ответ

Хорошо, вот так! Оказывается, что проблема была в моем значении tapZ, и проблема связана с тем, что значения Z буфера глубины не являются линейными. (Подробнее об этом чудаке здесь.)

В любом случае, используя glProject() для проекции фрагмента рассматриваемой геометрии на экран (помните, я имею дело с видом сверху плоской шахматной доски!), Я получаю желаемое значение z. Код конечного результата получился так:

- (GLKVector3) vectorFromTapPoint: (CGPoint) tapPoint
{
    tapPoint.y = (self.view.bounds.size.height - tapPoint.y);

    BlockDiagram *bd = [worldObjects objectAtIndex: 0];

    // find Z-depth of center of board
    GLKVector3 v3Zero = { 0, 0, 0 };
    int viewport[4];
    glGetIntegerv(GL_VIEWPORT, viewport);
    GLKVector3 worldZero = GLKMathProject(v3Zero, bd.modelviewMatrix, [self projectionMatrix], viewport);

    // Find tapped point on geometry
    float tapZ = worldZero.z;
    GLKVector3 tapPoint3 = GLKVector3Make(tapPoint.x, tapPoint.y, tapZ);
    GLKVector3 tapAt = [MFglkUtils gluUnproject: tapPoint3 inView: self.view withModelMatrix: bd.modelviewMatrix projection: [self projectionMatrix]];

    return tapAt;
}

и gluUnProject был изменен на:

+ (GLKVector3) gluUnproject: (GLKVector3) screenPoint
                     inView: (UIView*) view
            withModelMatrix: (GLKMatrix4) model
                 projection: (GLKMatrix4) projection
{
    int viewport[4];
    glGetIntegerv(GL_VIEWPORT, viewport);

    bool success;
    GLKVector3 result = GLKMathUnproject(screenPoint, model, projection, &viewport[0], &success);

    return result;
}

ПРИМЕЧАНИЕ: запрос glGet*() для области просмотра дал правильно ориентированные (мое приложение - альбомная) значения, что также имеет значение!

Другие вопросы по тегам