2015年12月13日日曜日

ベトコンは大人しく貴様のヒサツ・ワザの披露を待っていてはくれんのだ


この記事はOUCC Advent Calendar 2015のために書かれたものです。

・UV座標をいじって擬似3D


https://youtu.be/tNBWQLtC4Ls

このような擬似3Dのスプライトを作る方法を解説します。
難しい数学は一切使っておらず、手法のコアとなる部分は1次関数です。
UE4でのやり方を書きますが、アルゴリズム自体は一般的に使えるかも知れません。





全体の流れは、
1.角度を表すベクトルから、必要な数値を求める
2.その数値を元にUV座標に対して操作を加え、表示する
です。

1.角度を表すベクトルから、必要な数値を求める

角度を表すベクトルというのは、言葉で説明するのが難しいので図で表します。

このような物体を例にすると

正面から見た図(ベクトルは(0,0))

青の矢印が使用するベクトルです(ちょっと右下から見た図)

このベクトルは任意で決めます。僕の場合、ゲームコントローラーの右スティックのベクトルを使用しました。ベクトルの大きさは1以下になるようにします。(ゲームコントローラーのスティックの値を使う場合はスティックの構造上、物理的に1以下になります。)
以下、この元の2次元ベクトルをV(inputX,inputY)と置きます。

次にこのベクトルから必要な数値を導出する方法です。

Blueprintなどで次のような式を組みます。
求める数値には、naname, multX, multYという名前をつけました。

naname = V・(1/√2, 1/√2) - V・(1/√2,-1/√2)
(Vと(1,1)を正規化したベクトルの内積から、Vと(1,-1)を正規化したベクトルの内積を引いたもの)

multX = 1 - |inputX|*0.1161
multY = 1 - |inputY|*0.1161
(スプライトの拡大率。Vのx(y)成分が大きくなればなるほどスプライトは左右(上下)に縮小されて表示される。0.1161という数字は、nanameをマテリアル式中で何倍して使うかに依存する。||記号は絶対値です。)

これらの数値を元に、マテリアル式中でUV座標をいじってやります。

2.求めた数値を元にUV座標に対して操作を加え、表示する

・3D風に見える原理

メタセコイア上で本当に3D表示するとこのようになります。


これはちょうど右スティックを右上に倒した状態です。
これを平面的に見れば、右上方向に縮小され、手前にあるアイコンのテクスチャが右上にずれて表示されているように見えます。つまり、ベクトルV方向に縮小して、手前にあるものをベクトルVの定数倍(小さい数)だけずらして表示すれば、3D風に見えると考えられます。

しかし、少なくともUE4のマテリアル式では任意の方向成分について縮小するノードが存在しないため、次のような方法で表示します。


このように、せん断変形させてやります。(この度合いが先ほどのnaname)
こうすると、結果的に(1,1)方向の成分について縮小したことになります。
これと、上下左右方向の縮小とを組み合わせてやれば、4つの方向成分について縮小ができることになり、厳密ではありませんが、見た感じではVの方向成分について縮小しているように見せることが出来ます。

・具体的な方法
このようなマテリアル式を組むと実装出来ます。
(UV座標の操作がキモなので、その後の合成の方法などは省略)


右側のノードの円盤状のテクスチャが最も奥にあり、その下のノード2つの、アイコンのテクスチャ(アルファ抜きはプレビューされないので真っ白になっている)のテクスチャがその手前にあるように見えるように表示する式です。

UE4を使っている方であればこれを見れば意味はわかると思いますが、そうでない方のためにノードの説明をします。


まず、「Texcoord」というのは、元の何もいじっていないUV座標です。UV座標はR,Gの2つの成分を持つテクスチャで表され、RがUV座標のU、GがUV座標のV成分を表しています。左上が(0,0)、右上が(1,0),右下が(1,1)となっているので、このUV座標を使ってマテリアルを表示すると、元の画像がそのまま、スプライトの大きさに拡大縮小されて表示されます。
このテクスチャに、ベクトルを加減算することで斜めにします。

「BreakOutFloat2Components」は、左側のピンから入力されたテクスチャを成分分解したテクスチャを出力するノードです。
上記のマテリアル式がやっていることを日本語で書くと以下のようになります。

//////////////////
元のUV座標テクスチャから、
naname ×ベクトル(0, 0.25) × 1/2  (テクスチャ右下がせん断変形によって上下した分の半分の値)
を引いたものに、
naname × ベクトル(0, 0.25) × 「Texcoord」のUV座標のU成分
で得たテクスチャを加えることで(せん断変形させて)、
(1,1),(1,-1)方向に拡大縮小したUV座標テクスチャを得る。

そのUV座標テクスチャを、スプライト中心を起点に上下左右方向に(MultX,MultY)倍する。
それを、テクスチャノードのUV入力ピンに入力する。
////////////



naname ×ベクトル(0, 0.25) × 1/2 を元のUVテクスチャから引いてやらないと、スプライトの見かけ上の中心位置が上下にずれてしまいます。
0.25という数字は任意ですが、これを変更する場合はMultX、MultYの0.1161も変更しないといけません。ここでの0.25を⊿、0.1161をφとおくと、上(下左右)に目一杯スティックを倒したときと、正確に斜め45度にスティックを目一杯倒したときの拡大率が同じにならなければならないことから、この2つの間には次のような関係が成り立ちます。
2φ^2  - 4φ = ⊿^2 - 2⊿
片方を任意で決めてやると、2次方程式となるので2つ解が出てきますが、1を超える解などは不適なので適切な値は1つに絞れます。


基本となるテクスチャよりも手前に見えるように表示したいテクスチャには、(inputX, inputY) に-0.03(より手前のものは-0.06などそれより絶対値が大きい数値を指定する)をかけたものを、得られたUV座標テクスチャに足します。


あとは、HUDBlueprintにDrawMaterialSimpleなどのノードで描画する処理を書いてやれば、最終的に冒頭リンクの動画のような擬似3Dのスプライトを表示できます。




0 件のコメント:

コメントを投稿