2011-08-26 72 views
0

我有一個iPhone 4的OpenGL ES應用程序,我一直在努力,現在解決和關閉了幾個月,並且已經進入了死衚衕儘管有一些真正有用的一個莫名其妙的問題和誘人的提示和建議在這個網站上。的iPhone4的OpenGL ES GLuProject返回錯誤的y座標

我寫一個3D遊戲,其簡單地畫塊,並允許用戶移動它們成各種安排和應用程序的大部分是用C++編寫。

我的問題是,我想使用GLuUnproject,我發現這裏的源代碼:由用戶選擇

http://webcvs.freedesktop.org/mesa/Mesa/src/glu/mesa/project.c?view=markup

解釋三維點(因此塊),以推動並旋轉它,我贊成浮點而不是雙精度。

請注意,我已將此源與網絡上的其他版本進行了比較,它看起來是一致的。

我用下面的代碼來獲取光線矢量:

Ray RenderingEngine::GetRayVector(vec2 winPos) const 
{ 
    // Get the last matrices used 
    glGetFloatv(GL_MODELVIEW_MATRIX, __modelview); 
    glGetFloatv(GL_PROJECTION_MATRIX, __projection); 
    glGetIntegerv(GL_VIEWPORT, __viewport); 

    // Flip the y coordinate 
    winPos.y = (float)__viewport[3] - winPos.y; 

    // Create vectors to be set 
    vec3 nearPoint; 
    vec3 farPoint; 
    Ray rayVector; 

    //Retrieving position projected on near plan 
    gluUnProject(winPos.x, winPos.y , 0, 
       __modelview, __projection, __viewport, 
        &nearPoint.x, &nearPoint.y, &nearPoint.z); 

    //Retrieving position projected on far plan 
    gluUnProject(winPos.x, winPos.y, 1, 
       __modelview, __projection, __viewport, 
        &farPoint.x, &farPoint.y, &farPoint.z); 

    rayVector.nearPoint = nearPoint; 
    rayVector.farPoint = farPoint; 

    //Return the ray vector 
    return rayVector; 
} 

從近平面描繪出返回的射線到遠平面向量代碼很簡單,我發現附近的墊塊屏幕被正確識別,但是隨着屏幕向上移動,所報告的y值和所選點的預期y值似乎有越來越大的差異。

我一直在使用GLuProject手動檢查其屏幕座標生成我的世界座標如下也試過:

vec3 RenderingEngine::GetScreenCoordinates(vec3 objectPos) const 
{ 

    // Get the last matrices used 
    glGetFloatv(GL_MODELVIEW_MATRIX, __modelview); 
    glGetFloatv(GL_PROJECTION_MATRIX, __projection); 
    glGetIntegerv(GL_VIEWPORT, __viewport); 

    vec3 winPos; 

    gluProject(objectPos.x, objectPos.y, objectPos.z , 
        __modelview, __projection, __viewport, 
        &winPos.x, &winPos.y, &winPos.z); 

    // Swap the y value 
    winPos.y = (float)__viewport[3] - winPos.y; 

    return winPos; 
} 

再次,結果與在光線追蹤方法的GLuProjected y座標得到一致越來越錯誤,因爲用戶點擊更高的屏幕。

例如,當由所述的touchesBegan事件直接報告點擊位置是(246190)所計算出的位置爲(246,215)的25

,AY差異當由事件的touchesBegan直接報告點擊位置是(246,398)計算出的位置是(246,405),ay的差異是7.

x座標似乎是現貨。

我注意到,當視口高度設置爲480(全屏幕高度)時,layer.bounds.size.height報告爲436。報告的圖層邊界寬度爲320,這也是視口的寬度。

無論我使用的視口大小,還是顯示窗口頂部的狀態屏幕,436的值似乎都是固定的。

嘗試設置bounds.size。身高480以下的呼叫前:

[my_context 
     renderbufferStorage:GL_RENDERBUFFER 
     fromDrawable: eaglLayer]; 

但這似乎被忽略和高度後報告爲呼叫436:

glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, 
           GL_RENDERBUFFER_HEIGHT_OES, &height); 

我已經看到了分差的一些討論和像素以及可能的縮放需求,但一直在努力使用這些信息,因爲這些暗示了差異是由於iPhone 4的視網膜顯示分辨率以及模擬器和實際設備需要不同的縮放比例。但是,據我所知,模擬器和設備的表現一致。

2011年8月30日由於沒有收到任何反饋意見,是否有更多的信息可以讓問題變得更加易於理解?

31 - 8 - 2011 OpenGL的設置和顯示代碼如下:

- (id) initWithCoder:(NSCoder*)coder 
{  
    if ((self = [super initWithCoder:coder])) 
    { 

     // Create OpenGL friendly layer to draw in 
     CAEAGLLayer* eaglLayer = (CAEAGLLayer*) self.layer; 
     eaglLayer.opaque = YES; 

     // eaglLayer.bounds.size.width and eaglLayer.bounds.size.height are 
     // always 320 and 436 at this point 

     EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES1; 
     m_context = [[EAGLContext alloc] initWithAPI:api]; 

     // check have a context 
     if (!m_context || ![EAGLContext setCurrentContext:m_context]) { 
      [self release]; 
      return nil; 
     } 

     glGenRenderbuffersOES(1, &m_colorRenderbuffer); 
     glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_colorRenderbuffer); 

     [m_context 
      renderbufferStorage:GL_RENDERBUFFER 
      fromDrawable: eaglLayer]; 

     UIScreen *scr = [UIScreen mainScreen]; 
     CGRect rect = scr.applicationFrame; 
     int width = CGRectGetWidth(rect); // Always 320 
     int height = CGRectGetHeight(rect); // Always 480 (status bar not displayed) 

     // Initialise the main code 
     m_applicationEngine->Initialise(width, height); 

      // This is the key c++ code invoked in Initialise call shown here indented 

      // Setup viewport 
      LowerLeft = ivec2(0,0); 
      ViewportSize = ivec2(width,height); 

      // Code to create vertex and index buffers not shown here 
      // … 

      // Extract width and height from the color buffer. 
      int width, height; 
      glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, 
              GL_RENDERBUFFER_WIDTH_OES, &width); 
      glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, 
              GL_RENDERBUFFER_HEIGHT_OES, &height); 

      // Create a depth buffer that has the same size as the color buffer. 
      glGenRenderbuffersOES(1, &m_depthRenderbuffer); 
      glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_depthRenderbuffer); 
      glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, 
            width, height); 

      // Create the framebuffer object. 
      GLuint framebuffer; 
      glGenFramebuffersOES(1, &framebuffer); 
      glBindFramebufferOES(GL_FRAMEBUFFER_OES, framebuffer); 
      glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, 
             GL_RENDERBUFFER_OES, m_colorRenderbuffer); 
      glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, 
            GL_RENDERBUFFER_OES, m_depthRenderbuffer); 
      glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_colorRenderbuffer); 


      // Set up various GL states. 
      glEnableClientState(GL_VERTEX_ARRAY); 
      glEnableClientState(GL_NORMAL_ARRAY); 
      glEnable(GL_LIGHTING); 
      glEnable(GL_LIGHT0); 
      glEnable(GL_DEPTH_TEST); 

     // ...Back in initiWithCoder 

     // Do those things which need to happen when the main code is reset 
     m_applicationEngine->Reset(); 

      // This is the key c++ code invoked in Reset call shown here indented 

      // Set initial camera position where 
      // eye=(0.7,8,-8), m_target=(0,4,0), CAMERA_UP=(0,-1,0) 
      m_main_camera = mat4::LookAt(eye, m_target, CAMERA_UP); 


     // ...Back in initiWithCoder 
     [self drawView: nil]; 
     m_timestamp = CACurrentMediaTime(); 

     // Create timer object that allows application to synchronise its 
     // drawing to the refresh rate of the display. 
     CADisplayLink* displayLink; 
     displayLink = [CADisplayLink displayLinkWithTarget:self 
           selector:@selector(drawView:)]; 

     [displayLink addToRunLoop:[NSRunLoop currentRunLoop] 
       forMode:NSDefaultRunLoopMode]; 
    } 
    return self; 
} 



- (void) drawView: (CADisplayLink*) displayLink 
{ 

    if (displayLink != nil) { 

     // Invoke main rendering code 
     m_applicationEngine->Render(); 

      // This is the key c++ code invoked in Render call shown here indented 

      // Do the background 
      glClearColor(1.0f, 1.0f, 1.0f, 1); 
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 

      // A set of objects are provided to this method 
      // for each one (called visual below) do the following: 

      // Set the viewport transform. 
      glViewport(LowerLeft.x, LowerLeft.y, ViewportSize.x, ViewportSize.y); 

      // Set the model view and projection transforms 
      // Frustum(T left, T right, T bottom, T top, T near, T far) 
      float h = 4.0f * size.y/size.x; 
      mat4 modelview = visual->Rotation * visual->Translation * m_main_camera; 
      mat4 projection = mat4::Frustum(-1.5, 1.5, h/2, -h/2, 4, 14); 

      // Load the model view matrix and initialise 
      glMatrixMode(GL_MODELVIEW); 
      glLoadIdentity(); 
      glLoadMatrixf(modelview.Pointer()); 

      glMatrixMode(GL_PROJECTION); 
      glLoadIdentity(); 
      glLoadMatrixf(projection.Pointer()); 

      // Draw the surface - code not shown 
      // …  

     // ...Back in drawView 
     [m_context presentRenderbuffer:GL_RENDERBUFFER]; 
    } 
} 
+0

如何在屏幕上顯示CAEAGLLayer?如果你圍繞它構建了一個UIView,那麼它有什麼框架? 436與426相似 - 您確定您的視圖或代碼沒有假設或嘗試強制使用4:3的寬高比嗎? – Tommy

+0

@Tommy。謝謝你的問題。我有一個名爲GLView的自定義類,它具有上面添加的方法(從函數調用調用的一些代碼顯示爲內聯以便於跟蹤)。 – Braunius

回答

0

當保持渲染器的視圖的大小時,它會被以這種方式通知:

- (void) layoutSubviews 
{ 
    [renderer resizeFromLayer:(CAEAGLLayer*)self.layer]; 
    [self drawView:nil]; 
} 

- (BOOL) resizeFromLayer:(CAEAGLLayer *)layer 
{ 
    // Allocate color buffer backing based on the current layer size 
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderBuffer); 
    [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:layer]; 
    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth); 
    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight); 

    if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) 
    { 
    NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES)); 
    return NO; 
    } 

    [self recreatePerspectiveProjectionMatrix]; 
    return YES; 
} 

注意由於視圖端口大小已更改,應正確重新創建透視矩陣。它會影響到非項目結果。

到尺度問題相關:

內部視圖初始化得到的比例因子:

CGFloat scale = 1; 
    if ([self respondsToSelector:@selector(getContentScaleFactor:)]) 
    { 
     self.contentScaleFactor = [[UIScreen mainScreen] scale]; 
     scale = self.contentScaleFactor; 
    } 

視圖大小實際上幾乎是標準和視網膜顯示屏,320像素寬相同,但渲染圖層大小將增加一倍,視網膜640px。在opengl渲染器空間和視圖空間之間轉換時,應考慮縮放因子。

補充: 嘗試改變用於獲取和設置寬度和高度參數初始化代碼中的順序:

取而代之的是:

int width = CGRectGetWidth(rect); // Always 320 
    int height = CGRectGetHeight(rect); // Always 480 (status bar not displayed) 

    // Initialise the main code 
    m_applicationEngine->Initialise(width, height); 

     // This is the key c++ code invoked in Initialise call shown here indented 

     // Setup viewport 
     LowerLeft = ivec2(0,0); 
     ViewportSize = ivec2(width,height); 

     // Code to create vertex and index buffers not shown here 
     // … 

     // Extract width and height from the color buffer. 
     int width, height; 
     glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, 
             GL_RENDERBUFFER_WIDTH_OES, &width); 
     glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, 
             GL_RENDERBUFFER_HEIGHT_OES, &height); 

試試這個順序(dont't使用從視圖大小):

 // Code to create vertex and index buffers not shown here 
     // … 

     // Extract width and height from the color buffer. 
     int width, height; 
     glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, 
             GL_RENDERBUFFER_WIDTH_OES, &width); 
     glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, 
             GL_RENDERBUFFER_HEIGHT_OES, &height); 

    // Initialise the main code 
    m_applicationEngine->Initialise(width, height); 

     // This is the key c++ code invoked in Initialise call shown here indented 

     // Setup viewport 
     LowerLeft = ivec2(0,0); 
     ViewportSize = ivec2(width,height); 

還要確保你已經設置了UIController參數f或全屏幕布局:

self.wantsFullScreenLayout = YES; 

在此之後,對於iphone 4的寬度和高度應該完全640x960的,和contentScaleFactor應2.

但是,還要注意的是layoutSubviews是標準的UIView功能和這是我獲得屏幕尺寸和調整投影或平截頭體矩陣的唯一地方。

+0

感謝您的反饋,但我不確定如何使用它。初始化後,視口大小不會更改。也許我現在提供的附加代碼將更好地顯示我正在嘗試做什麼?我試着添加你在initWithCoder方法中提供的縮放代碼,它總是返回1,但那是因爲if語句不滿意。 – Braunius

+0

哎呀。抱歉。我從頭腦裏寫下來。用setContentScaleFactor替換getContentScaleFactor。我檢查了我的來源。也看看我更新的評論。 – Prcela

+0

再次感謝 - 仍在掙扎 - 道歉。已包含對縮放檢查的更改,現在會調用它,但會返回1的值。根據建議計算寬度/高度(而不是幀大小)似乎已經將我所引用的兩個測試案例的y偏差增加了15。另外,將self.wants ...調用放在viewWillAppear方法中,但注意已經設置狀態欄最初隱藏在plist文件中。我在調試中的任何地方都看不到640 * 960,或者內容比例因子爲2。我只是不明白436的數字來自支撐高度。 – Braunius

0

那麼......現在感覺有些愚蠢......

問題是,我使用的視圖實際上是436像素高,這是我在實驗時允許在不再使用的主窗口上留出空間用於共同導航欄的空間。

將此設置回480解決了問題。

對那些看着這個,特別是那些迴應的人的道歉。

經過數月的挫折,我現在要離開我的苦難!

+0

LOL! :D祝你好運!無論如何,對於IOS 4,在視網膜上進行調試時內容比例因子必須爲2。看到這篇文章:http://stackoverflow.com/questions/4189745/ios-4-0-contentscalefactor-and-scale-how-to-handle-in-3-1-3 – Prcela