😊

自作ゲームエンジンでシェーダーツールを実用レベルまで作った話

に公開

作り始めたきっかけ

シェーダーのツールと聞くと、
シェーダーグラフを思い浮かべる方が多いと思います。
ノードベースで繋いでいくシェーダーグラフは非常に便利ですが、
ノードが増えてくると見た目をきれいに保ち、
全体の流れを把握することが難しいと感じる場面がありました。

そこで、ノードベースとは別のアプローチで
シェーダーを構築できないかと考えたのが、
このツールを作り始めたきっかけです。

設計案1

最初に、シェーダーの1行分をモジュール1つとして考えて
GUI上で並べて構築していく方法で実装しました。

この方法でも構築自体は可能でしたが、
1行単位という粒度が荒すぎてモジュール数が増えてしまい、
その結果、全体の見通しが悪くなり、
どこで何をしているのかが把握しづらくなってしまいます。

例えば、変数に値を代入するだけでも、
変数を作るモジュールと代入するモジュールの
2つが必要になってしまい手間も増えてしまいました。

設計案2

モジュールの問題点を踏まえ、
大きく方針を変えて作り直したのが、
今回作成したシェーダーツールです。

1つ目の問題は見た目のわかりにくさでした。
実際のソースコードに近い形で構築できた方が、
全体の流れを把握しやすいと考えました。

2つ目はモジュールの粒度です。
1行単ではなくて「値」単位でシェーダーを構築できるようにしました。

ツール設計

シェーダーの要素を細かく分解し
「Element」として扱うことにしました。

Elementはツリー構造になっており、
入れ子でElementを持つことができます。

シェーダー1行分もElementとして扱い、
複数のElementの集まりになっています。

例えば、次のような変数宣言して初期値を代入しているコードは、

float4 value = float4(1, 2, 3, 4);

[TypeElement] [NameElement] [OperationElement] [ValueElement]
のように4つのElementから構成されています。

さらにValueElementがfloat4の場合は、
その中に4つのElementを持つ形になります。

このように入れ子構造にすることで、
型や構文が増えても柔軟に対応でき、
拡張性の高い設計にできたと感じてします。

ツール上の見た目はこのようになっています。
コード上をクリックすると、値を変更したりElementを変更したりできます。

メリット

プログラマの視点にはなりますが、
ソースコードベースになったことで、
シェーダー全体の処理内容を把握しやすくなったと感じています。

また、シェーダーのバインドが自動化できる点も、
大きなメリットの1つです。
CPU側と対応関係をツール側で管理できるため、
バインドミスも防ぐことができました。

さらに、システムバリューのように
HLSLであらかじめ決められているセマンティクスについても、
候補から選択できるようにしています。

使用されているセマンティクスは自動で設定されるため、
設定もれや指定ミスを減らせると考えています。

デメリット

正直なところ、慣れている人であれば、
ソースコードを直接書いた方が早いと感じる場面は多いです。

私自身は普段からHLSLを書いているわけではないため、
セマンティクスなどを忘れることがよくあります。
そのため、このツールの制約は
そこまで大きなデメリットには感じていません。

一方で、HLSLをがっつり記述する場合は、
ストレスに感じる可能性はあると思います。

もう一つのデメリットは見た目の問題です。
表示をソースコードをベースにしている都合上、
空白文字をそのまま扱うことができません。

例えば、float4( float3, 1) のような場合でも、
何か文字列を表示しないとクリックして編集できないので、
現状ではfloat4( float3, 1 #Null #Null)
のような表記になってしまい、
可読性が落ちてしまっています。

改良点

基本的な機能は完成してコンパイルすることもできるので、
あとは、使いやすさを中心に、
機能追加や改善を進めていく予定です。

エラー個所を表示する

まず対応したいのが、エラー個所の可視化です。
コンパイル時に発生したエラーの位置を
ツール上で直接表示できるようになれば、
開発効率が大きく上がると考えています。

Elementをドラッグで移動

もう一つはElementをドラッグで移動できる機能です。
現状では、一度作成したElementを
後から移動することができません。

例えば、float4のXに設定したElementを
Yに移動したい場合でも、
一度XのElementを削除して、
Yに同じElementを作って設定しなければいけません。

ドラッグ操作でElementを移動できるようになれば、
試行錯誤もしやすくなり、
全体の操作性も改善できると考えています。

まとめ

まだまだ、改善の余地はありますが、
シェーダーツールとしては満足したものができました。

今後は、このツールを実際の開発で使いながら、
アップデートしていけたらなと思っています。

同じようにエンジニア向けのシェーダーツールを検討している方の
参考になれば幸いです。

Discussion