【GLSL】画像をY軸周りに回転する


gl-reactを使って画像(テクスチャ)をY軸周りに回転させることを考えます。

直接関係はないけどGLSLの練習【Crop, Tiling】の続きです。

 

一般的に画像を回転するというとZ軸周りの回転です。

この回転自体は単純な三角関数で可能ですし、拡大縮小、平行移動、せん断を含めてもアフィン変換で簡単に描画できます。

ただY軸周りの回転となると射影変換 (透視変換 / 透視投影)が必要です。

GLSLを書きつつも基本的な三角関数と線形代数をベースに書いていきます。

基本的な計算

まずはZ軸を0として画像の三次元座標を考え、Y軸周りに回転させます。

回転行列自体は色々と解説が転がっているので、忘れたらwikiでも参考に。

 

続いて同次座標系で射影(透視投影)を行います。

透視投影に関しては詳しい説明は見つけにくいですがこちらのPDFなんかわかりやすいです。

ここでw=1-x/d cosθとすると(x, y) => (x cosθ/w, y/w)になります。

ここでdが十分大きいとw≒1になり平行投影になることを覚えておきます。

GLSLを書いてみる

まずはd=1000として平行投影で動作を見ます。

基本的な事ですが変換の中心を(0, 0)にして変換後に戻す処理が必要です。

今回の座標は[0-1]なのでvec2(0.5)を引いて後で足すことにします。

想定では画像が中心に向かって小さくなって反対側に伸びるはずですが真逆です。

これはuvの座標に変換後のテクスチャをとっているせいです。

簡単に言うと考え方が逆。

(x, y) => (x cosθ/w, y/w)の逆で(xw/cosθ, yw) => (x, y)と考えます。

これでOK。視点dを1000から1に変更してみます。

よし上手くいった、と思いきやどこか変です。

回転してこちら側に来た辺が来た方向に戻っていくように見えます。

wをよく見ると分かるんですが、π/23π/2sin(th)が1付近で増減することを考えるとyがこうなってしまうのはしかたない。

どこかで計算を間違えたか、途中式を横着して結果だけ逆算したのがまずかったか。

 

最初からやり直す前にじーっと式を見ているとπ/23π/2sin(th)の符号が反転すればうまくいきそうに見えます。だったらcosの符号を使ってみましょう。

上手くいきました。ちゃんと回っているように見えます。

途中躓きましたが三角関数をある程度理解していれば意外と何とかなりますね。

雑記:Reactでの時間利用

Reactで時間経過による描画を行うのは思ったより面倒です。

gl-reactのtimeLoopサンプルを見るとかなりややこしいことをしています。

今回のサンプルではReactのフックを使って簡易的なタイムループを実装しました。


コメントを残す

メールアドレスが公開されることはありません。