0

私は iPhone 4 OpenGL ES アプリで不可解な問題を抱えており、このサイトでいくつかの本当に有用で興味をそそるヒントや提案にもかかわらず、ここ数か月オンとオフに取り組んでおり、行き詰まりに陥っています。

ブロックを単純に描画し、ユーザーがブロックをさまざまな配置に移動できるようにする 3D ゲームを作成しています。アプリの大部分は C++ で記述されています。

私の問題は、ここでソースコードを見つけたGLuUnprojectを使用しようとしていることです:

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

ユーザーが選択した3Dポイント(したがってブロック)を解釈して移動および回転させ、倍精度ではなく浮動小数点に変換しました。

このソースをネット上の他のバージョンと比較したところ、一貫しているように見えることに注意してください。

次のコードを使用して光線ベクトルを取得します。

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 イベントによって直接報告されたクリック位置が (246,190) の場合、計算された位置は (246, 215) であり、不一致は 25 です。

touchesBegan イベントによって直接報告されたクリックされた位置が (246,398) の場合、計算された位置は (246, 405) であり、不一致は 7 です。

x座標は正しいようです。

ビューポートの高さが 480 (全画面の高さ) に設定されている場合、layer.bounds.size.height が 436 と報告されることに気付きました。レイヤー境界の幅は、ビューポートの幅でもある 320 として報告されます。

436 という値は、使用するビューポートのサイズに関係なく、ウィンドウの上部にステータス スクリーンを表示するかどうかに関係なく固定されているようです。

次の呼び出しの前に、bounds.size.height を 480 に設定しようとしました。

[my_context
        renderbufferStorage:GL_RENDERBUFFER
        fromDrawable: eaglLayer];

しかし、これは無視されているようで、高さは後で呼び出しで 436 として報告されます。

glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES,
                                GL_RENDERBUFFER_HEIGHT_OES, &height);

ポイントとピクセルの違いとスケーリングの必要性についての議論を見てきましたが、その違いは iPhone 4 の Retina ディスプレイ解像度によるものであり、異なるスケーリングが必要になることを示唆していたため、その情報を有効に使用するのに苦労しました。シミュレータと実際のデバイス。ただし、私が知る限り、シミュレーターとデバイスは一貫して動作しています。

2011 年 8 月 30 日 これに関するフィードバックが得られないので、質問をより扱いやすくするために提供できる情報はありますか?

2011 年 8 月 31 日 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];
    }
}
4

2 に答える 2

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ピクセルですが、レンダリングレイヤーサイズは網膜の場合は2倍の640ピクセルになります。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パラメーターが設定されていることを確認してください。

self.wantsFullScreenLayout = YES;

その後、iphone 4の場合、幅と高さは正確に640x960になり、contentScaleFactorは2になります。

ただし、layoutSubviewsは標準のUIView関数であり、画面サイズを取得して投影または錐台マトリックスを調整する唯一の場所であることに注意してください。

于 2011-08-30T14:28:53.787 に答える
0

うーん...ちょっとバカみたいな感じです...

問題は、私が使用していたビューが実際には 436 ピクセルの高さであったことでした。これは、私が使用しなくなったメイン ウィンドウに共通のナビゲーション バーのスペースを確保する実験を行ったときに、何年も前に設定したものです。

これを 480 に戻すと、問題は解決しました。

これを見てくださった方、特に回答してくださった方、申し訳ありません。

私は今、何ヶ月にもわたる欲求不満の後、自分の悲惨さから抜け出すつもりです!

于 2011-09-02T10:52:59.957 に答える