フメンピック lua解説①: TQBFJOLD + YOU (演出編)

f:id:paraphrohn:20200620234601p:plain

カスです。

 The Quick Brown Fox Jumps Over Lazy Dog (D_AAN Remix)

前述の通りDual-Ego luaの改良版。具体的な変更点としては

・ノート表示部分

f:id:paraphrohn:20200620235107p:plain

f:id:paraphrohn:20200620235049p:plain

Dual-Ego: 画面内に現れたタイミングからJUST判定までの秒数だけ、linear (or accelerate or decelerate) で補助Actorの aux value を減少させて、aux * 画面高さの位置に毎フレーム描画

f:id:paraphrohn:20200620235158p:plain

改良後: (JUST判定の拍数 - 現在の拍数) / 画面内に存在する拍数 * 画面高さの位置に毎フレーム描画

いや意味分からんかもしれませんが、これでソフラン・停止に自動対応するようになりました。ついでに細かいズレも治りました。

・譜面読み込み部分

f:id:paraphrohn:20200620235259p:plain

難易度とプレイスタイルを読んで自動的に対応する難易度のluaを読み込みに行くようになりました。同様にバーサス時にはプレイヤーを2つ、そうでないときはプレイヤーを1つだけ読み込むようになっています。さらにSINGLE/DOUBLEに応じてプレイヤーの表示位置も変更されます。この機能がSM5じゃないと使えないのでITGへの逆移植が難航してます。

・ノート毎の命令対応

f:id:paraphrohn:20200620235828p:plain

f:id:paraphrohn:20200621000011p:plain

readme.txtにあるようにmineやfakeを意味するMとFを使ってノート毎の命令が出せるように。これは譜面情報として保管されるのでノート表示部分で対応する命令を書き込むことでいろんな効果が出せます。また、3種類で足りない場合は手動でstep.luaを書き換えてXとかZとか入れてやって、step_converter.luaに上のように追加してやればいくらでも種類が増やせます。まあ割と読みにくい関数であるparaph_updatenotes()を弄れないと使えませんが。

・その他

ITG版では画面ギリギリまでしか表示してなかったのを、本来の3倍の位置まで表示するように。これでいろいろMODS系のギミックを入れても大丈夫になりました。

f:id:paraphrohn:20200620235741p:plain

ホールド対応。簡易版ですが搭載、小節をまたぐホールドで、かつ前後の小節の最小単位が違う場合は表示がおかしくなります。ここの修正は難しそうなので譜面側でなんとかするしか。実装は……見ての通り汚いです。

 

YOU(SHORT CUT)

1. 演出考

前回書いた通り基本は色んなMVからインスピ受けてるだけですが、まあそれを実現する方法は考えないといけないわけです。というわけで、実装する前にまずはどう表現していくかを考えます。

f:id:paraphrohn:20200621001216p:plain

まずはシンプルな回転の組み合わせ。こういう表現は変にField of Viewを入れるとダサくなるのでFOVかけずに平面性を強調します。rotationy(90)つければ画像を消せるので自然な図形移行が可能。ちなみにフォントはフリーフォントです。

f:id:paraphrohn:20200621001626p:plain

曲を通して出てくる背景の線は全部Quadのみで構成。前方はcroptopのみ後方はfadebottomを軽くかけてからcropbottomすることで動きを出せます。また、Quad類の配置はvertalign('top')とveralign('middle')を使い分けて必ず対称かつ円形になるようにしています。ここはマジでずっと流れ続けるのである程度力入れて作って、backing_quads.luaとして隔離して一番奥に配置しています。

f:id:paraphrohn:20200621002412p:plain

地味に手が込んでるような気がする開幕。実際はFGに六角形の画像を回しながら拡大しているだけです。その上で、PlayerP1とPlayerP2のNoteFieldをテクスチャ化して六角形画像の上から表示させ、これに50% stealthをかけてBlend('Subtract')で重ねています。50% stealthはご存知ノートが真っ白になる = diffuseが(1,1,1,1)状態になるわけですが、これに「奥の色から手前の色を引いた値を表示する」Blend('Subtract')を組みわせると、背景から(1,1,1,1)を引くことになり、結果として背景が黒い部分には何も影響しないまま白い部分だけに(1-1,1-1,1-1) = (0,0,0)の色を持つ = 黒いノートを表示させることができます。

また後述しますが、今回のluaでは徹底的なまでの3Dモデルの使い回しをしており、実は矢印モデルとラストシーンの背景以外には8つのActorしか登場しません。このシーンではP1_1とP2_1の二つのNoteFieldテクスチャを重ねて表示しています。

f:id:paraphrohn:20200621003016p:plain

色が分かれる場所では、上の2つではなく、別の6つのActorにNoteFieldを張り付けたものをdiffuseで色指定して表示させています。テクスチャとして貼っているだけで、NoteFieldそのものではないので色指定ができるわけです。この間P1_1とP2_1は非表示に。また背景の灰色の六角形は、さっき使った六角形と同じ画像をdiffuseで灰色化して重ねています。さらに背景色に合わせてbacking_quads.luaの中身を全部黒色に変更しています。

今回は判定文字を重ならせないために常に左右に置いていますが、これも判定画面をテクスチャ化してそれぞれ適当なActorに貼り付けて上から重ねているだけです。

f:id:paraphrohn:20200621003754p:plain

前半のド派手なシーン。さらに同じ六角形画像をdiffuseで黒くして上から重ねて拡大し背景を黒くした上に、改めて50% stealthのNoteFieldテクスチャを置きます。実際には右に描いたような多角錐の頂点を切り取った形の側面に対応する数のテクスチャを張り付けたものを下から覗いている感じになっています。この多角錐を回転させることで回転表現を出しています。また多角錐全体にFOVを強めにかけて立体感を出しています。

f:id:paraphrohn:20200621004058p:plain

ここの虹色の発光は、右下のような画像をSubtractモードで左右に動かして重ねているだけです。黒い部分からは色が引けないのでそのまま、白い部分は虹色の補色となるので結果として白い部分 = NoteFieldとbacking_quadsだけが虹色に光ります。まあ色はかなり調整しましたが。

f:id:paraphrohn:20200621004330p:plain

NoteFieldの退場はaddzを強めにかけ、遠近法効果での拡大+z方向の描画限界を利用します。また、奥から出てくる矢印モデルはyou_spriteに含まれず、FOVがかかっていない (なぜならActorMultiVertexのLineStripはFOVをかけるとダサくなる) のでz方向は0のままzoomだけで出現させています。

f:id:paraphrohn:20200621004817p:plain

このシーンでは、先ほどまでNoteFieldを張り付けていたActor類の一部をただの真っ白or影付きテクスチャに変更して六角形の土台とし、その上にNoteFieldを張り付けたActorを重ねています。ここの変わり身の早さはかなりヤバいです。

1枚目: P2_4 on P1_2 and P1_1

2枚目: P2_3 on P1_4 and P1_3

3枚目: P2_1 and P2_2 → P2_4 on P1_2 and P1_1

4枚目: P1_2 and P1_1 → P2_3 on P1_4 and P1_3

各六角形はz方向に720pxずつずらして-1440~1440の領域に配置し、それぞれをz方向の表示限界によって画面から追い出したり画面内に突っ込みながら、ステージ全体であるyou_spriteにかかるrotation類で位置を調整してそれっぽく見せています。

先も言った通り3Dモデルを8Actor分しか使用していないので3枚目以降はActorが足りず、1枚目が消えた瞬間に3枚目に貼り付け直す等して節約を図っています。地味にここの調整に一番時間がかかりました。

f:id:paraphrohn:20200621005303p:plain

戻るシーン。ぱっと見レイヤーsubtractですが、単純に今まで3枚重ねにしていた白・灰・黒の六角形を順に縮小しているだけです。結果として黒は無くなり、灰が大きく表示され、BGは全部白になります。

本当は最後に踏んだHOLDが白色で背景に伸びてきて、そこから黒が割れるみたいな演出も考えていたんですがシンプルにまとめました。

f:id:paraphrohn:20200621005726p:plain

ラストシーン。今まで書いていませんでしたが、NoteField類の表示優先度はP2_4 > P2_3 > ... P2_1 > P1_4 > ... >P1_1になっています。

で、実際に回転して各オブジェクトが重なるこのシーンでは、1Pと2P代表としてP2_1とP1_4を真ん中にNoteFieldを張り付けて表示し、残りを今度は帯として左右に召喚しています。結果、P2_2~P2_4からなる帯は真ん中のNoteFieldよりも手前側に、P1_1~P1_3からなる帯はNoteFieldよりも奥側に表示され、正しい遠近感が得られます。またやはり全体にFOVがかかっているので、手前は勝手に拡大され、奥は縮小されています。ただし矢印モデルにはFOVがかかっていないので、手動でzoomをかけてそれっぽく動かしています。

また、帯を円柱状にしてあるので、この円柱の背景に楕円型のそれっぽいブラーを平面的に表示させることで勝手に光っているように見えます。円柱自体は光ってないです。円柱以外だと回転に伴ってブラーがずれるので、円ならではの表現です。

f:id:paraphrohn:20200621010231p:plain

そして、このように構成したステージを、全体のActorFrameごと回転させながら、しかしNoteFieldとブラーの画像だけ逆回転をかけて打ち消して画面上回らないようにしながら、半回転させたのちに全体を縮小しながら高速回転させて終了します。

上の画像で背景に大量に表示されていた立方体&三角形については、見ての通り4つの輪っか上にランダムに配置したものを回転させて、かつその輪っかに薄くブラーをテクスチャとして貼った円柱モデルを重ねて光っているように見せかけています。

輪っか4つのうち中央の1つ (輪っか4) 以外はdiffuseで暗めに設定し遠近感を演出、さらに回転軸をz軸方向で180pxだけ手前側に設定することで「手前側はz軸表示限界で表示されず、しかし奥側は表示される」塩梅に調整しています。これが、ステージ全体が回転することで後半は180px奥側に回転軸がズレますので、今度は手前側に輪っか上のオブジェクトがいくつか通過するという表現になります。

こうやって静止画で見ると、帯に付随していたブラーが平面的な画像であることがよくわかりますね。

 

というわけで、ここまでの記述で大体の演出についてどういった挙動をさせればいいのかが分かりました。実は意外にシンプルな技術の組み合わさで全体が構築されているのが分かるかと思います。実際、今の環境でこのluaを書こうと思えば、何も知らない状態からでも多分2~30時間くらいの勉強で書けるんじゃないかと思います。

次回は、これを実際にどうやって実装していったかについて軽く説明したいと思います。いやまあここが絶望的なまでに汚物なんですけど。