高度な検索
Developer Connection
Member Login ログイン | ご入会 ADC連絡先

Technical Q&A QA1227
Why does my identity matrix look strange?


Q: QuickTime の単位行列が間違っているように見えるのはなぜかを調べようとしています。QuickTime の単位行列は次のようになるはずだと思われます。

1 0 0
0 1 0
0 0 1

しかし、SetIdentityMaxtix を使用して作成するときには必ず、以下のようになります。

1 0 0
0 1 0
    0 0 16384

何か間違ったことをしているのでしょうか?16384 という数字は何を意味するのでしょうか?

A: MatrixRecord は Fixed 値の 3 × 3 の配列として宣言されていますが、この構造体の最後の列は、実際には Fract として解釈されています。したがって、16384 という数字は、まさに Fract の 1.0 なのです。

さらに詳しく見ていきます。

Fixed は 16 ビットの符号付き整数に 16 ビットの有理数を足したものです。
Fract は 2 ビットの符号付整数に 30 ビットの有理数を足したものです。

typedef long Fixed;
typedef long Fract;
struct MatrixRecord {
     Fixed matrix[3][3];
};
typedef struct MatrixRecord MatrixRecord;

図 1 の各セルは、3 × 3 行列の対応する要素のデータ型を示しています。行列の最初の 2 列の要素は Fixed 値で表現されます。3 列目の要素は、Fixed 値と宣言されていますが、内部的には Fract 値として表現されます。Fract データ型は、2 ビットの整数と 30 ビットの有理数を含む 32 ビットの固定小数点値を指定します。

[0][0]Fixed       [1][0]Fixed       [2][0]Fract
[0][1]Fixed       [1][1]Fixed       [2][1]Fract
[0][2]Fixed       [1][2]Fixed       [2][2]Fract

図 1. MatrixRecord

このようになるのは、最後の列で非アフィン(遠近法)変換を定義しているためです。これらの変換には、さらに高い精度が要求されますが、値の範囲はそれほど大きくする必要はありません。

この最後の列は、要素値と動作の間のマッピングが複雑であるため、独自に正しく設定するのは極めて困難です。QuickTime が提供する QuadToQuadMatrix API は、遠近法行列のセットアップに使用できるほか、これを使用してあらゆる変換(拡大縮小、回転、ゆがみなど)も簡単に行えます。

OSErr QuadToQuadMatrix(const Fixed *source,
                       const Fixed *dest, MatrixRecord *map);

図 2. QuadToQuadMatrix API

この呼び出しは、4 つの開始点と 4 つの最終点を取り、これらの点の間をマップする行列を定義します。

以下の例は、QuadToQuadMatrix を使用して行列を作成し、スターウォーズタイプの「遠方へのスクロール」効果を実現するものです。関数は単純に、ソースポイント (x, y)、左上、右上、右下、左下から開始します。次に、目的のポイントとして左上を x 方向に+20、y 方向に+40、右上を x 方向に−20、y 方向に+40、右下、左下を設定します。

void SetPerspectiveMatrix(Rect &inRect, MatrixRecord &outMatrix)
{
    FixedPoint source[4], dest[4];
    source[0].x = Long2Fix(inRect->left);
    source[0].y = Long2Fix(inRect->top);
    source[1].x = Long2Fix(inRect->right);
    source[1].y = Long2Fix(inRect->top);
    source[2].x = Long2Fix(inRect->right);
    source[2].y = Long2Fix(inRect->bottom);
    source[3].x = Long2Fix(inRect->left);
    source[3].y = Long2Fix(inRect->bottom);
    dest[0].x = Long2Fix(inRect->left + 20);
    dest[0].y = Long2Fix(inRect->top + 40);
    dest[1].x = Long2Fix(inRect->right - 20);
    dest[1].y = Long2Fix(inRect->top + 40);
    dest[2].x = Long2Fix(inRect->right);
    dest[2].y = Long2Fix(inRect->bottom);
    dest[3].x = Long2Fix(inRect->left);
    dest[3].y = Long2Fix(inRect->bottom);
    QuadToQuadMatrix((Fixed *)source, (Fixed *)dest, outMatrix);
}

リスト 1. QuadToQuadMatrix の使用例



[2002 年 1 月 3 日]