いろいろあってShaderShowdownに参加することになっていました。25分で参考資料無しで絵を作るという競技です。
📢📢📢📢📢📢📢📢📢📢📢📢📢📢📢
— Tokyo Demo Fest 2021 (2021/12/11-12) (@TokyoDemoFest) 2021年12月12日
Shader Showdown決勝!!!!!!!!https://t.co/Nw5HakClvl pic.twitter.com/AmnNsIkvsZ
優勝しました。
— phi16 (@phi16_) 2021年12月12日
(リプライツリーにあるshadertoyのリンク先の中に、YouTubeのURLも置いてあります)
素直に嬉しく思います。祝ってくれた方々ほんとうにありがとうございます。
余計な話
昔butadieneさんにShaderShowdownに誘われたことが何度かあった覚えがあるんですが、私は毎度「私は無理」と返していた覚えがあります。
今回も0b5vrさんから話を頂いたときには同様の返しをしていたんですが、「25分の試合やったことある人今回居ないから」と言われ、何故か説得されて参加してしまいました。
騙されたなぁと思いました。
一昨日の日記 に書いてしまったように私には精神的にこの形式が向いてないようで、本当にずっとしんどい気持ちでした。
終わった現在としては一応ありがとうございましたの気持ちが結構あるんですが、まぁ、もうあの精神状態には成りたくないなぁと思ってしまう感じです。
たぶん、向いてる人はいるとおもいます。単に私がそうじゃないだけです。
だから私がこんなにしんどいとか言っていることはそんなに自分のことかと感情移入する必要は無いと思います。いろんな人がいます。
そのうち普通に4kとか出したいとは思っています。
Quarterfinal
まずレイマーチは一切しないことを前提にしました。ただの逆張りですが、単に私はあんまりレイマーチが得意ではないという理由もあります。
作るものを考えるにあたって、最初は全然違うものを考えていたんですが、発展性とかディティールとか、何もかもが足りなかったのでやめました。
そのときに思ったことは「遠近感があると解像感が変わるのでディティールが出る = 3Dの強さ」です (これはそれ故に出てきた文章です)。だから「どうオーソドックスではない方法で3Dをやるか」が問題でした。
とりあえずレイトレ的にQuadを出して (だから quad
って名前なんです) 飛ばしたり曲げたりしてみたはいいものの、あんまりおもしろくありませんでした。
そこで色々悩んでギリギリ (試合の8時間前です) 出てきたのが、Quadの大きさを無限にしてしまって、その表面での色付けを使って遊ぶという部分です。
遮蔽してしまうとディティールがもったいないので加算合成にして、各点での色付けを3D空間ベースで行うことで一貫した絵になるようにしました。
というところでやっと「これはvolumetric renderingもどきを目指している」ことに気づきました。
解釈が定まったので出来ることがわかるようになりました。つまりvolumetric的に映えるdistance fieldを作れば良いということです。
なので乱雑にキューブをいっぱい散らして、modで増やして、ごちゃごちゃしてくるのでメリハリとして中央からキューブを引きます (文字通りね)。
だいぶ締まった感じになったので、やっとこれでなんとかなりそうだな、と思いました。これが試合開始1時間前でした。
あとは自分の行動をリプレイするだけです。
今回、最終的な絵はそこまで劇的なものではないので、そこまでの過程で勝負する必要があると感じました。
最初は2Dの振りをして。板を回すことで発展性を提示して。やわらかい感じから輪郭入れてディティール出して、球からキューブに変えて変化を見せて、だんだんと硬い雰囲気に。あとはまぁそれこそVJみたいにシーンを変えてみる (パラメータ変えると結構変わりますからね)、という感じで。
twitch側の方で「real "performance"」と言及していただけたのは嬉しかったですね。
なんとかなってよかったです、わりと良い勝負できた感じもしましたし…。願わくば完璧な状態の0b5vrさんのシェーダと並びたかったですね。
Semifinal
正直もう考えてられるかという気持ちでしたが、可能性がある以上考えるしかありません (実際そうなったわけですが)。
なんか根本的に「作りたいもの」ないかなぁ~と考えていたんですが、1つ思いつきがありました。
えー。曲が普通に好きなんですが、MVも好きです。
ひたすら世界をぐるぐる飛び回るだけ、ではなく時々「世界が異常な繋がりをする」んですよね。こういうのすき。
これをやるか、とまず考えましたが地形が大変です。と、同時にvoxel traversalやってもいいな~と思っていたので、voxelで地形作るか、ということを考えました。
レイマーチと違ってディティールの最小単位が決まっているので、あんまり細かく作り込まなくても大丈夫だろう、という思惑です。
が、私には自然を作る能力がありませんでした。
仕方ないので適当に削って洞窟っぽいのを作ったはいいものの、ここから空間ワープみたいなことを作らなきゃいけないのか…と考えると25分でやる内容ではありません。そうだね。
やめました。
代わりにカメラワークをちゃんとやる、ということを思って、Bezierっぽいイメージで適当に曲線に載せてみたところ、めちゃ良感があったので、これでいっちゃえとなりました。
寝る前ちゃんの曲があてられるということだったので、そのまま疾走感とビート感強め。
これに合わせる形で、ポイントライトと影でぱきっとさせて、後は 𝑚𝑜𝑡𝑖𝑜𝑛 𝑏𝑙𝑢𝑟 と画面全体のdistortion。
最終的な絵にめちゃ満足できたので自分の中でもすごく良かったです。
本番でのリプレイですが、前回とは違って「途中で絵を出しにくい」という問題があります。ポイントライトを置くにはカメラワークと地形が必要で、どうしても順序があります。
なのでもうそこは諦めて、完全に最終形での勝負と考えました。
代わりに離れ業っぽいことは一切やらずに着実に。さっとvoxel書いて、AO (これを参考にしました) 載せて、カメラ動かして、シーン作って、ライティングして、エフェクト掛けて。わかりやすいですね。
カメラの動きを直線ベースから曲線に変化させる、ということも考えたんですが、寝る前ちゃんの曲はずっと華やかなので、最後にぐっと入れるよりも早い内に良い動きにしておきたいという気持ちもありました。
こちらも惜しくもsp4ghetさんの方がバグっていたのが残念です…。
Final
今度こそ考える余裕がありません。
1戦目と2戦目を組み合わせて「voxel上でvolumetric rendering」とかも考えたんですが、ディティールの出し方がめちゃくちゃ難しいと思いました。炎のシミュレーションとか出来たらまた違うんでしょうけど。
どうしようもなかったので0b5vrさんのシェーダを眺めていたんですが……これやるか、と思い立って。
今から新しいテクニック (quad tree traversal) やるのはしんどいので、今持っているvoxel用のコードをそのまま、ライティング側で魅せる方向を考えました。
まぁ、こう、感謝の気持ちと、惜しかった1戦目を連れてくるような気持ちで、文脈的にもいいかなって思った。最終戦なのでそこまで気張らなくてもいいかな、というのもありました。
で。
quad treeはそれそのものがかっこいいのでかっこいいんですが、私はそれに見合うものを代わりに連れてこなくてはなりません。
ランダムで作れる地形はやっぱりランダムで作れる地形でしかないので、こう、なんか、変なものが欲しくって。
ライフゲームやるか、となりました。シミュレーション系は強いのよ。実在度が。
元々は3Dのcell automataで良いのがあったらいいなぁと思っていたんですが、求めているような感じのルールは無いっぽくて。
ならまぁ2Dのいつものを引き延ばせばいいかと。
で、光源と金属をどう分けるかが問題だったんですが、よくある「数F前まで生きていたことを覚えておく」やり方、わんちゃんいけるのではと思ったら、いけました。
「さっきまで生きていたセル」のほうが「今生きているセル」よりも少なかったので、そちらを光源に。生きているセルを金属に。
めちゃいい感じになった。
ブロックが純粋な金属柱に、ブリンカーが眩しい柱になるので、シーンの情報量的に激良いんですよね。そこまで予測はしてなかったです。
あと最初はふわふわしてたんだけどなんとなく地面を置いてみたら激良になった (GIがね、綺麗なのよね) し、気分で色を乗せてみたらこれもいい感じになったし (0b5vrさん感は減りましたね、私らしくはあるんでしょう)。
あと毎フレーム動かすと目に悪いな~と思ったけどカウンタわざわざ作るのもな~とか思ってたんですが、シンプルに時間ベース (fract(t) < 0.5
) でシミュレーション止めるようにしたら思いの外ハマったので良し、となって。
なんとかなりそうで安心しました。
さて、リプレイ戦略ですが、今回は完全にトリッキーが1つ居ます。
こっそり作ることも出来たとは思うんですが、まぁ敢えて完全に分けて堂々と仕込みを見せるのも (安全性的にも) 良いだろう、と思って、ああなりました。
試作時では最後にライティングを入れたんですが、予めちゃんと入れといて、「唐突に全然違うことをやり始めた感」そして「これまでの2つが噛み合った瞬間」を出したほうが良さそうで。
どうやらなんかめちゃ反応いただけていたようで本当に良かったです。組み合わせたタイミングも結構良い感じに見せられたっぽかったですね。うれしい。
個人的には仕込みが終わったときに堂々とシーンを元に戻すのがわざとらしくて好きです。
最終的に出来たものはちゃんと「それらしい」ものになったと思うし、Kamoshikaさんと本当に良い勝負だったようなので、良い試合が出来たなという満足感がすごいです。
というわけで。以上、何をしようとしていたのか、についての解説でした。
実況、何度も見返していてすごい楽しませて頂いてます。本当にみなさんありがとうございました。
コーディングについて
以上を、ちゃんと、時間内に、間違えないように、色々と検証と書き方は考えていました。
まず根本的に3作品どれも予めほぼ完成形は前以て作っています。
ちょっとずつ違うんですけど、でも見ての通り2戦目と3戦目はもうほぼ同じです。
色々と思っていたことはありまして。
- 段階的にチェックする
- 間違えそうなところを認識する
- 微分したときの符号とか
- プラスマイナス関係ないなっていうところは、それはそれで「関係ない」ことを覚える (後述の「迷わない」に繋がる)
- これについては「やっていることを正しく理解する」ことが何よりも便利かなと思います、検証もできるし
- カプセルのSDFの
length(pa-h*ba)
とか、パーティクルのdistance(pl, o+dot(pl-o,d)*d)
とか - voxel traversalの
r += d*length(l*m) - m
とか - 私は元々数学ベースで考えるタイプなのでそのへんも功を奏していますね…
- カプセルのSDFの
- コードを単純にする (短くなるし、間違えにくくなる)
- 正しくなくても要らなそうなところは省く (ray direction の normalize とか)
- 実際に抜いて問題ないなと思ったら消してます
- 円周率は3
- コピペをすることを前提として覚えておく (脳内圧縮する)
- x,y,z,w の順番で現れるように (覚えやすいように) 並び替えたりする
- 正しくなくても要らなそうなところは省く (ray direction の normalize とか)
- 迷わない (速度を維持する、書き続ける)
- 変数名は全部もう固定しておく、被りそうな命名をしそうならそれも把握して予め避ける
- ループの回数、大きさの範囲、そのへんの数値調整パラメータも覚える
- 関数の最初にfor文の前に何行あったか覚えておく
- 座標系は必ず +X Right, +Y Up, +Z Forward で固定する (頭がそうなってしまったので)
- 記述する処理の順番を覚えておく、「いつ終わるか」「どこから始めるか」も覚える
- フレキシブルに出来る場合はそれはそれとして覚えておく (エフェクト系はいつでも良い)
- 「こっちのほうがおもしろいかな」みたいな邪念は全部前段階で消化しておく
あとはタイプ速度の問題ですが、入力するものが全て頭に入っている場合は通常のタイピングよりも余程早く打てるんではないかなと思います。
ちなみに練習だと27分とかで怪しいな~というところで、おかげで適切に急げて間に合ったのかなと思います。時間感覚がわかるのも大事ね…。
で、私が今回やらかしたミスですが。
まず2戦目、m = step(l,l.yzx) * step(l,l.zxy)
を m = step(l.yzx, l.zxy)
って書きました。これは覚えすぎたことによる弊害で、覚えるべき場所だけが頭にあった結果、当たり前のことが抜けているケースです。
ちなみにこれは l.xyz
のうち最も小さい軸の値が1、そうでない軸の値が0であるようなベクトルを作る計算で、これを参考にしました (75行目)。
普通によく見たらどう見ても違うので直せました。冷静になるのが大事…。
3戦目の最初にミスったのはvoxel traversalの中心からのオフセット o-u-0.5
を何故か o-d-0.5
って書いていたせいで、多分目が滑ったんだと思います。
さすがにびびりましたがなんかこんなところに d
あったっけなぁ…って思えたので気づけました。そういう「文字がどこにあるか」みたいな感覚は (ずるいですが) 便利ですね…。
あとライフゲームの前フレームサンプル位置をミスったのは cd.xy %= 64
を入れ忘れていたからで、これは誤字では無いので処理が正しいかどうかを丁寧に見るしかなかったです。
当たり前のように動くと思われるコードが変な結果になるので、入力 (cd
) がおかしいんかな?って思ったら値の範囲を縛る行が無かったので気づきました。
バグるとマジで焦るんですが、「私のコードはちゃんと動いていた」という自信は、めちゃくちゃ安心に繋がっていたと思います。
(ちなみに、書き込む方は直したんですが読み出す方が直っていなくて、終了後に「微妙にバグらせてる」と言ったのはそれを指しています / shadertoyに移植したら動かなかったのでちゃんと直しました)
正直なところShaderShowdownとしては「完全記憶」は邪道だと思います。正直。
でも私は「途中で頭が空っぽになって何もできなくなる」ことの方が怖かったのです。テストで書いてると大体そうなんですもの。
まぁ当然何もルールには抵触していないわけで、ギリギリを攻めて出来る限りのことをしようとした、という態度として許してほしい気持ち、です。
参考になるかはわかりませんが、これで頭の中をほとんど出しました。
みえてきたもの
昔から、Showdownに誘われる度に「私ならどんな絵を出すんだろう」と気になっていたことはありました。
こういう場で「吐き出すもの」っていうのはどうやってもその人の性格が出るわけで。私は自分がどんな存在に視えるのか知りたかったのです。
そして今回、実際それが (不幸中の幸いとして) 出来て。あの3枚は、「私」なのですね。
きっと他の人は作らなくて、3枚とも全然違うんだけどどことなく見えない共通点がある、この感じが私なのです。きっと。
それはワールドでもそうで、色々作る度に「私は私を客観視できるようになっていく」のを感じています。
ただ今回は顕著で、「テーマ無しで3つ、同一手法(GLSL)」なので本当に純度高く私を観察できているのです。それがすごく嬉しい。
これは当然「私がつくるものがわかったので、これからも作れる」という話では一切ございませんが、今後の何かの指標には成りうるのかな、と思っています。
そして。
今回、奇しくも SANRIO Virtual Fes と同日となってしまったわけで、たくさんの知り合いがとても大変なことになっているのを眺めている私です。
私は本当に一切関与してない (GC用に前に作ったものが流用されたりはしてますが) ので、それ単体に関する気持ちとしてはわりと「しんどい」です。
ただ今回、私は私で何か出せたというのは「具体的な救い」だとは思います。なのでこう、これだけだと良い話ではないんですが。
…割と上に書いた「私を認識した」という話は結構大きくて。
私は、やっぱり他人が作るようなものが作れないという自覚があります。本当に。
Bonzomaticのデフォルトを一番最初に消している理由はそれです。自分の書いている内容に、自分以外の存在が含まれていることがあまりにも許せないのです。非効率的だとしても。
そして中途半端なところでやめることができないのもそれで。他の人が期待していようがいまいが、きっと私が一番私に期待しているのです。だから私は自分に応えなければならない。
その結果として以上に書いた諸々の長い考えに繋がるわけですが、マジで気持ち悪いと思う。
世の中にあるチュートリアルを素直に実行することが出来ないし、人の助言は自分の言葉に置き換えないと受け入れられないし、意味もわからないで誰かの式を使うことも許せない。
それが良い方向に働いていることもあれば、悪い方向に働いていることももちろんあって。
困るなぁ、とは思うんですが、でも結局私はその通りに進むしか無いのです。
ね。
…というわけで、私は、他の人がすごいことに関する諦めが、そうしたくはなくても、必然的に発生してしまうのです。
この私は多少特殊ケースだとは思うのですが、ここまでではなくても、「結局自分が在るように在るしかない」という結論は持ちうるものだと思います。
今回、いろんなしんどさが振りまかれたとは思いますが、私はもう段階的に歩いていくことしかできません。それで自分が満足できれば良いのかなとは思います。
趣味だからね。人生も。
自分に刺さる曲がつくれるようになりたいですね。
良い曲です。
歌詞のある曲が理解できなくて、無い方がすっと入ってくるというのは、なんとも面白いところです。音楽は面白いですね。
はい。
では。長い感想文でした。今度こそみなさまお疲れさまでした。
あとね、全ての人がごちゃまぜに存在できているこのVRChatがだいすきなのよ。