2013-06-06 2 views
0

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

Мой unproject код выглядит следующим образом:

+ (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 всегда возвращает геометрическую точку все, что в на середине экрана, независимо от того, где я нажимаю.

EDIT: «всегда рядом с центром» Проблема в том, что возвращаемые значения X/Z всегда очень-близко к нулю, и моя геометрия сосредоточена на нуле.

Похоже, что проблема связана с моим значением tapZ. Я понимаю, что это должно быть значение от 0-1, где 0 означает «на плоскости ближнего Z», а 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 значение, но я не понимаю, как поступить в этом!

ответ

0

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

Во всяком случае, используя 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 *() для окна просмотра дал правильно сориентированы (мое приложение ландшафт), что также имеет значение!