2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Godot Engineで複数のカメラを重ねて表示する

Last updated at Posted at 2024-10-22

はじめに

自分が開発しているVRMViewMeisterでも使用している機能なのだが、Unityではカメラコンポーネントに深度とカリングマスクが備わっており、それによってカメラの映し出す映像の優先度をつけて重ねて表示できたりする。
(URPだとカメラはレンダータイプとスタック機能で同じことができる)

ではGodotで同じことをしたいと思ったときどうすればいいのか。調べてもドンピシャなテクニックが見つからなかった。
というわけで公式マニュアルを見て試した結果を今回紹介したい。

Unityでは

たとえばVRMViewMeisterではカメラを次のように構成して映像を表示している。

名前 深度 カリングマスク
FrontMainCamera 10 Default,Player,Stage
SubCamera 50 UserUI
IKHandleCamera 70 Handle,SubPlayer
Main Camera 99 TransparentFX,Ignore Raycast,...,UI

※全てを同時に使っているわけではない。

image.png

VRMViewMeisterで表現したかったのは、下図のような3DモデルのIKを動かすのに、IKの操作ハンドル用の図形を常に全面で表示したかったのだ。

image.png

URP環境では

Main Cameraをレンダータイプ=基本にし、それ以外をオーバーレイにして次のように構成した。

image.png

URP環境でもこのカメラをすべて活用しているわけではない。

Unityでの実現方法

Builtin RP
深度とカリングマスクを適切に使い分ける
Universal RP
レンダータイプとカリングマスク、スタックを使い分ける

至極簡単だ。(管理の仕方によってはすごく大変だろうが)

Godot では

じゃあGodotで同じことを実現したいと思ったときどうすればいいのか。
GodotにもCamera3Dというノードがある。同じことができれば一番スマートなのだろうが、Camera3Dでは似たプロパティは Cull Mask しかなさそうだ。

image.png

それにCamera3Dを複数追加しても、そのままではそれぞれのカメラの映像を活用できない。

実現方法

結論から言うと、次の3つを使うことでだいたい同じことをできることがわかった。

  • Camera3D
  • SubViewport
  • SubViewportContainer

公式マニュアルでは次のページだ。

Viewport
Using Viewports

サンプルの図形

ゲーム中に使う3Dノードは、普通にルートノードの任意の場所に追加していってよい。

シリンダー

image.png

VisualInstance3Dの Layers を1にした。

球体

image.png

VisualInstance3Dの Layers を2にした。

なおかつ、優先度別に重ねて表示したのがわかるように、あえてシリンダーの内部に埋もれて見えなくなるように配置した。

期待値
球体がシリンダーに埋もれて隠れることなく、表示されること

SubViewportContainerを追加する

映像を重ねたい Cull Mask のまとまりの分、Camera3Dを用意すると思いきや、ただそのままルートノードに追加しても意味がない。
最初にするのは、 SubViewportContainer をシーンに追加することだ。

SubViewportContainer はControlノードの派生なので、こんな感じで配置する。

image.png

Control
->SubViewportContainer

Controlのプロパティは次のとおりにする。

Layout:
  Anchors Preset: Rect全面
  Transform:
    Size: 
      x: [指定の値]
      y: [指定の値]
  Container Sizing:
    Horizontal: 塗りつぶし
      拡大: オン
    Vertical: 塗りつぶし
      拡大: オン

SubViewportContainerのプロパティは次の通りにする。

Layout:
  Anchors Preset: Rect全面
  Transform:
    Size: 
      x: [指定の値]
      y: [指定の値]

ポイントとなるのはこれらのプロパティだ。ControlとSubViewportContainer、それぞれのLayoutグループのTransformのSizeにて、目的とするビューポートのサイズを設定する。

そしてアンカープリセットは Rect全面 にすることによって、描画を全面に塗りつぶして表示させる。
そうしないとカメラ映像はUI周りに影響されて極端に小さかったりずれたりすることになる。

この段階ではこのような表示になる。

image.png

当然何も映らない。

必要な数のCamera3DとSubViewportを用意する

器が用意できたので実際に必要なCamera3DとSubViewportを SubViewportContainer の子ノードとして追加していく。

image.png

ポイント
Unityの深度やスタックのように、目的の順番通りにSubViewportとCamera3Dのセットを追加してく必要がある。
つまり、 一番下に描画したいカメラ映像を1番目 に追加し、以後は順に追加していく。

1番目のSubViewportとCamera3D

SubViewportのプロパティは次の通り。

Size: ※Control・SubViewportContainerと同じ値
Viewport:
  Transparent BG: オフ

Camera3Dのプロパティは次の通り。

Cull Mask: ※目的に応じてオン・オフする
Current: オン

この段階ではこのような表示になる。

image.png

見るべきポイントはプロパティ内のプレビュー表示だ。ちゃんとCamera3Dで設定した Cull Mask の通りに3Dモデルや他のノードが表示されていること。

2番目以降のSubViewportとCamera3D

SubViewportのプロパティは次の通り。

Size: ※Control・SubViewportContainerと同じ値
Viewport:
  Transparent BG: オン

Camera3Dのプロパティは次の通り。

Cull Mask: ※目的に応じてオン・オフする
Current: オン

この段階でこのような表示になる。

image.png

ポイント

  • 2番目以降のSubViewportでポイントなのは、 Transparent BGオン にすること
  • SubViewportの プレビュー表示 で、対象の Cull Mask だけの映像になっていること

これがもし Transparent BGオフ だとこうなってしまう。

image.png

シーンの画面にも2番目のCamera3Dの映像しか映らないことになる。

これがUnityでいうところの 深度のみ や背景タイプの効果に相当する。

プロジェクトの設定

忘れてはならないのがプロジェクトの設定だ。

一般:
  表示:
    ウィンドウ:
      ストレッチ:
        モード: viewport
        アスペクト: expand

image.png

するとウィンドウ比率を変えた場合にこうなる。
image.png

設定は モード: disabled, アスペクト: keep でもいいかもしれない。

設定が モード: viewport, アスペクト: ignore だとこうなる。

image.png

設定が モード: viewport, アスペクト: keep だとこうなる。

image.png

このあたりの表示方法は目的に応じて決めたいところだ。

注意点

カメラを動かす

無事映像が重なって表示されるようになったが、注意したいのはカメラが複数になったので、カメラを動かすときはすべて同時に同じ位置に動かさないといけない点だ。

例えばカメラを動かす別の操作用のノードを用意しておき、その子ノードとして RemoteTransform3D を追加し、移動や回転を管理する。

image.png

あとはRemoteTransform3Dの親ノードを動かすようにすれば、すべてのカメラが同時に同じ動き方をするようになる。

特定の優先度のカメラだけ非表示にしたい

このやり方の場合、SubViewportのプロパティを変更すればよい。

Viewport:
  Disable 3D: オン

これでそのSubViewportの3D映像が無効化される。つまり配下のCamera3DのCull Maskで指定された3Dモデルやノードは表示されなくなる。

シーンのツリービューにある 可視性の切り替え をオフにしても効果がないので注意。

image.png

まとめ

  • SubViewportContainerの子ノードとして、SubViewportを必要な数だけ追加する

  • SubViewportの子ノードとして、Camera3Dを追加する

  • SubViewportのプロパティは次のとおりにする

SubViewport Transparent BG
1番目 オフ
2番目 オン
  • カメラを動かす場合は全てのカメラが同じ動きになるように工夫する

終わりに

これでGodotでもUnityで深度別にオブジェクトの表示を分けていたように、優先度別に積み重ねて表示できる。
ただ、個人的にこれでいいのか疑問に思うのは3D映像がUIのノードの配下ベースになってしまう点だ。

3Dのままだったら、デフォルトのビューポートに直接3Dのカメラ映像が描画されていたが、このやり方だとあくまでUIのコントロールのコンテナの表示領域に沿って映した3D映像となる。
まわりくどい気がする。

もしGodotで実はこうすればいいんだよ、とか、こうしたほうがもっとスマートだよなどのご意見や発見があれば教えていただけると助かります。

このやり方でいいのであれば、カメラ映像を重ねることがGodotでもできるようになるので参考にしていただければ幸いだ。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?