World3Dで描き分ける Godot
Godotエンジン、レイヤーを使わず複数のカメラを使う話。
World3D
World3Dってリソースありますよね。内部にEnvironmentリソースと、CameraAttributeリソースを保持できます。Environmentは背景や環境光、CameraAttributeは露光やDoFに関するパラメータを持っていて、どちらも描画に関する設定です。
World3DはViewportノードにセットすることができます。world_3dプロパティです。これによって、そのViewportの描画先(派生クラスがWindowの場合は画面、SubViewportの場合はテクスチャ)の背景や環境光、露光が変わります。
でもね、Viewport.world_3dプロパティの役割、これだけではないみたいです。
レンダーレイヤー
ところでGodotにはレンダーレイヤーという機能があります。カメラ、光源、物体(VisualInstance3D派生クラス)の各ノードにレイヤーのマスク値を設定することができて、「写す/写る」「照らす/照らされる」の関係をコントロールするためにあります。同じ部屋にあるけど別々のライトで照らしたい、とか、複数のカメラで別々の物を写して、その結果をGUIに表示したい、とか。そういうことができます。
こういった「照らし分け」「写し分け」は、レンダーレイヤーのマスク値を別々に設定しないと、実現できない。かと思いきや、そうではないようです。
Viewport.world_3d
さて、Viewport.world_3dプロパティにWorld3Dプロパティが設定されていると、そのViewportの子孫ノードは、このWorld3Dに登録(register)されることになるそうです。
この状況は、Node3D .get_world_3d()関数で取得することができます。
そしてどうやら、別々のWorld3Dに登録されると、別々に照らされるし、別々に写されるようなのです。同じレンダーレイヤーであっても。
ええ~~~そうだったの!?
(知ってた!?)
ほぼ同じ座標にある、形状の違う4つのメッシュが、それぞれ色の違うライトで照らされ、別々のカメラに写っている様子↓
World3Dを使うと、複数のカメラで描画する状況が楽に作れそうです。
例えばキャラクター選択画面で、各キャラの動くポートレートが並んでるような状況。Subviewportでテクスチャに描画して、それをTextureRectノードでUIに張り付けるということをすると思います。このとき、レンダーレイヤーで写しわけると、別々のマスク値を設定しなければなりません。他のUIでもレンダーレイヤーを使っているなら、値がかぶらないように処理する必要もあります。さらに、この方法では表示できるのは20キャラが限界です。ユーザーにはレイヤーが20種類しか解放されてないからです。
SubViewport
Camera <- レイヤーA
Light <- レイヤーA
Character <- レイヤーA
SubViewport
Camera <- レイヤーB
Light <- レイヤーB
Character <- レイヤーB
でも、SubviewportにWorld3Dを設定すれば、レイヤーの設定は不要です。他のUIとの兼ね合いを考えなくていいし、一度に表示できる数の限界も多分ありません。素直!
SubViewport <- World3D A
Camera
Light
Character
SubViewport <- World3D B
Camera
Light
Character
World3Dは文字通り、世界を表しているんだと思います。Subviewportに写すものが別々の場所にある場合は、レイヤーで分けるのではなく、World3Dで分けるのが、Godot流な気がします。
そ、そんな役割があったのか、World3D。知らなかった~~。
以上です~~