MRTKではじめるPortal表現

17.1K Views

December 14, 22

スライド概要

2022/12/18に開催したAR Fukuokaのハンズオン資料

profile-image

可視化技術や人間計測/空間計測技術を活用した問題解決に関する研究開発。 ARコンテンツ作成勉強会(AR_Fukuoka)を主催。

シェア

埋め込む »CMSなどでJSが使えない場合

関連スライド

各ページのテキスト
1.

MRTKではじめるPortal表現

2.

⾃⼰紹介 ⽒名︓吉永崇 (Takashi Yoshinaga) 所属︓Steampunk Digital株式会社 / エンジニア 九州先端科学技術研究所 / 特別研究員 領域︓AR/VR応⽤に関するR&D。主に医療⽀援 ウェアラブル・モーションキャプチャ技術開発 Volumetric Video遠隔コミュニケーション

3.

⾃⼰紹介 ⽒名︓吉永崇 (Takashi Yoshinaga) 趣味︓ARシステムのプロトタイピングと情報共有 @Taka_Yoshinaga Takashi Yoshinaga コミュニティ︓ARコンテンツ作成勉強会を主催

4.

ARコンテンツ作成勉強会(略称:AR Fukuoka)の概要 [形式] AR/VRコンテンツの作り⽅や関連技術を主にハンズオン形式で体験。 [規模] 参加⼈数はコロナ前は約5~10名/回、現在は約10~20名/回。 [参加条件] AR/VRの開発に興味があれば初⼼者⼤歓迎。専⾨知識は不要。

5.

Twitterと勉強会ページで情報を発信しています @AR_Fukuoka Googleで「AR勉強会」で検索

6.

ハッシュタグ #AR_Fukuoka

7.

今⽇のゴール https://youtu.be/rOwVVCeY_NU https://youtu.be/ps9HG3C5cpM ポータル表現を⽤いたAR/VRアプリを作るための基礎的な部分の実装とUnityEditorでの動作確認

8.

演習素材のダウンロード https://github.com/TakashiYoshinaga/ARFukuoka/raw/main/PortalMRTK_20221218/Sample.zip

9.

UnityHubを起動 Unity Hub

10.

プロジェクトを作成 (1/7) ①Projects ②New project

11.

プロジェクトを作成 (2/7) Editor Versionを開く

12.

プロジェクトを作成 (3/7) 2020.3.xを選択 ※2020以降でも動作するが 本資料ではこのバージョンで解説

13.

プロジェクトを作成 (4/7) 3Dを選択

14.

プロジェクトを作成 (5/7) プロジェクト名 (例:PortalApp) 保存場所 (例:Desktop)

15.

プロジェクトを作成 (6/7) Create project

16.

プロジェクトを作成 (7/7)

17.

UIの概要 Sceneタブ オブジェクトの一覧 オブジェクトの配置を行う プロジェクト内のフォルダやファイルの一覧

18.

シーンを作成 File -> Save As...

19.

シーンを作成 シーン名を設定(例︓PortalApp) Save

20.

今回使⽤するアセットのインストール

21.

移動先空間のアセット 本ハンズオンで利⽤するにはオブジェクトの位置の調整が必要なため、作者の許可のもと調整済みのパッケージを使⽤

22.

移動先空間のアセットの導⼊ (1/5) Assets

23.

移動先空間のアセットの導⼊ (2/5) ImportPackage Custom Package

24.

移動先空間のアセットの導⼊ (3/5) [Sampleフォルダ内] RPGPP_LT.unitypackage Open

25.

移動先空間のアセットの導⼊ (4/5) Import

26.

移動先空間のアセットの導⼊ (5/5) RPGPP_LTが追加されていればOK

27.

MRTKのダウンロード (1/3) https://github.com/microsoft/MixedRe alityToolkit-Unity/releases/tag/v2.8.3 ※今回はMRToolKit v2.8.3を使用

28.

MRTKのダウンロード (2/3) スクロール

29.

MRTKのダウンロード (3/3) Foundationをダウンロード

30.

MRTKのインストール (1/5) Assets -> Import Package -> Custom Package

31.

MRTKのインストール (2/5) [ダウンロードフォルダ内] MicrosoftMixedRealityToolkit.Unity.Foundation.2.8.3 Open

32.

MRTKのインストール (3/5) Import

33.

MRTKのインストール (4/5) Built-in Unity plugins ※OpenXRでもBuilt-inでもOKだが今回は後者

34.

MRTKのインストール (4/5) Skip Setup Until Next Session ※実際の開発ではスキップせず対応させるプラットフォームに合わせて設定を行う

35.

インストール完了

36.

Next Step 移動先の世界をシーンに追加

37.

移動先の世界を追加 (1/3) Assets->RPGPP_LT->Prefabs

38.

移動先の世界を追加 (2/3) Hierarchyに ドラッグ&ドロップ World

39.

移動先の世界を追加 (3/3) 移動先の空間が表⽰される

40.

確認 Worldを開く ⼦要素として各オブジェクトが登録されている 本来は各⾃で各オブジェクトの配置や位置の調整が必要。 今回は事前に調整したプレハブでこの操作を省略。

41.

ゲートを作成 (1/8) 何も選択されていない状態で Hierarchy内を右クリック

42.

ゲートを作成 (2/8) 3D Object Quad

43.

ゲートを作成 (3/8) 板が追加される ⾒づらいのでSceneの視点を調整 (次⾴)

44.

ゲートを作成 (4/8) Quadをダブルクリック

45.

ゲートを作成 (5/8) 板らしきもの (裏⾯のため不可視)

46.

ゲートを作成 (6/8) ⽩い板 (1x1m) Altもしくはoption + ドラッグで視点を回転

47.

ゲートを作成 (7/8) Quad Position X: 0 Y:1 Z:1 Rotation: X: 0 Y:0 Z:0 Scale: X:1.2 Y:2 Z:1

48.

ゲートを作成 (8/8) Quad 名前をPortalGateに変更

49.

動作確認 Play

50.

動作確認 Main Cameraからの視点 (固定視点)

51.

動作確認 再度Playをクリックして停⽌ 動作確認をしたときは編集に戻る前に必ず停⽌︕︕

52.

空間作成はほぼ完了

53.

MRTKの設定 (1/2) Mixed Reality -> Toolkit -> Add to Scene and Configure...

54.

MRTKの設定 (2/2) MRTK関連のオブジェクトが追加される

55.

Ctrl/command + Sで現状を保存

56.

動作確認 Play

57.

動作確認 [A][D]キー︓左右移動 [W][S]キー︓前後移動 [Q][E]キー︓上下移動 右クリック+ドラッグ︓回転 MRTKを使うことで仮想的に動きまわれる

58.

動作確認 再度Playをクリックして停⽌ 動作確認をしたときは編集に戻る前に必ず停⽌︕︕

59.

Next Step ゲートから移動先の世界を覗き込む

60.

今⽇のメインテーマ ステンシルバッファを使ったマスク表現

61.

ステンシルって︖

62.

ステンシルのイメージ (現実世界) ⽳の空いたシートの上からスプレー シートの⽳の部分だけ⾊がつく 引用元: https://jeanssitesame.web.fc2.com/content/column/stencil.html

63.

ステンシルのイメージ (デジタルな世界) 2D画⾯ ゲートのピクセルがシートの⽳に相当 Worldオブジェクトで上書き ⽳の部分だけ描画される

64.

つまり 2D画⾯内で描画する/しない領域を制御するテクニック

65.

シェーダーでの処理 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 1 0 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 ⽐較 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 0 0 0 0 1 1 1 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 ⽳の代わりに数値で描画領域を定義 ⽐較⽤の値を割り当て 同じ値(=1)のピクセルに描画

66.

この後やること 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 1 0 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 ⽐較 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 0 0 0 0 1 1 1 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 マスク側の各ピクセルの値 マスクされる側の値 それぞれを設定

67.

シェーダーを記述することで実現可能。 でも初学者には敷居が⾼い・・・ MRTKのStandard Shaderを使うと楽できる︕

68.

マスク情報の作成 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 1 0 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 ⽐較 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 0 0 0 0 1 1 1 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 マスク側の各ピクセルの値 マスクされる側の値 それぞれを設定

69.

マスク作成⼿順 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1 1 常に 0 上書き 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 描画前の背景(デフォルト値:0) ゲートのピクセルの値を1に設定 マスク完成

70.

これから操作する箇所の確認 PortalGate Default-Materialに注⽬ UnityではMaterial(に紐づいたシェーダー)で そのオブジェクトの⾒た⽬に関する設定を⾏う

71.

これから操作する箇所の確認 Default MaterialはUnityが⽤意した デフォルトのビジュアル設定なので変更不可 設定変更可能なマテリアルを作ろう

72.

マテリアルの作成 (1/7) Assets 空⽩を右クリック

73.

マテリアルの作成 (2/7) Create Material

74.

マテリアルの作成 (3/7) New Materialの名前をPortal Materialに変更

75.

マテリアルの作成 (4/7) PortalGateにドラッグ&ドロップ Portal Material

76.

マテリアルの作成 (5/7) PortalGate Portal Materialに差し代わっていればOK

77.

マテリアルの作成 (6/7) Shaderのドロップダウンを開く

78.

マテリアルの作成 (7/7) Mixed Reality Toolkit Standard

79.

ステンシル関連の設定 (1/7) PortalGate マテリアルの詳細を開く

80.

ステンシル関連の設定 (2/7) Rendering ModeをFadeに変更 Cull ModeをOffにして両⾯描画 Rendering ModeがOpaqueだとステンシルの設定に関係なく 空間的に奥にあるオブジェクトが描画されなくなるため要透過設定

81.

ステンシル関連の設定 (3/7) Albedoの横の□をクリック Aを0(=透明)にする

82.

ステンシル関連の設定 (4/7) Gateが消えるけど気にしない

83.

ステンシル関連の設定 (5/7) Render Queue Overrideを1999 今回は他のオブジェクトのRender Queueが2000なので それより⼩さな値を設定し、まず先にマスク情報を作成。

84.

ステンシル関連の設定 (6/7) Enable Stencil Testingをオン

85.

ステンシル関連の設定 (7/7) 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 1 1 1 1 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 0 常に 0 上書き 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ステンシル処理(以下の2項⽬)で 使⽤する値を1に設定 ステンシル処理(=描画)をする条件を Always(=常に処理)に設定 条件に合致した場合の処理を Replace(=書き換え)にして1を書き込む

86.

マスクされる側のステンシルバッファの設定 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 1 0 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 ⽐較 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 0 0 0 0 1 1 1 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 マスク側の各ピクセルの値 マスクされる側の値 それぞれを設定

87.

ステンシル関連の設定 (1/7) マスクされる側のオブジェクト 数が多いためオブジェクトごとに設定するのは⾯倒。 ただし、実は3つのマテリアルを使い回しているだけなので ⼤元となるマテリアルを変更してしまえばOK。

88.

ステンシル関連の設定 (2/7) Assets->RPGPP_LT->Materials

89.

ステンシル関連の設定 (3/7) ⼀気に設定するため、3つとも選択

90.

ステンシル関連の設定 (4/7) Shaderのドロップダウンを開く

91.

ステンシル関連の設定 (5/7) Mixed Reality Toolkit Standard

92.

ステンシル関連の設定 (6/7) Enable Stencil Testingをオン

93.

ステンシル関連の設定 (7/7) いまここ 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 1 0 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 ⽐較 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 0 0 0 0 1 1 1 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 ステンシル処理(以下の2項⽬)で 使⽤する値を1に設定 ステンシル処理(=描画)をする条件を Equal(等しい場合)に設定 条件に合致した場合の処理を Keepにして値の上書きはしない

94.

結果 ゲートの向こうを覗けるようになった

95.

Ctrl/command + Sで現状を保存

96.

動作確認 Play

97.

動作確認 動き回るとさらに奥⾏きを感じられる https://youtu.be/xuC07SmuZj0 [A][D]キー︓左右移動 [W][S]キー︓前後移動 [Q][E]キー︓上下移動 右クリック+ドラッグ︓回転

98.

動作確認 再度Playで停⽌

99.

Next Step 逆パターンも確認してみよう

100.

ゲートの外側にWorldオブジェクトを表⽰ (1/2) RPGPP_LT->Materials ⼀気に設定するため、3つとも選択

101.

ゲートの外側にWorldオブジェクトを表⽰ (2/2) いまここ 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 1 0 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 ⽐較 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 ゲートの値(=1)とNotEqualつまり 異なる値のピクセルに描画するよう設定

102.

結果

103.

表⽰を元に戻す (1/2) ⼀気に設定するため、3つとも選択

104.

表⽰を元に戻す (2/2) Stencil ComparisonをEqualに戻す

105.

Next Step ARモード VRモード カメラ(視点設定オブジェクト)とゲートの接触を検知し、各世界を⾏ったり来たりできるようにする

106.

接触検知をゲートに追加 (1/5) PortalGate Mesh Colliderが 接触検知を担っている 接触判定にMesh Colliderを使うことも可能だが、 判定領域を勝⼿に設定されるので使い勝⼿が良くない

107.

接触検知をゲートに追加 (2/5) Mesh Colliderを右クリックし、 RemoveComponent

108.

接触検知をゲートに追加 (3/5) PortalGate Add Component

109.

接触検知をゲートに追加 (4/5) Box Colliderで検索 Box Collider

110.

接触検知をゲートに追加 (5/5) Box Colliderが追加される Is Triggerをオン

111.

接触検知をカメラに追加 (1/6) MainCamera Add Component

112.

接触検知をカメラに追加 (2/6) Sphere Colliderで検索 Sphere Collider

113.

接触検知をカメラに追加 (3/6) Main Camera Sphere Colliderが追加される Is Triggerをオン Radiusを0.15

114.

補⾜︓Radius=0.15の理由 ここでPortal Gateとの 接触判定をしたい 引用元:https://docs.unity3d.com/ja/2021.3/Manual/UnderstandingFrustum.html Computer Graphicsの世界では描画する奥⾏きの範囲を Near clipping planeとFar clipping planeで設定。 今回Near=0.1[m]と設定されているため、接触半径を少し⼤きめの0.15[m]とした。

115.

接触検知をカメラに追加 (4/6) MainCamera Add Component

116.

接触検知をカメラに追加 (5/6) Rigidで検索 Rigidbody

117.

接触検知をカメラに追加 (6/6) Main Camera Rigidbodyが追加される Use Gravityをオフ Is Kinematicをオン

118.

Ctrl/command + Sで現状を保存

119.

スクリプトで接触検知を取得しよう

120.

スクリプトを追加 (1/4) PortalGate Add Component

121.

スクリプトを追加 (2/4) 検索をクリア PortalManager New script Create and Add

122.

スクリプトを追加 (3/4) PortalGate Portal Managerが追加される

123.

スクリプトを追加 (4/4) Assets スクリプトファイルとしても追加されている

124.

スクリプトを追加 PortalManager.csをダブルクリックで開く

125.

接触開始と終了を検知 public class PortalManager : MonoBehaviour { //最初に⼀回だけ呼ばれる void Start() { } //毎フレーム呼ばれる void Update() { } //他のオブジェクトが接触した時に呼ばれる void OnTriggerEnter(Collider other) { Debug.Log("Portal Entered"); } //接触終了時に呼ばれる void OnTriggerExit(Collider other) { Debug.Log("Portal Exited"); } } Lesson01

126.

Ctrl/command + Sでソースを保存

127.

動作確認の前におすすめレイアウト Scene Game SceneとGameウィンドウを横並びに表⽰

128.

動作確認の前におすすめレイアウト Scene Game [Sceneでの視点調整] 回転: Alt/option + ドラッグ 移動: ← → ↑ ↓キー

129.

動作確認 Play

130.

動作確認 Gameウィンドウをクリックして選択 Consoleを開く [A][D]キー︓左右移動 [W][S]キー︓前後移動 [Q][E]キー︓上下移動 右クリック+ドラッグ︓回転

131.

動作確認 PortalGateとカメラが接触開始・終了時にメッセージが表⽰

132.

動作確認 再度Playをクリックして停⽌ Projectに戻す

133.

Next Step ゲート通過後に表⽰を切り替える

134.
[beta]
ステンシル設定変更スクリプト (1/5)
using System.Collections.Generic;
using UnityEngine;
//ステンシルの⽐較条件を操作する際に必要
using UnityEngine.Rendering;
public class PortalManager : MonoBehaviour
{
//移動先の世界の3Dモデルをまとめたオブジェクト
[SerializeField] GameObject worldObject;
//上記オブジェクトのマテリアル(描画設定ファイル)を保持するために使⽤
List<Material> worldMaterials = new List<Material>();
//現在の表⽰モード
bool isARMode = true;
void Start()
{
}
/*以下略*/

Lesson02

135.
[beta]
ステンシル設定変更スクリプト (2/5)
//移動先の世界の3Dモデルをまとめたオブジェクト
[SerializeField] GameObject worldObject;
//上記オブジェクトのマテリアル(描画設定ファイル)を保持するために使⽤
List<Material> worldMaterials = new List<Material>();
void Start()
{
//移動先の3DモデルのRendererを取得
Renderer[] renderers =
worldObject.GetComponentsInChildren<Renderer>();
foreach (Renderer renderer in renderers)
{
//マテリアルを取得
Material material = renderer.sharedMaterial;
//既に他のオブジェクトから取得したマテリアルでなければリストに追加
if(!worldMaterials.Contains(material)){
worldMaterials.Add(material);
}
Lesson03
}
}

136.

ステンシル設定変更スクリプト (3/5) //他のオブジェクトが接触した時に呼ばれる void OnTriggerEnter(Collider other) { Debug.Log("Portal Entered"); } //接触終了時に呼ばれる void OnTriggerExit(Collider other) { Debug.Log("Portal Exited"); } //引数で受け取った設定でステンシル設定を変更 void SetStencilComparison(CompareFunction mode){ //マテリアルを1つずつ取得してステンシル処理の⽐較条件を変更 foreach(Material material in worldMaterials){ material.SetInt("_StencilComparison",(int)mode); } } Lesson04

137.

ステンシル設定変更スクリプト (4/5) //他のオブジェクトが接触した時に呼ばれる void OnTriggerEnter(Collider other) { Debug.Log("Portal Entered"); } //接触終了時に呼ばれる void OnTriggerExit(Collider other) { Debug.Log("Portal Exited"); /*ここにコード追加*/ } //引数で受け取った設定でステンシル設定を変更 void SetStencilComparison(CompareFunction mode){ //マテリアルを1つずつ取得してステンシル処理の⽐較条件を変更 foreach(Material material in worldMaterials){ material.SetInt("_StencilComparison",(int)mode); } }

138.

ステンシル設定変更スクリプト (5/5) void OnTriggerExit(Collider other) { Debug.Log("Portal Exited"); if(isARMode){//現在ARモード︓VRモードにしてゲートの外側のみを表⽰ SetStencilComparison(CompareFunction.NotEqual); isARMode=false; } else{//現在VRモード︓ARモードにしてゲートの内側のみを表⽰ SetStencilComparison(CompareFunction.Equal); isARMode=true; } } //アプリ終了時にEditor内の表⽰をARモードに戻しておく void OnDestroy() { SetStencilComparison(CompareFunction.Equal); } Lesson05

139.

Ctrl/command + Sでソースを保存

140.

Worldオブジェクトをスクリプトに登録 (1/2) PortalGate Worldオブジェクトを割り当てる(次⾴)

141.

Worldオブジェクトをスクリプトに登録 (2/2) Worldに注⽬(クリックしない) World Object横の ボックスにドラッグ&ドロップ

142.

動作確認 Play Gameウィンドウをクリックして選択

143.

動作確認 https://youtu.be/o7JWDX7Sbds [A][D]キー︓左右移動 [W][S]キー︓前後移動 [Q][E]キー︓上下移動 右クリック+ドラッグ︓回転

144.

動作確認 再度Playをクリックして停⽌

145.

問題点 接触前 接触中 ARモード 接触後 VRモード ⼀瞬、移動先の 世界が消える

146.

原因 NearPlane 引用元:https://docs.unity3d.com/ja/2021.3/Manual/UnderstandingFrustum.html Computer Graphicsの世界では描画する奥⾏きの範囲を Near clipping planeとFar clipping planeで設定。 Farより奥やNearよりも⼿前のオブジェクトは描画されない︕ PortalGateがNearPlaneの内側

147.

解決のためのアイディア Worldオブジェクト表⽰ カメラのコライダーが 接触した瞬間

148.

没にした実装 //他のオブジェクトが接触した時に呼ばれる void OnTriggerEnter(Collider other) { Debug.Log("Portal Entered"); } //接触終了時に呼ばれる void OnTriggerExit(Collider other) { Debug.Log("Portal Exited"); モード切り替えのコードを OnTriggerEnterに移動 if(isARMode){//現在ARモード︓ VRモードにしてゲートの外側のみを表⽰ SetStencilComparison(CompareFunction.NotEqual); isARMode=false; } else{//現在VRモード︓ ARモードにしてゲートの内側のみを表⽰ SetStencilComparison(CompareFunction.Equal); isARMode=true; } }

149.

問題点 (VR -> AR) ゲートをくぐっていないのに 元いた世界が消えてしまう 視線⽅向 後ろ向きに進む

150.

解決⽅法(暫定) 前進 後進 Collider接触中はWorldオブジェクトを表⽰

151.

実装 //他のオブジェクトが接触した時に呼ばれる void OnTriggerEnter(Collider other) { Debug.Log("Portal Entered"); //Alwaysを指定して常に表⽰ SetStencilComparison(CompareFunction.Always); } //接触終了時に呼ばれる void OnTriggerExit(Collider other) { Debug.Log("Portal Exited"); if(isARMode){//現在ARモード︓ VRモードにしてゲートの外側のみを表⽰ SetStencilComparison(CompareFunction.NotEqual); } isARMode=false; else{//現在VRモード︓ ARモードにしてゲートの内側のみを表⽰ SetStencilComparison(CompareFunction.Equal); /*以下略*/ Lesson06

152.

Ctrl/command + Sでソースを保存

153.

動作確認 Play Gameウィンドウをクリックして選択

154.

動作確認 [A][D]キー︓左右移動 [W][S]キー︓前後移動 [Q][E]キー︓上下移動 右クリック+ドラッグ︓回転 https://youtu.be/CfGrS9OZZS4 AR->VRの前進とVR->ARの後進は⾃然に切り替わる

155.

動作確認 再度Playで⽌める

156.

更なる問題点 ARモード VRモード 後進 視線⽅向 ゲートをくぐっていないのに これから⼊る世界が⾒えてしまう 同じAR->VRの移動でもWorldオブジェクトを表⽰したい場合と⾮表⽰にしたい場合がある

157.

結局どう解決するのか︖ (例︓AR->VRの場合) Gate接触時にWorldオブジェクトは表⽰。 ただし、Gateの表・裏のどちらか半分を表⽰ つまり Gate接触時は現在いる世界は残しつつ、 Gateの向こうはこれから⾏く世界を表⽰。

158.

Gate接触時の状態のパターン VRモード ARモード カメラの位置がGateの表(図中の左) カメラの位置がGateの裏(図中の右)

159.

シェーダーを操作することでクリッピングも可能。 ただし結構⾯倒なので今回は MRTKが提供するスクリプトに頼る

160.

Clipping Primitive 今回はClipping Planeを使⽤ 引用元: https://learn.microsoft.com/ja-jp/windows/mixed-reality/mrtkunity/mrtk2/features/rendering/clipping-primitive?view=mrtkunity-2022-05

161.

Clipping Planeの追加 (1/9) 右クリック

162.

Clipping Planeの追加 (2/9) 3D Object Plane

163.

Clipping Planeの追加 (3/9) ⼤きな板が表⽰される (10x10m相当)

164.

Clipping Planeの追加 (4/9) 名前をClippingPlaneに変更 Plane

165.

Clipping Planeの追加 (5/9) Position: 0 0 1 Rotation:-90 0 0 Scale: 全て0.05 位置と⾓度はPortalGateに⼀致するように設定。 サイズは⽬視での確認⽤なのでなんでもOK。

166.

Clipping Planeの追加 (6/9) Clipping Plane Add Component

167.

Clipping Planeの追加 (7/9) Clippingで検索 ClippingPlane

168.

Clipping Planeの追加 (8/9) ClippingPlaneが追加される

169.

Clipping Planeの追加 (9/9) Renderers: クリッピングしたいオブジェクトを ここで登録。 今回はオブジェクトが多いので 後ほどスクリプトから設定。 Clipping Side: このPlaneに対して表と裏の どちらをクリッピングするか設定

170.

スクリプトを⽤いたClippingPlane設定 (1/7) PortalManager.csを開く

171.
[beta]
スクリプトを⽤いたClippingPlane設定 (2/7)
//ステンシルの⽐較条件を操作する際に必要
using UnityEngine.Rendering;
//ClippingPlaneをこのスクリプトで操作するためのMRTKの関連機能を読み込み
using Microsoft.MixedReality.Toolkit.Utilities;
public class PortalManager : MonoBehaviour
{
//Clipping Planeスクリプト
[SerializeField] ClippingPlane clippingPlane;
//移動先の世界の3Dモデルをまとめたオブジェクト
[SerializeField] GameObject worldObject;
//上記オブジェクトのマテリアル(描画設定ファイル)を保持するために使⽤
List<Material> worldMaterials = new List<Material>();
//現在の表⽰モード
bool _isARMode=true;
void Start()
{
//ここでclippingPlaneにworldObject内のオブジェクトを登録
}

Lesson07

172.
[beta]
スクリプトを⽤いたClippingPlane設定 (3/7)
void Start()
{
//移動先の3DモデルのRendererを取得
Renderer[] renderers =
worldObject.GetComponentsInChildren<Renderer>();
foreach (Renderer renderer in renderers)
{
//clippingPlaneにWorld内のオブジェクトを登録 (必ず先に実⾏すること)
clippingPlane.AddRenderer(renderer);
//マテリアルを取得
Material material = renderer.sharedMaterial;
//既に他のオブジェクトから取得したマテリアルでなければリストに追加
if(!worldMaterials.Contains(material)){
worldMaterials.Add(material);
}

}

}
//デフォルトはクリッピングをオフ
clippingPlane.enabled=false;

Lesson08

173.

スクリプトを⽤いたClippingPlane設定 (4/7) void OnTriggerEnter(Collider other) { Debug.Log("Portal Entered"); SetStencilComparison(CompareFunction.Always); //ゲートに接触したらクリッピング処理をオン clippingPlane.enabled=true; } void OnTriggerExit(Collider other) { Debug.Log("Portal Exited"); if(isARMode){//現在ARモード︓ゲートの外側のみを表⽰し、VRモードにする SetStencilComparison(CompareFunction.NotEqual); isARMode=false; } else{//現在ARモード︓ゲートの外側のみを表⽰し、VRモードにする SetStencilComparison(CompareFunction.Equal); isARMode=true; } //ゲートから離れたらクリッピング処理をオフ Lesson09 clippingPlane.enabled=false; }

174.

Ctrl/command + Sでソースを保存

175.

スクリプトを⽤いたClippingPlane設定 (5/7) PortalGate PortalManagerのClippingPlaneに Hierarchy内のClippingPlaneオブジェクトを登録

176.

スクリプトを⽤いたClippingPlane設定 (6/7) Clipping Planeに注⽬ (まだクリックしない) None (Clipping Plane)に ドラッグ&ドロップ

177.

スクリプトを⽤いたClippingPlane設定 (7/7) ClippingPlane Clipping SidをOutside (ゲートの向こう側を表⽰)

178.

動作確認 Play

179.

動作確認 接触前 接触中 [A][D]キー︓左右移動 [W][S]キー︓前後移動 [Q][E]キー︓上下移動 右クリック+ドラッグ︓回転 この進⾏⽅向に関して クリッピングの切り替え完了 接触後

180.

動作確認 再度Playで停⽌

181.

状況に応じたクリッピング処理の実装 (1/3) VRモード ARモード カメラの位置がGateの表(図中の左) カメラの位置がGateの裏(図中の右)

182.

状況に応じたクリッピング処理の実装 (2/3) public class PortalManager : MonoBehaviour { //Clipping Planeスクリプト [SerializeField] ClippingPlane clippingPlane; //移動先の世界の3Dモデルをまとめたオブジェクト [SerializeField] GameObject worldObject; //上記オブジェクトのマテリアル(描画設定ファイル)を保持するために使⽤ List<Material> worldMaterials = new List<Material>(); //現在の表⽰モード bool isARMode = true; //ゲートに表と裏どちらから⼊るか float enteringSide; void Start() { /*省略*/ } Lesson10

183.
[beta]
状況に応じたクリッピング処理の実装 (3/3)
void OnTriggerEnter(Collider other) {
/* 省略 */
clippingPlane.enabled=true;
//カメラの座標をゲートを原点にしたローカル座標に変換
Vector3 localPos=
transform.InverseTransformPoint(Camera.main.transform.position);
//表か裏かを+-で表現
enteringSide=Mathf.Sign(localPos.z);
//条件に応じたクリッピング設定
if((isARMode&&enteringSide<0)||(!isARMode&&enteringSide>0)){
clippingPlane.ClippingSide=ClippingPrimitive.Side.Outside;
}
else{
clippingPlane.ClippingSide=ClippingPrimitive.Side.Inside;
}
//Clipping情報更新のフラグをOn
clippingPlane.IsDirty=true;
Lesson11
}

184.

Ctrl/command + Sでソースを保存

185.

動作確認 Play

186.

動作確認 https://youtu.be/fZyW3dVI_1Q

187.

動作確認 再度Playで停⽌

188.

Clipping Planeの不可視化 Clipping Plane Mesh Rendererをオフ

189.

問題点 接触前 接触中 接触後 [A][D]キー︓左右移動 [W][S]キー︓前後移動 [Q][E]キー︓上下移動 右クリック+ドラッグ︓回転 ⼊った⾯と同じ⽅向から出ても切り替わってしまう

190.

Enter/Exitの⽅向を考慮 void OnTriggerExit(Collider other) { Debug.Log("Portal Exited"); //カメラの座標をゲートを原点にしたローカル座標に変換 Vector3 localPos= transform.InverseTransformPoint(Camera.main.transform.position); //表か裏かを+-で表現 float exitingSide=Mathf.Sign(localPos.z); } if(isARMode){//現在ARモード︓ゲートの外側のみを表⽰し、VRモードにする SetStencilComparison(CompareFunction.NotEqual); isARMode=false; } else{//現在ARモード︓ゲートの外側のみを表⽰し、VRモードにする SetStencilComparison(CompareFunction.Equal); isARMode=true; } //ゲートから離れたらクリッピング処理をオフ clippingPlane.enabled=false; Lesson12

191.

Enter/Exitの⽅向を考慮 if(isARMode){//現在ARモード︓ if(exitingSide!=enteringSide){ //⼊った⽅向と逆から出たならVRモードに切り替え SetStencilComparison(CompareFunction.NotEqual); isARMode=false; } else{ SetStencilComparison(CompareFunction.Equal); } } else{//現在VRモード︓ if(exitingSide!=enteringSide){ //⼊った⽅向と逆から出たならARモードに切り替え SetStencilComparison(CompareFunction.Equal); isARMode=true; } else{ SetStencilComparison(CompareFunction.NotEqual); Lesson13 } }

192.

動作確認 Play

193.

動作確認

194.

動作確認 再度Playをクリックして停⽌

195.

仕上げ︓Diagnosticsの⾮表⽰化 MixedRealityToolKit Cloneをクリック

196.

仕上げ︓Diagnosticsの⾮表⽰化 Cloneをクリック

197.

仕上げ︓Diagnosticsの⾮表⽰化 Diagnostics Enable Diagnostics Systemをオフ

198.

動作確認 https://youtu.be/ps9HG3C5cpM

199.

完成︕

200.

完成版 https://github.com/TakashiYoshinaga/PortalExpression-Sample-for-Unity

201.

参考 AR Portal Tutorial with Unity - Portal Mask Implementation - Part 4 https://www.youtube.com/watch?v=OBb4iUiXaRA Building a holographic card with the MRTK Standard Shader https://smeenk.com/building-a-holographic-card-with-the-mrtkstandard-shader/ Clipping primitive ̶ MRTK2 https://learn.microsoft.com/en-us/windows/mixed-reality/mrtkunity/mrtk2/features/rendering/clipping-primitive QuestパススルーUnityサンプルプロジェクト (ポータルなし) https://github.com/TakashiYoshinaga/UnityVRStarter

202.

おまけ ARCore/ARKitアプリとしてビルド

203.

p オブジェクトの位置調整 p ARFoundationのインストール p ARCore/ARKitのインストール p ビルドセッティング p MRTKのセッティング p ARでスマホカメラを使うセッティング p ビルド

204.

p オブジェクトの位置調整 p ARFoundationのインストール p ARCore/ARKitのインストール p ビルドセッティング p MRTKのセッティング p ARでスマホカメラを使うセッティング p ビルド

205.

表⽰オブジェクトをまとめる (1/3) 下記を選択 ・World ・PortalGate ・ClippingPlane

206.

表⽰オブジェクトをまとめる (2/3) MixedRealitySceneContentにドラッグ&ドロップ

207.

表⽰オブジェクトをまとめる (3/3) MixedRealityScene Contentの⼦要素 になっていればOK

208.

⾼さの調整 (1/2) MixedRealitySceneContent

209.

⾼さの調整 (2/2) PosittionのY=-1.5 スマホARの原点はアプリ起動時のスマホの位置。 地⾯はスマホの1.5m下と仮定して全体的に下に下げる。 ちなみにQuestの場合、原点の⾼さ=地⾯なので調整不要。

210.

p オブジェクトの位置調整 p ARFoundationのインストール p ARCore/ARKitのインストール p ビルドセッティング p MRTKのセッティング p ARでスマホカメラを使うセッティング p ビルド

211.

AR Foundationのインストール (1/4) Window ->PackageManager

212.

AR Foundationのインストール (2/4) Packagesのドロップダウンから Unity Registryを選択

213.

AR Foundationのインストール (3/4) ARで検索

214.

AR Foundationのインストール (4/4) AR Foundation Install

215.

p オブジェクトの位置調整 p ARFoundationのインストール p ARCore/ARKitのインストール p ビルドセッティング p MRTKのセッティング p ARでスマホカメラを使うセッティング p ビルド

216.

ARCore and/or ARKitのインストール (1/3) ARCore XR Plugin Install

217.

ARCore and/or ARKitのインストール (2/3) ARKitXR Plugin Install

218.

ARCore and/or ARKitのインストール (3/3) 閉じる

219.

p オブジェクトの位置調整 p ARFoundationのインストール p ARCore/ARKitのインストール p ビルドセッティング p MRTKのセッティング p ARでスマホカメラを使うセッティング p ビルド

220.

ビルドプラットフォームの選択 (1/3) File ->Build Settings...

221.

ビルドプラットフォームの選択 (2/3) AndroidもしくはiOSを選択 Switch Platform

222.

ビルドプラットフォームの選択 (3/3) MRTK Project Configuratorが表⽰ された場合は閉じる。(この作業は後程)

223.

ビルド設定 Player Setting

224.

ビルド設定 for Android (1/6) Other Settings

225.

ビルド設定 for Android (2/6) Vulkan - で削除

226.

ビルド設定 for Android (3/6) Minimum API Level Android 7.0以上を選択

227.

ビルド設定 for Android (4/6) Configuration Scripting BackendをIL2CPP

228.

ビルド設定 for Android (5/6) Target Architecturesで ARM64にチェックを⼊れる

229.

ビルド設定 for Android (6/6) 閉じる

230.

ビルド設定 for iOS (1/3) Other Settings

231.

ビルド設定 for iOS (2/3) Configuration Camera Usage Descriptionに下記を追加 Required for AR

232.

ビルド設定 for iOS (3/3) 閉じる

233.

p オブジェクトの位置調整 p ARFoundationのインストール p ARCore/ARKitのインストール p ビルドセッティング p MRTKのセッティング p ARでスマホカメラを使うセッティング p ビルド

234.

MRTKの設定 Mixed Reality -> Toolkit -> Utilities -> Configure Project for MRTK

235.

MRTKの設定 Built-in Unity Plugin

236.

MRTKの設定 Show Settings

237.

MRTKの設定 (iOSの場合) iOS ARKitのチェックをオン

238.

MRTKの設定 (Androidの場合) Android ARCoreのチェックをオン

239.

MRTKの設定 (共通) Project Settingsを閉じる

240.

MRTKの設定 Next

241.

MRTKの設定 Apply

242.

MRTKの設定 Next

243.

MRTKの設定 Skip This Step

244.

MRTKの設定 Done

245.

p オブジェクトの位置調整 p ARFoundationのインストール p ARCore/ARKitのインストール p ビルドセッティング p MRTKのセッティング p ARでスマホカメラを使うセッティング p ビルド

246.

MRTKプロファイルの設定 MixedRealityToolkit Camera

247.

MRTKプロファイルの設定 DefaultMixedRealityCameraProfileをClone

248.

MRTKプロファイルの設定 Clone

249.

MRTKプロファイルの設定 Add Camera Setting Provider

250.

MRTKプロファイルの設定 New data provider4を開く

251.

MRTKプロファイルの設定 Typeの横のドロップダウン

252.

MRTKプロファイルの設定 Type ->Microsoft中略.UnityAR ->UnityARCameraSettings

253.

MRTKプロファイルの設定 ⻘空が消えてしまう

254.

MRTKプロファイルの設定 Camera Display Settingsを開く

255.

MRTKプロファイルの設定 Far Clipを1000に変更

256.

MRTKプロファイルの設定 Spatial Awareness

257.

MRTKプロファイルの設定 Enable Spatial Awareness Systemをオフ

258.

MRTKプロファイルの設定 Mixed Reality -> ToolKit -> Utilities ->UnityAR ->Update SettingDefines

259.

p オブジェクトの位置調整 p ARFoundationのインストール p ARCore/ARKitのインストール p ビルドセッティング p MRTKのセッティング p ARでスマホカメラを使うセッティング p ビルド

260.

ビルド File -> Build Settings...

261.

ビルド Buildをクリック Android: apkファイルができます iOS: xcodeプロジェクトができます

262.

インストール⽅法等はネットに掲載されていますのでご確認ください