6

すべて、

特定のモデル ビュー マトリックスと特定の投影マトリックスに対して OpenGL-ES を使用して 3D モデルを描画する iphone プロジェクトがあります。3D モデルを CALayer に置き換える必要があったため、モデル ビュー マトリックスの値を CATransform3D 構造体に入れ、 に割り当てましたlayer.transform。それはうまく機能し、レイヤーが表示され、期待どおりに画面上で移動しましたが、しばらくして、レイヤーの動作が十分に正確ではないことに気付き、射影行列を考慮する必要があります。そして、問題が発生しました.2つのマトリックスを単純に連結すると、レイヤーが奇妙に見えるか(遠く離れているため、約300であるはずですが、非常に小さく、約2ピクセルです)、まったく見えません. どうすれば解決できますか?

コードの一部は次のとおりです。

- (void)adjustImageObjectWithUserInfo:(NSDictionary *)userInfo
{
    NSNumber *objectID = [userInfo objectForKey:kObjectIDKey];
    CALayer *layer = [self.imageLayers objectForKey:objectID];
    if (!layer) { return; }

    CATransform3D transform = CATransform3DIdentity;
    NSArray *modelViewMatrix = [userInfo objectForKey:kModelViewMatrixKey];

      // Get raw model view matrix;
    CGFloat *p = (CGFloat *)&transform;
    for (int i = 0; i < 16; ++i)
    {
        *p = [[modelViewMatrix objectAtIndex:i] floatValue];
        ++p;
    }

      // Rotate around +z for Pi/2 
    transform = CATransform3DConcat(transform, CATransform3DMakeRotation(M_PI_2, 0, 0, 1));

      // Project with projection matrix
    transform = CATransform3DConcat(transform, _projectionMatrix);

    layer.transform = transform; 
}

どんな助けでも大歓迎です。

4

5 に答える 5

10

私は最近、まさにこの問題に遭遇し (私も ARToolKit を使用していました)、あなたが答えを見つけられなかったことに非常に失望しました。あなたは今先に進んだと思いますが、私はそれを理解し、この同じ問題を乗り越える可能性のある他の失われた魂のために投稿しています.

私にとって最も混乱したのは、m34 変数を小さな負の数に設定することで CALayer パースペクティブ トランスフォームを作成することについて誰もが話していることです。それは機能しますが、まったく有益ではありません。私が最終的に気付いたのは、変換が他のすべての変換とまったく同じように機能することです。これは、同次座標の列主要変換行列です。唯一の特殊なケースは、モデル ビューと射影マトリックスを組み合わせてから、openGL ビューポートのサイズにすべて 1 つのマトリックスでスケーリングする必要があることです。ここで詳細に説明されているように、m34 が小さな負の数であるスタイルでマトリックスを使用することから始めましたが、最終的にここで説明されているようにオープン GL スタイルの透視変換に切り替えまし。それらは実際には同等です相互に、それらは変換についてのさまざまな考え方を表しているだけです。

私たちの場合、CALayer 変換がオープン GL 変換を正確に複製するようにしようとしています。必要なのは、モデル ビュー、投影、およびスケーリング マトリックスを乗算し、y 軸を反転して、デバイス画面の原点が左上であり、開いている GL が左下であるという事実を説明することだけです。レイヤー アンカーが (.5,.5) にあり、その位置が画面のちょうど中央にある限り、結果は開いている GL の変換と同じになります。

void attach_CALayer_to_marker(CATransform3D* transform, Matrix4 modelView, Matrix4 openGL_projection, Vector2 GLViewportSize)
{
//Important: This function assumes that the CA layer has its origin in the 
//exact center of the screen.

Matrix4 flipY = {   1, 0,0,0,
                    0,-1,0,0,
                    0, 0,1,0,
                    0, 0,0,1}; 

//instead of -1 to 1 we want our result to go from -width/2 to width/2, same 
//for height
CGFloat ScreenScale = [[UIScreen mainScreen] scale];
float xscl = GLViewportSize.x/ScreenScale/2;
float yscl = GLViewportSize.y/ScreenScale/2;

//The open GL perspective matrix projects onto a 2x2x2 cube.  To get it onto the
    //device screen it needs to be scaled to the correct size but
//maintaining the aspect ratio specified by the open GL window.
    Matrix4 scalingMatrix = {xscl,0   ,0,0,
                               0,   yscl,0,0,
                               0,   0   ,1,0,
                               0,   0   ,0,1};

//Open GL measures y from the bottom and CALayers measure from the top so at the
//end the entire projection must be flipped over the xz plane.
//When that happens the contents of the CALayer will get flipped upside down.
//To correct for that they are flipped updside down at the very beginning,
//they will then be flipped right side up at the end.

Matrix flipped = MatrixMakeFromProduct(modelView, flipY);
Matrix unscaled = MatrixMakeFromProduct(openGL_projection, flipped);
Matrix scaled = MatrixMakeFromProduct(scalingMatrix, unscaled);

//flip over xz plane to move origin to bottom instead of top
Matrix Final = SiMatrix4MakeFromProduct(flipY, scaled);
*transform = convert_your_matrix_object_to_CATransform3D(Final);
}

この関数は、open GLprojection と openGL ビュー サイズを取得し、それらを使用して CALayer の正しい変換を生成します。CALayer のサイズは、開いている GL シーンの単位で指定する必要があります。OpenGL ビューポートには実際には [xoffset,yoffset,x,y] の 4 つの変数が含まれていますが、最初の 2 つは関係ありません。これは、CALayer の Origin が OpenGL 3d Origin に対応するように画面の中央に配置されているためです。

Matrix を、アクセスできる一般的な 4x4 列の主要な行列クラスに置き換えるだけです。マトリックスを正しい順序で乗算することを確認するだけで、何でも機能します。これが本質的に行っていることは、OpenGL パイプラインを複製することだけです (クリッピングを除く)。

于 2012-06-08T16:43:28.120 に答える
2

射影行列を取り除きましたが、これは私が持っている最高のバリアントです:

- (void)adjustTransformationOfLayerWithMarkerId:(NSNumber *)markerId forModelViewMatrix:(NSArray *)modelViewMatrix
{   
    CALayer *layer = [self.imageLayers objectForKey:markerId];

            ...

    CATransform3D transform = CATransform3DIdentity;        
    CGFloat *p = (CGFloat *)&transform;
    for (int i = 0; i < 16; ++i) {
        *p = [[modelViewMatrix objectAtIndex:i] floatValue];
        ++p;
    }

    transform.m44 = (transform.m43 > 0) ? transform.m43/kZDistanceWithoutDistortion : 1;

    CGFloat angle = -M_PI_2;
    if (self.delegate.interfaceOrientation == UIInterfaceOrientationLandscapeLeft)      { angle = M_PI; }
    if (self.delegate.interfaceOrientation == UIInterfaceOrientationLandscapeRight)     { angle = 0; }
    if (self.delegate.interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) { angle = M_PI_2; }
    transform = CATransform3DConcat(transform, CATransform3DMakeRotation(angle, 0, 0, -1));

    transform = CATransform3DConcat(CATransform3DMakeScale(-1, 1, 1), transform);

        // Normalize transformation
    CGFloat scaleFactor = 1.0f / transform.m44;
    transform.m41 = transform.m41 * scaleFactor;
    transform.m42 = transform.m42 * scaleFactor;
    transform.m43 = transform.m43 * scaleFactor;
    transform = CATransform3DScale(transform, scaleFactor, scaleFactor, scaleFactor);
    transform.m44 = 1;

    BOOL disableAction = YES;

            ...

    [CATransaction begin];
    [CATransaction setDisableActions:disableAction]; // Disable animation for layer to move faster
    layer.transform = transform;                
    [CATransaction commit];
}

完全に正確というわけではありませんが、私の目的には十分正確でした。x または y の変位が画面サイズ程度になると、たわみが顕著になります。

于 2011-08-02T07:43:39.360 に答える
1

考えられる 2 つの問題:

1) 連結順序。古典的な行列演算は右から左です。だから試してみてください

CATransform3DConcat(_projectionMatrix, transform)

、 と

2) 射影係数の値が間違っている。使用している値は何ですか?

お役に立てれば。

于 2011-08-01T04:17:51.390 に答える
0

オルソ射影行列が既に適用されている GL コンテキストにレイヤーがレンダリングされることを考慮しましたか?

Mac の紹介コメントを参照してください。このクラスは iPhone では非公開ですが、原則は同じです。

また、CATransform3D と比較して、OpenGL マトリックスはメモリ内で転置されます。それも考慮に入れてください。ほとんどの結果は同じように見えますが、そうでないものもあります。

于 2012-06-26T07:23:46.307 に答える