» VR開発メモトップへ

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プロパティを使う方法もあります。