2013-06-06 31 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總是返回無論是在幾何點無論我在哪裏點擊屏幕中間。

編輯: 「始終中心附近」問題是,返回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價值,但我不知道如何在它到達!

回答

0

好的,哇!事實證明,問題我的tapZ值,並且問題與深度緩衝區Z值不是線性的事實有關。 (更多關於那個不好的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 *()視口給方向是否正確(我的應用程序是景觀)的價值觀,這也很重要!