GoogleAnalytics

SyntaxHighlighter

2012年2月12日日曜日

[Glaeja] ウチのオカンでもわかる「変形と移動」

…実際にウチのオカンに教えたわけじゃありませんがw
Glaeja』の「変形と移動」レイヤーのチュートリアルです。

できるだけ数式を使わないように努力はしてみます。



「変形と移動」レイヤーは、次レイヤーの描画結果(以下、面倒なので画像と表記)に対して、変形と平行移動をおこなう効果レイヤーです。

設定可能なパラメータは左図のようになっています。ちょっと記述が面倒なので、

・マトリクス前の並進:水平 = aX
・マトリクス前の並進:垂直 = aY
・マトリクスの左上 = LT
・マトリクスの右上 = RT
・マトリクスの左下 = LB
・マトリクスの右下 = RB
・マトリクス後の並進:水平 = pX
・マトリクス後の並進:垂直 = pY
と略記しましょう。


画像のうちのある画素(X, Y)は、このレイヤーによる変形と平行移動の結果、新しい位置(X', Y')に移動するとすると、その(X', Y')は、

・X' = LT * (X + aX) + RT * (Y + aY) + pX 
・Y' = LB * (X + aX) + RB * (Y + aY) + pY

となります。…意味がわからないよwww というわけで、非常にざっくりと表現すると、

ある画像を、
(1) [マトリクス前の並進]だけ平行移動
(2) 平行移動した画像を[マトリクス]で変形
(3) 変形後の画像を[マトリクス後の並進]だけ平行移動

という操作をおこなっている、ということになります。

ここで重要なのは、「[マトリクス]による変形の前と後の2回平行移動をおこなっている」というところです。これは後でじんわり効いてきますので覚えておいてください。



まずは、[マトリクス]による変形、について触れてみましょう。

変形、といっても色々な種類があります。下図にそれらの一例を示します。
これらのうち、「変形と移動」レイヤーで実現できる変形は⑥以外です。

①~⑤と⑥とでは何が異なっているのでしょうか?それは「長方形の向い合う2辺の平行性」です。
長方形は(辺の長さによらず)向かい合う2辺が互いに平行です。この長方形を変形したときに、

・①~⑤:向かい合う2辺が平行のまま(長方形が長方形もしくは平行四辺形に変形される)
・⑥:向かい合う2辺が平行でなくなる(長方形が台形やいびつな四角形に変形される)


数学的には、①~⑤のような変形を『線形変換』といい、「変形と移動」レイヤーの変形は、この線形変換のみが可能となっています。


さて、能書きはいいとして、この『線形変換』を簡単に理解する方法はないのでしょうか?…ありますw。
ざっくり言うと、

『線形変換』とは、座標軸を伸び縮みさせたり傾けたりする、ことである。

ということです。…って、どういうことでしょうw?

ま、実際にやってみましょう。Glaejaのウィジェット描画座標系は、左上が原点、右にXが増え、下にYが増えますので、下のような感じですかね。
この図では、座標系の(20, 10)をアンカーポイントとして、横30, 縦20の画像を置いています。
では、この座標軸のうち、X軸だけを右下がりに傾けてみると…下のような感じになります(変形前のものを薄く重ねてあります)。
紙箱を押さえつけたように、座標が平行四辺形に歪められていますね。画像も、この歪められた座標系で描かれますので、同様に歪められます。
では、ここからさらにY軸も傾けてみましょう…こんな感じに。
なんとなく、「座標軸を傾ける」というイメージがつかめてもらえたんではないでしょうか?
では、次は座標軸を回転させてみましょう…下のようにX・Y軸を時計回りに15度回転させてみます。
X軸・Y軸が同じ方向に傾くので、座標軸の直角は変化していないことが見てわかります。
では、座標軸を傾けないで、伸び縮みだけさせてみましょう…X軸は1.5倍に伸ばし、Y軸は半分に縮めてみます。
座標軸の数値が重なって見難いですが、感覚を掴んでもらえればOKです。
これで、「座標軸を伸び縮み・傾ける」とどんな変形が行われるか、というイメージが掴めたのではないでしょうか?で、問題は『マトリクスの各パラメータと「座標軸の伸び縮み・傾き」』の関係ですね。 これは、

 ・原点と点(1, 0)の変形後の座標を結ぶ直線が変形後のX軸
 ・原点と点(0, 1)の変形後の座標を結ぶ直線が変形後のY軸

となります。数学的に言うと「基底ベクトルの変換」というやつですねw 例えば、

・マトリクスの左上 = LT
・マトリクスの右上 = RT
・マトリクスの左下 = LB
・マトリクスの右下 = RB

というマトリクスによって、点P(X, Y)が点P'(X', Y')に変形されるとすると、その式は以下のようになります。

X' = LT * X + RT * Y
Y' = LB * X + RB * Y

さて、以下のようなマトリクスを考えてみましょう。


・マトリクスの左上 = 1
・マトリクスの右上 = 0
・マトリクスの左下 = 0.5
・マトリクスの右下 = 1

このマトリクスによって、点(1, 0)は、

1(LT) * 1(X) + 0(RT) * 0(Y) = 1(X')
0.5(LB) * 1(X) + 1(RB) * 0(Y) = 0.5(Y')

と点(1, 0.5)へ移動することになります。















原点とこの点を結ぶ直線が新しいX軸となるわけです。















このとき、新しいX軸上での(1, 0)と原点との距離が伸びていることに注意してください。これが回転と歪み(剪断)の違いです。
ちなみに、このマトリクスではY軸上の点(0, 1)を変形しても(0, 1)のままですので、Y軸は変わらないままです。

マトリクスを、以下のようにすると、

・マトリクスの左上 = 1
・マトリクスの右上 = 0.333
・マトリクスの左下 = 0.5
・マトリクスの右下 = 1

(1, 0)は、点(1, 0.5)に、
1(LT) * 1(X) + 0.333(RT) * 0(Y) = 1(X')
0.5(LB) * 1(X) + 1(RB) * 0(Y) = 0.5(Y')

(0, 1)は、点(0.333, 1)に、
1(LT) * 0(X) + 0.333(RT) * 1(Y) = 0.333(X')
0.5(LB) * 0(X) + 1(RB) * 1(Y) = 1(Y')

となり、以下のようにX・Y両座標軸が変わります。
















このようなマトリクスによる変形(「歪み」とか「剪断」とか「スキュー」とか言う)のパラメータをざっくり表すと、

○歪みマトリクス: 
 ・マトリクスの左上 = 1で固定
 ・マトリクスの右上 = 垂直方向の歪み度合い
 ・マトリクスの左下 = 水平方向の歪み度合い
 ・マトリクスの右下 = 1で固定
とでも表現できるでしょうか。

次に、拡大・縮小をおこなうマトリクスをみてみましょう。これは非常に簡単で、
・マトリクスの左上 = 2
・マトリクスの右上 = 0
・マトリクスの左下 = 0
・マトリクスの右下 = 0.5
というマトリクスを考えると、

(1, 0)は、点(2, 0)に、
2(LT) * 1(X) + 0(RT) * 0(Y) = 2(X')
0(LB) * 1(X) + 0.5(RB) * 0(Y) = 0(Y')

(0, 1)は、点(0, 0.5)に、
2(LT) * 0(X) + 0(RT) * 1(Y) = 0(X')
0(LB) * 0(X) + 0.5(RB) * 1(Y) = 0.5(Y')

となります。












ざっくり表すと、

○拡大縮小マトリクス: 
 ・マトリクスの左上 = 水平方向拡大縮小率
 ・マトリクスの右上 = 0で固定
 ・マトリクスの左下 = 0で固定
 ・マトリクスの右下 = 垂直方向拡大縮小率
とでも表現できるでしょうか。
ちなみに、拡大縮小率をマイナスの値にすると反転になります。

では最後に回転をやってみましょう。

○時計回りにθ度回転させるマトリクス:
 ・マトリクスの左上 = cos(θ)
 ・マトリクスの右上 = -1*sin(θ)
 ・マトリクスの左下 = sin(θ)
 ・マトリクスの右下 = cos(θ)
となります。

例えば、時計回りに15度回転させる場合、cos(15度) = 0.966、sin(15度) = 0.259 ですので、
・マトリクスの左上 = 0.966
・マトリクスの右上 = -0.259
・マトリクスの左下 = 0.259
・マトリクスの右下 = 0.966
となり、

(1, 0)は、点(0.966, 0.259)に、
0.966(LT) * 1(X) - 0.259(RT) * 0(Y) = 0.966(X')
0.259(LB) * 1(X) + 0.966(RB) * 0(Y) = 0.259(Y')

(0, 1)は、点(-0.259, 0.966)に、
0.966(LT) * 0(X) - 0.259(RT) * 1(Y) = -0.259(X')
0.259(LB) * 0(X) + 0.966(RB) * 1(Y) = 0.966(Y')
なります。












さて、これでマトリクスで表現できる「歪み・拡大縮小・反転・回転」について理解できたかと思います。
でも何かが足りない気がします…そうですね、こんな場合が足りませんかね。













マトリクスによる回転は、その回転中心が原点(ウィジェット左上隅)となるわけですが、多くの場合、原点とかじゃなくて画像の中心とか文字列中心とかイイ感じのところで回転させたいわけですよね。

そういうときに、最初に述べた「[マトリクス]による変形の前と後の2回平行移動」を使うわけです。

要するに、
(1) 画像中心等が原点にくるよう平行移動
(2) マトリクスによる回転
(3) 画像中心等が元の位置に戻るよう平行移動

すればイイのです。図にすれば下のような感じ。



























この図の場合ですと、画像の中心座標が(35, 20)ですので、
・マトリクス前の並進:水平 -35
・マトリクス前の並進:垂直 -20
・マトリクスの左上 0.966
・マトリクスの右上 -0.259
・マトリクスの左下 0.259
・マトリクスの右下 0.966
・マトリクス後の並進:水平 35
・マトリクス後の並進:垂直 20

となります。

以上、これでワカランかったら知らん。

0 件のコメント: