組み込みの埋まってるとこ

システム寄りの組み込みCプログラミングBLOG

OpenVGで画像を狙いどおり表示する方法

OpenVGで画像を表示するとき単に座標だけを指定して表示しているときは問題ないのですが、拡大や回転を加えると思いどおり表示されなくなることがよくあります。 その原因をOpenVGの内部的な計算方法から探り、最終的に画像を意図どおり自由自在に表示できるように頭の中を整理します。

行列変換は順序が大事

OpenVGでは行列変換を使って画像を描画しているということは既にどこかで見聞きしたことがあると思います。 一般的な2Dグラフィックスでは画像を表示する座標を指定したうえでて回転して表示しようとするときこれらは互いに独立したパラメータになっていて設定の順序を入れ換えても結果は同じになります。 ところがOpenVGでは座標と回転はどちらも行列変換の一要素として扱われるため設定順序を入れ換えると結果が変わってしまいます。 数学の授業で行列演算では必ずしも交換則が成り立たないと習ったとおりです。 このことはOpenVGを使いこなす上で常に意識しておくべきポイントになります。

OpenVGでの行列演算の仕組み

OpenVGでは画像変換やパス変換等の目的別にいくつか行列があり、その中から目的に合わせてどれか1つの行列を選択して使用します。 選択した行列はまず最初に単位行列に初期化します。 この後プログラム中で行列変換の関数が実行される度に現在選択している行列に対して乗算が起こり変換が合成されていきます。 そして描画の関数が実行されたときそれまで変換を合成してきた行列により画像上の点に対して変換が始まります。

この様子を下記のようなプログラムにより 画像上の点(x,y)が点(x',y')に変換されるとして式に表すと次のようになります。

vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
vgLoadIdentity();
vgTranslate(tx,ty);
vgRotate(rz);
vgScale(sx,sy);
vgDrawImage(img);

\begin{bmatrix}
1 & 0 & 0 \\
0 & 1 & 0 \\
0 & 0 & 1 \\
\end{bmatrix}
\begin{bmatrix}
1 & 0 & tx \\
0 & 1 & ty \\
0 & 0 & 1 \\
\end{bmatrix}
\begin{bmatrix}
cos(rz) & -sin(rz) & 0 \\
sin(rz) & cos(rz)& 0 \\
0 & 0 & 1 \\
\end{bmatrix}
\begin{bmatrix}
sx & 0 & 0 \\
0 & sy & 0 \\
0 & 0 & 1 \\
\end{bmatrix}
\begin{bmatrix}
x \\
y \\
1 \\
\end{bmatrix}
=
\begin{bmatrix}
x' \\
y' \\
1 \\
\end{bmatrix}

ここで重要なことはプログラムでは変換が移動(vgTranslate)、回転(vgRotate)、拡大(vgScale)の順序になっているのに対し、 式を見ると分かるように画像上の点(x,y)に対しては拡大、回転、移動といった具合にプログラムとは逆の順序で変換が作用しているということです。

ハードウェア構成上のメリットがあって画像に対して逐次変換せず、マトリクスとして溜め込んでから変換するようになっているため数学的にはやや直感的ではない使い方になっています。しかしこのことは重要なのでもしピンとこなかったとしてもOpenVGでは変換は順序を逆にしてプログラムするということを覚えておいてください。

画像は最初どこにあるのか

画像上の点(x,y)と言われてもそもそも画像が存在する座標が分からなければ始まりません。 OpenVGでは画像の最初の位置は画面の左下です。 例えばvgLoadIdentity()した直後にvgDrawImage()すると画面の左下に画像が表示されます。

画面の左下が座標系の原点になっていて、画像も最初は原点に位置するということです。

拡大・回転の原点をどこにとるか

画像の回転や拡大は大昔のスプライトベースの2Dグラフィックスのように画像単独で変形すると考えるのは間違いです。 OpenVGでは回転と拡大は行列変換の一要素ですので画像と行列変換の原点との関係を常に意識しなければなりません。

例えば風車が回転するときのように画像の中心を原点にして回転させたいのであれば、回転行列で回転させる前に画像の中心を座標系の原点、つまり画面の左下に予め移動させておく必要があります。目的の座標へは回転の後で移動させることになります。

まとめ ~それでもやはり難しい?~

ここまでの説明でOpenVGでの行列演算の仕組みとプログラムする上での注意点をまとめました。 OpenVGで画像を意図どおり表示できるようになるための基本はこれで十分です。

しかしながら実際にやってみると どこかでレガシーな2Dグラフィックスライブラリでの考え方から抜け切れずに分からなくなってしまうこともあるでしょう。 それでも基本に戻って落ち着いて考えればきっと解決することができると思います。

関連記事