2011-08-26 4 views
0

iPhone 4 OpenGL ES 응용 프로그램에 문제가 있습니다. 몇 달 동안 켜고 끄는 데 많은 어려움을 겪었습니다. 이 사이트에 대한 조언과 제안을 엿볼 수 있습니다.iPhone4 OpenGL ES GLuProject가 잘못된 y 좌표를 반환합니다.

나는 단순히 블록을 그리고 사용자가 다양한 준비로 주변을 이동하고 응용 프로그램의 대량은 C로 작성된 수 있도록 3D 게임을 쓰고 + +. 이동하기 위해

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

는 3D 점 (따라서 블록)을 해석 할 수있는 사용자에 의해 선택 :

내 문제는 내가 여기에 대한 소스 코드를 발견 GLuUnproject를 사용하는 것을 시도하고 있다는 것입니다 그리고 그것을 double precision이 아닌 floating point로 바꾸어서 회전시킵니다.

이 소스를 인터넷의 다른 버전과 비교했는데 일관성이있는 것으로 나타났습니다.

나는 광선 벡터를 얻기 위해 다음 코드를 사용

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; 
} 

는 다시, 결과는 Y 좌표 GLuProjected 가져 점에서 광선 추적 방법과 일치 사용자가 더 높은 화면을 클릭하면 점점 더 잘못됩니다. 직접 touchesBegan 이벤트에 의해보고되는 클릭 위치가 예를 들어

는 (246,190) 상기 계산 위치 (246, 215)를 클릭 위치가 직접 touchesBegan 이벤트가보고 25.

의 바깥 편차이며 (246,398)이고, 계산 된 위치는 (246, 405)이고, 불일치는 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); 

픽셀 및 가능한 스케일링에 대한 필요성 때문에 이러한 정보가 아이폰 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

@ 토미. 귀하의 질문에 감사드립니다. 위에서 추가 한 메서드가있는 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); 

이 순서를 시도 대신이의

: 시도는 초기화 코드 내부에 폭과 높이 매개 변수를 가져오고 설정하는 순서를 변경하려면 보기의 크기) :

 // 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; 

는 아이폰 4의 폭과 높이를 정확하게 640x960해야하고, contentScaleFactor 2.

해야하지만, 통지도 layoutSubviews 표준 UIView의 기능이 있고 스크린 크기와 투영 또는 절두체 매트릭스를 조정하는 유일한 곳입니다.

+0

의견을 보내 주셔서 감사 드리지만 사용 방법을 잘 모르겠습니다. 뷰포트 크기는 초기화 후에 변경되지 않습니다. 아마도 내가 지금 제공 한 추가 코드가 내가하려고하는 것을 더 잘 보여줄 것입니까? initWithCoder 메서드에서 제공 한 크기 조정 코드를 추가하려고 시도했지만 항상 1을 반환했지만 if 문이 만족스럽지 않았기 때문입니다. – Braunius

+0

죄송합니다. 죄송합니다. 나는 내 머리에서 그것을 쓴다. setContentScaleFactor로 getContentScaleFactor를 대체하십시오. 나는 내 근원을 조사했다. 또한 내 업데이트 된 주석을보십시오. – Prcela

+0

다시 고마워 - 그래도 고투 - 사과. 확장 검사에 변경 사항을 포함 시켰습니다. 이제이 호출이 호출되지만 값 1을 다시 소수점으로 반환합니다. 제안 된 두 가지 테스트 케이스에 대해 프레임 크기가 아닌 제안 된 너비/높이를 계산하면 y 디 퍼런시를 15만큼 증가시킨 것으로 보입니다. 또한 viewWillAppear 메서드에서 self.wants ... 호출을 넣으십시오. 그러나 메모가 이미 설정되어 있습니다. 상태 표시 줄은 처음에는 plist 파일에 숨겨져 있습니다. 내 디버깅이나 콘텐츠 스케일 팩터 2에서 어디서나 640 * 960을 볼 수 없습니다. 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