Godot VR開発メモ
最終更新日:2026年09月26日記事作成日:2021年09月26日
オープンソースのゲームエンジンGodotでVR開発をする方法をメモする場所です。
更新履歴
(2026年9月26日)Godot 4.7.2でMeta Quest 3向けMRアプリを制作した内容を反映
(2023年10月9日)Godot 4.1.2でWindowsとMeta Questのエクスポートを再確認
(2023年4月23日)Godot XR TemplateがGodot 4ベースになったのを反映
(2023年1月31日)「Godot XR update - January 2023」の内容を一部反映
(2022年12月10日)Godot 4 beta 8でWebXRが動作するようになったのを反映
(2022年11月8日)Godot XR Toolsのチュートリアル動画を紹介、最低限の使い方をメモ
GodotのXR対応の概要
GodotはXRに標準で対応しており、エンジン本体にOpenXRモジュールとWebXRモジュールが組み込まれています。また、左右両眼をまとめて描画するMultiviewレンダリングに対応しています。
Godot 4.7現在、WindowsのOpenXR対応ヘッドセット(Quest LinkやSteam VR)のほか、Meta Quest、PICO、Android XR(Galaxy XR)などのAndroidベースのヘッドセット向けにエクスポートできます。Android向けのベンダー固有機能はGodot OpenXR Vendors pluginで提供されています。
ドキュメントのこのあたりにXR関連機能の解説やチュートリアルがまとまっています。
上のスクリーンショットに示すように、シーンにXROrigin3D、XRCamera3D、XRController3Dノードでカメラとモーションコントローラーのリグを組み、スクリプトのXRServer.find_interfaceでモジュールをロードし、get_viewport().use_xr = trueでビューポートのVR描画を有効にするのが概ね共通する手順になります。
プラットフォームごとのセットアップ方法
Windows(OpenXR)
Oculus LinkやSteam VRで動作するアプリを作る方法は以下の通りです(概略)。
- プロジェクトの設定
- シェーダーを立体視対応にする
- Project Settings > XR > Shaders > Enabledをオンにする
- OpenXRモジュールを有効にする
- Project Settings > XR > OpenXR > Enabledをオンにする
- 右下のSave & RestartでGodotを再起動
- シェーダーを立体視対応にする
- カメラリグを作成する
- 3D Sceneを作成しXROrigin3Dノードを追加
- XROrigin3Dの子にXRCamera3Dノードを追加
- XROrigin3Dの子にXRController3Dノードを2つ追加、InspectorでTrackerをそれぞれleft_handとright_handに設定
- シーンにOpenXRのインターフェース取得とVRモード有効化のスクリプトを書く(下記)
func _ready():
var xr_interface : XRInterface = XRServer.find_interface("OpenXR")
if xr_interface and xr_interface.is_initialized():
get_viewport().use_xr = true
再生ボタンを押すとVRモードで実行されます。
Meta Quest(OpenXR)
Meta QuestアプリはAndroidアプリとしてエクスポートします。
Android開発環境の準備
まず、通常のAndroidエクスポートができるようにします。JDK 17とAndroid SDKを用意して、Editor SettingsのExport > AndroidでJava SDK PathとAndroid SDK Pathを設定します。Godot 4.7での手順は「Godotメモ」にまとめています。
プロジェクトの設定
上のWindows(OpenXR)と同じく、XR > Shaders > EnabledとXR > OpenXR > Enabledをオンにします。Androidへのエクスポートに必要なImport ETC2 ASTCもオンになっているか確認します(「Godotメモ」参照)。
Android Build Templateのインストール
Project > Install Android Build Template…を実行します。プロジェクト内にandroid/build/フォルダができ、Gradleプロジェクトが展開されます。
GodotのAndroidエクスポートには2つの方式があります。
- ビルド済みAPKの詰め替え(Gradleなし): エクスポートテンプレートのAPKにゲームデータ(.pck)を入れて署名し直すだけの方式です。コンパイルしないので速いのですが、AndroidプラグインのAARを組み込めません
- Gradleビルド: 展開したGradleプロジェクトでビルドする方式です。AndroidプラグインのAARをリンクし、プラグインのAndroidManifestをアプリのマニフェストにマージできます
OpenXR Vendors pluginは、ベンダーごとのAAR(Meta向けはgodotopenxr-meta-*.aar)に対応デバイスやパーミッションのマニフェストを持っています。これをマージするために、Gradleビルドが必須です。
なお、android/build/libs/にあるgodot-lib.template_release.aarがエンジン本体です。中身はほぼlibgodot_android.so(C++のエンジン)です。
Godot OpenXR Vendors pluginのインストール
Meta Questなどのベンダー固有の機能(パススルー、ハンドトラッキング、Meta向けマニフェストなど)はGodot OpenXR Vendors pluginで提供されています(以前の「Godot XR Android OpenXR Loaders」の後継です)。
エディタのAsset Storeタブで「OpenXR vendors」を検索してインストールします。見つからないときやバージョンが古い場合は、GitHubのリリースからzipを入手し、中のgodotopenxrvendorsフォルダをプロジェクトのaddons/に置きます。GDExtensionなので、Pluginsの画面で有効にする必要はありません。ただし、読み込ませるためにエディタを一度再起動します。
プラグイン一式は全アーキテクチャ分のバイナリを含むため、80MB強あります。とはいえ最大のファイルでも数MBなので、Git LFSを使わずに普通にコミットしても問題ありませんでした。
エクスポートプリセットの作成
Project > Export…でAndroidのプリセットを追加し、以下を設定します。
- Runnableをオン(ワンクリックデプロイの対象にする)
- Gradle Build > Use Gradle Buildをオン
- Architecturesはarm64-v8aだけをオン(Questは64bit ARMなので、他を外すとAPKが小さくなります)
- XR Features > XR ModeをOpenXRに
- XR Features > Enable Meta Pluginをオン
パススルーやハンドトラッキングなどの使用宣言は、Meta XR Featuresの項目で設定します。
実機で実行する
QuestをUSBで接続し、エディタ右上のRemote Deployボタン(Androidアイコン)を押すと、ビルド・インストール・起動まで行われます。初回はGradleやその依存ライブラリのダウンロードがあるので時間がかかりますが、2回目以降は速くなります。
レンダラーの選択
Questなどのスタンドアロン機でも、Mobileレンダラー(Vulkan)を使うのがよさそうです。Setting up XRでは、Meta Quest 3のようなスタンドアロン機でもMobileレンダラーが推奨されています。
Mobileレンダラーではこれまで、Quest実機での不具合がたびたび報告されてきました(#115924、#112988など。どちらも修正済み)。今回はMobileレンダラーで制作し、Quest 3でパススルーを含めて問題なく動作しました。
フォービエイテッドレンダリング
視野の周辺部の解像度を下げて負荷を減らす機能です。プロジェクト設定のXR > OpenXR > Foveation LevelとFoveation Dynamicで設定します。CompatibilityレンダラーではこれだけでOKですが、MobileとForward+では、さらにViewportのvrs_modeをVRS_XRにする必要があります。グローやDOFなどのポストエフェクトを使うと無効になります。
Godot 4.7では、Vulkanのsubsampled images(VK_EXT_fragment_density_map2)を使うxr/openxr/foveation_with_subsampled_imagesが追加されました(#116220)。Quest 3で1フレームあたり約0.75ms短縮したと報告されています。
ブラウザ(WebXR)
WebXRで動作させるには、上のWindows(OpenXR)向けのセットアップ項目に加えて以下を行います。
WebXR用の初期化スクリプトを追加する
「ブラウザがWebXR Device APIをサポートしているか調べ、VRモードのボタンを押すとWebXRのセッションを開始する」スクリプトを用意する必要があります。
WebXRInterfaceクラスのページに必要最小限のスクリプトが掲載されていますので、ルートNodeのスクリプトをこちらに置き換えます。
VRボタンを作成する
ブラウザでVRモードに入るためのボタンを作ります。ルートのNodeの子にButtonノードを作成し、Buttonのサイズを適当に設定して、Textに適当に「Enter VR」と入力します。
プロジェクトのエクスポート
作成したシーンを保存して、右クリックのSet As Main Sceneでメインシーンに設定します。Project > Export…でAdd…でWebを追加してExport Projectします。
ローカルHTTPSサーバーでホストする
WebXR Device APIはHTTPSサーバーでなければ動作しません。エディタからブラウザで実行するには、Editor > Editor Settings…のExport > WebでUse Sslをオンにしておきます(ブラウザが開いたときに警告が出ますが無視してアクセスします)。
また、ローカルHTTPSサーバーを簡単に立てるにはBrowsersyncが便利です。
ブラウザで実行する
表示されたURLをブラウザで開きます。Questのブラウザで開く場合は、アドレスバーに「https://192.168..:1000/」とhttpsから全部入力する必要があります。「Enter VR」ボタンをクリックすると、上手くいけばVRモードに切り替わるはずです。
OpenXRとWebXRの両方に対応するには
ひとつのプロジェクトでOpenXRとWebXRの両方に対応させたい場合、初期化処理をOS.has_featureで分岐させればできそうです。
func _ready():
if OS.has_feature("web"):
webxr_interface = XRServer.find_interface("WebXR")
else:
xr_interface = XRServer.find_interface("OpenXR")
パススルー(MR)
Godot 4.7では、OpenXR標準の環境ブレンドモード(Environment Blend Mode)でパススルーを扱います。Meta Questでは、OpenXR Vendors pluginでパススルー拡張を有効にしたうえで、ブレンドモードをAlpha Blendにします。
プロジェクト設定(右上のAdvanced Settingsをオンにすると表示されます)で以下を設定します。
- XR > OpenXR > Extensions > Meta > Passthroughをオン(OpenXR Vendors pluginが追加する設定)
- XR > OpenXR > Environment Blend ModeをAlpha Blendに(起動直後のローディング中からパススルーになります)
エクスポートプリセットのMeta XR Features > Passthroughでもパススルーの使用を宣言しておきます。
実行時には、ビューポートの背景を透明にして、ブレンドモードをAlpha Blendにします。背景色のアルファが0のピクセルから現実の映像が見えます。
extends Node3D
var xr_interface: XRInterface
@onready var world_environment: WorldEnvironment = $WorldEnvironment
func _ready() -> void:
xr_interface = XRServer.find_interface("OpenXR")
if xr_interface and xr_interface.is_initialized():
get_viewport().use_xr = true
_enable_passthrough(true)
func _enable_passthrough(enable: bool) -> void:
var supported := xr_interface.get_supported_environment_blend_modes()
if enable and supported.has(XRInterface.XR_ENV_BLEND_MODE_ALPHA_BLEND):
get_viewport().transparent_bg = true
world_environment.environment.background_mode = Environment.BG_COLOR
world_environment.environment.background_color = Color(0.0, 0.0, 0.0, 0.0)
xr_interface.environment_blend_mode = XRInterface.XR_ENV_BLEND_MODE_ALPHA_BLEND
else:
get_viewport().transparent_bg = false
world_environment.environment.background_mode = Environment.BG_SKY
xr_interface.environment_blend_mode = XRInterface.XR_ENV_BLEND_MODE_OPAQUE
Quest 3ではget_supported_environment_blend_modes()が[0, 2](OPAQUEとALPHA_BLEND)を返しました。対応していない環境ではOPAQUEに戻して、通常のVRとして動くようにしています。
MRコンテンツを現実の場所に合わせるには
現実の場所に合わせてコンテンツを置く場合、XROrigin3Dは動かさず、コンテンツをまとめた親ノード(ここではStage)を体験者の位置と向きに合わせる方法が簡単です。
体験者に決められた位置で決められた方向を向いてもらい、スタッフがボタンを押したときのヘッドセットの位置とyaw(水平方向の向き)をStageに設定します。ピッチとロールは使いません。
func calibrate() -> void:
var cam_t := camera.global_transform
var fwd := -cam_t.basis.z
fwd.y = 0.0
fwd = fwd.normalized()
var yaw := atan2(-fwd.x, -fwd.z)
stage.global_transform = Transform3D(Basis(Vector3.UP, yaw), Vector3(cam_t.origin.x, 0.0, cam_t.origin.z))
体験者がQuestのボタンで視点をリセット(リセンター)すると位置がずれるので、OpenXRインターフェースのpose_recenteredシグナルを受けて、スタッフに再キャリブレーションを促すようにしておきます。
Godot XR Toolsについて
Godot XR Toolsという標準ツールキットが開発されていて、テレポート、移動・ターン、物を持つ・投げる、UIを操作する、酔い抑制のため視界を狭くする等の基本機能が入っています。UnityのXR Interaction Toolkitに相当します。
リポジトリはGodot XR Toolsで、ドキュメントサイトがこちらにあります。
さらに、テンプレートプロジェクトがあります。
Godot XR Toolsの使用方法(概略)は以下の通りです。
まず、Project Settings > PluginsでGodot XR ToolsのEnableをオンにします。
XRCamera3Dにvr_common_shader_cacheシーンをアタッチします。これによりシーン開始時にシェーダーをコンパイルして、実行中にカクつきが起こらないようにします。
左右のXRController3Dにleft_hand / right_handシーンをアタッチします。これにより手が表示されます。トリガーやグリップで手の形が変わります。物理に干渉するleft_physics_hand / right_physics_handシーンも用意されています。
XROrigin3Dにplayer_bodyシーンをアタッチして、左右のXRController3Dに以下の機能のシーンを任意にアタッチしていきます。
movement_direct
スティックを倒すと前後に移動します。Strafeをオンにすると左右にも移動できるようになります。Max Speedで速度を調整します。
movement_turn
スティック左右でターンします。デフォルトではVR酔い防止のため一定角度ずつターンします。Step Turn Angleでターンの角度を設定できます。
以下φ(..)メモメモ中
Tips
トラッキング基準位置を切り替えるには
ルームスケールと着座を切り替えたい場合、Project Settings > General > XR > OpenXR > ReferenceSpaceに設定があります。
Windowsでデスクトップに別視点の映像を表示するには
SubViewportノードを作成し、Use XRをオンにして、XROrigin3DのリグをSubViewportの子にします。その上でデスクトップの画面用にCamera3Dを作成します(こちらのviewportのuse_xrはtrueにしないこと)。
Questの実機でデバッグするには
エディタのRemote Deployで起動したアプリは、USB経由(adb reverse)でエディタのデバッガーにつながります。実行中に以下が使えます。
printの出力がエディタの出力パネルに出る- シーンドック上部のRemoteタブで、実機上のノード構成を見られる。選択したノードのプロパティは、インスペクターでリアルタイムに確認・変更できる
- ブレークポイント、プロファイラー、ビジュアルプロファイラー、モニター(FPS、メモリ、ドローコールなど)
- Debugメニューのシーン変更の同期・スクリプト変更の同期(保存すると再デプロイせずに実機に反映される)
ヘッドセットの映像はエディタでは見られないので、Meta Quest Developer Hubのキャスト機能などを使います。
ログはadbで見ます。Remote Deployするたびにadbサーバーが再起動するので、adb logcatを実行し続けても途中で切れてしまいます。デプロイのあとで、端末に残っているバッファを-dで取り出すのが確実です。
adb logcat -d -v time godot:V GodotOpenXR:V *:S
ヘッドセットを外していても画面を点けたままにしたい場合は、近接センサーを無効にします。作業が終わったら元に戻しておきます。
adb shell am broadcast -a com.oculus.vrpowermanager.prox_close
adb shell am broadcast -a com.oculus.vrpowermanager.automation_disable
Label3Dをカメラに向けると鏡文字になるときは
Label3Dの文字は+Z側から見て正しく読めます。一方、look_at()はノードの-Zをターゲットに向けるので、カメラに向けると裏側から見ることになり、鏡文字になります。字幕などをカメラに向けるときは、+Zがカメラ側を向くように回転を求めます。
var fwd := -camera.global_transform.basis.z
fwd.y = 0.0
fwd = fwd.normalized()
# +Zをカメラ側(fwdの逆)に向ける
var yaw := atan2(-fwd.x, -fwd.z)
label.global_transform.basis = Basis(Vector3.UP, yaw)
常にカメラを向いていればよいだけなら、Label3DのBillboardプロパティを使う方法もあります。