【Holograms 101D】一步步用Unity 開發 Hologram


轉載請注明出處:

Holograms 101


該教程將帶領你走完 Hologram 創建 的全過程。整個開發分成如下幾個部分: 聚焦輸入 gaze手勢輸入gesture , 聲音輸入voice input映射聲音spatial sound and 映射地圖spatial mapping.

整個教程大概耗時1個小時.

開始前的要求:

工程文件

  • 解壓下載的 開發文件,將該文件夾命名為 Origami


Chapter 1 - "Holo" world

在這一章節,我們將要配置 我們的 第一個 Unity 工程,並走過 整個Build (編譯)和 deploy(部署)過程

目標

  • 設置Unity環境,以適應Hologram開發
  • 創建一個Hologram
  • 看到創建出來的Hologram工程效果

步驟

  • 打開Unity
  • 點擊 Open.
  • 找到之前解壓並重命名為 Origami 文件夾
  • 選擇 Origami 並點擊 Select Folder.
  • 因為新工程 Origami project 並沒有包含任何 scene, 所以需要保存當前的默認 scene (default scene)為一個新的scene: File / Save Scene As.
  • 將新的scene命名為 Origami 並點擊 Save 按鈕.

配置主虛擬鏡頭(main virtual camera)

  • 在 Hierarchy Panel , 選中 Main Camera.
  • 在右側的 Inspector 選項欄中,將 position 配置為 0,0,0.
  • 在當前的 Clear Flags 屬性中,將下拉框中的設置從Skybox 改為 Solid color
  • 將 Background 屬性點開
  • 將 R, G, B, 和 A 設置為0
    

設置場景scene

  • 在 Hierarchy Panel , 點擊 Create 並 Create Empty
  • 新創建的文件夾名字是 GameObject,重命名該文件夾為 OrigamiCollection
  • 從 Project Panel 的 Holograms 文件夾中:
    • 拖拽 Stage 到 Hierarchy Panel 中,作為 OrigamiCollection 的子項
    • 拖拽 Sphere1 到 Hierarchy Panel 中,作為 OrigamiCollection 的子項
    • 拖拽 Sphere2 到 Hierarchy Panel 中,作為 OrigamiCollection 的子項
  • 刪除 Hierarchy Panel 中的  Directional Light 項
  • 從 Holograms 文件夾中,拖拽 Lights 項到 Hierarchy Panel 的根目錄
  • 選中 Hierarchy Panel  OrigamiCollection 目錄
  • 在右側的 Inspector 欄,設置 tranform的position值為0, -0.5, 2.0.
  • 點擊 項目 正上方的 “播放 按鈕,可以預覽效果

  • 再次點擊 “播放”按鈕,關閉預覽

從Unity導出工程到Visual Studio

  • 選擇 File > Build Settings.
  • 選擇 Windows Store 
  • SDK 選擇 Universal 10 並選擇 Build Type 為 D3D.
  • 選中 Unity C# Projects.
  • 點擊 Add Open Scenes 按鈕,添加當前的視圖到Scenes In Build 欄中
  • 點擊 Build.
  • 接下來會彈出一個windows窗口,在該窗口創建文件夾 App
  • 單擊 App 文件夾
  • 然后點擊 選擇文件夾. 就會開始編譯

  • 當編譯結束,就會自動彈出編譯好的文件目錄
  • 打開 App 文件夾
  • 雙擊 Origami.sln.
  • 在VS頂部工具欄中,修改Debug 為 Release ,並修改 ARM 為 X86 架構
  • 點擊設備旁的 三角形按鈕,選擇遠程計算機( Remote Device
    • 將地址(Address) 設置為Hololens的 IP 或者 Hololens的名稱
    • 設置身份驗證模式(Authentication Mode)通用(Universal)
    • 點擊選擇( Select)
  • 如果是 使用Hololens模擬器,則直接選擇HoloLens Emulator 即可。
  • 緊接着開始調試
  • Origami 項目將會被部署在你的Hololens上(或者Hololens 模擬器上),並運行
  • 帶上你的Hololens開始體驗吧!(譯者表示完全體驗不了,因為沒設備啊(┬_┬),只能仿真玩玩)
    
    啟動場景。。。。好興奮!!!
    
    移動視角看到的效果!!!
    a5989049-9a35-4ff4-8838-01078f0dd8f7.gif 

Chapter 2 - Gaze


在本節中,將會描述Hololens三種交互方式之一的  -- 凝視輸入(gaze).

目標

  • 讓我們的凝視輸入可視化(視線所指會出現一個圓圈).

介紹

  • 返回 Unity 工程
  • 選擇 Holograms 文件夾
  • 將 Cursor 組建拖入 Hierarchy panel 的根目錄中
  • 右擊 Scripts 文件夾,進入Create 目錄,並選擇C# Script.

  • 將新創建的腳本命名為 WorldCursor
  • 選中 Cursor 組件
  • 拖拽 WorldCursor 腳本到Inspector panel 中的 Cursor 組件上
  • jdfw.gif
  • 這時候,再雙擊 WorldCursor 腳本文件,會自動打開 Visual Studio 
  • 復制下面的代碼到 WorldCursor.cs 文件中,保存
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
using UnityEngine;
public class WorldCursor : MonoBehaviour
{
    private MeshRenderer meshRenderer;
    // Use this for initialization 初始化時候調用
    void Start()
    {
        // Grab the mesh renderer that's on the same object as this script.
        // 獲取 meshRenderer
        meshRenderer = this.gameObject.GetComponentInChildren<MeshRenderer>();
    }
    // Update is called once per frame 每一幀都會自動更新
    void Update()
    {
        // Do a raycast into the world based on the user's
        // head position and orientation.
        var headPosition = Camera.main.transform.position;
        var gazeDirection = Camera.main.transform.forward;
        RaycastHit hitInfo;
        if (Physics.Raycast(headPosition, gazeDirection, out hitInfo))
        {
            // If the raycast hit a hologram...
            // Display the cursor mesh.
            meshRenderer.enabled = true;
            // Move the cursor to the point where the raycast hit.
            this.transform.position = hitInfo.point;
            // Rotate the cursor to hug the surface of the hologram.
            this.transform.rotation = Quaternion.FromToRotation(Vector3.up, hitInfo.normal);
        }
        else
        {
            // If the raycast did not hit a hologram, hide the cursor mesh.
            meshRenderer.enabled = false;
        }
    }
}

  • 進入目錄 File > Build Settings 重新生成工程
  • 返回Visual Studio 解決方案中
  • 這時會提示 是否需要重新加載 ,選擇是。
  • 然后繼續點擊調試

  • 現在可以看到視線聚焦之處,有一個紅色圓環。

Chapter 3 - Gestures


在這一章節中,我們將學習使用 手勢輸入gestures通過使能 Unity 的物理引擎,打開重力模擬, 當用戶選擇了一個紙球,就會讓該紙球下落。

目標

  • 使用選擇手勢控制Hologram

步驟

接下來創建一個腳本,使得程序能夠檢測到 選擇手勢 

  • 在 Scripts 目錄中,創建一個名為 GazeGestureManager 的腳本
  • 將 GazeGestureManager 腳本拖入 OrigamiCollection 目錄中

  • 打開 GazeGestureManager 腳本,並復制如下code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
using UnityEngine;
using UnityEngine.VR.WSA.Input;
 
public class GazeGestureManager : MonoBehaviour
{
    public static GazeGestureManager Instance { getprivate set; }
 
    // Represents the hologram that is currently being gazed at.
    public GameObject FocusedObject { getprivate set; }
 
    GestureRecognizer recognizer;
 
    // Use this for initialization
    void Start()
    {
        Instance = this;
 
        // Set up a GestureRecognizer to detect Select gestures.
        recognizer = new GestureRecognizer();
        recognizer.TappedEvent += (source, tapCount, ray) =>
        {
            // Send an OnSelect message to the focused object and its ancestors.
            if (FocusedObject != null)
            {
                FocusedObject.SendMessageUpwards("OnSelect");
            }
        };
        recognizer.StartCapturingGestures();
    }
 
    // Update is called once per frame
    void Update()
    {
        // Figure out which hologram is focused this frame.
        GameObject oldFocusObject = FocusedObject;
 
        // Do a raycast into the world based on the user's
        // head position and orientation.
        var headPosition = Camera.main.transform.position;
        var gazeDirection = Camera.main.transform.forward;
 
        RaycastHit hitInfo;
        if (Physics.Raycast(headPosition, gazeDirection, out hitInfo))
        {
            // If the raycast hit a hologram, use that as the focused object.
            FocusedObject = hitInfo.collider.gameObject;
        }
        else
        {
            // If the raycast did not hit a hologram, clear the focused object.
            FocusedObject = null;
        }
 
        // If the focused object changed this frame,
        // start detecting fresh gestures again.
        if (FocusedObject != oldFocusObject)
        {
            recognizer.CancelGestures();
            recognizer.StartCapturingGestures();
        }
    }
}

  • 創建另外一個腳本 SphereCommands.
  • 占看 OrigamiCollection 目錄
  • 拖拽 SphereCommands 腳本到 Sphere1 模型上
  • 拖拽 SphereCommands 腳本到 Sphere2 模型上
  • 打開 visual studio 編輯,復制如下代碼到 SphereCommands 腳本中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
using UnityEngine;
 
public class SphereCommands : MonoBehaviour
{
    // Called by GazeGestureManager when the user performs a Select gesture
    void OnSelect()
    {
        // If the sphere has no Rigidbody component, add one to enable physics.
        if (!this.GetComponent<Rigidbody>())
        {
            var rigidbody = this.gameObject.AddComponent<Rigidbody>();
            rigidbody.collisionDetectionMode = CollisionDetectionMode.Continuous;
        }
    }
}

  • 重新生成Hologram
  • 注視紙球
  • 采用選擇手勢,查看紙球下落過程
jdfw.gif

Chapter 4 - Voice


這一章節,我們將要添加兩個語音輸入命令( voice commands ):

"Reset world": 將掉落的小球,初始化到原始位置

"Drop sphere":令小球掉落

目標

  • 添加常駐后台的聲音識別命令.
  • 創建一個能對聲音產生反應的應用

步驟

  • 在 Scripts 目錄中,創建一個名為 SpeechManager 的腳本
  • 拖拽 SpeechManager 腳本到 OrigamiCollection 目錄中
  • 雙擊打開 SpeechManager 腳本
  • 復制如下代碼到腳本 SpeechManager.cs 中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Windows.Speech;
 
public class SpeechManager : MonoBehaviour
{
    KeywordRecognizer keywordRecognizer = null;
    Dictionary<string, System.Action> keywords = new Dictionary<string, System.Action>();
 
    // Use this for initialization
    void Start()
    {
        keywords.Add("Reset world", () =>
        {
            // Call the OnReset method on every descendant object.
            this.BroadcastMessage("OnReset");
        });
 
        keywords.Add("Drop Sphere", () =>
        {
            var focusObject = GazeGestureManager.Instance.FocusedObject;
            if (focusObject != null)
            {
                // Call the OnDrop method on just the focused object.
                focusObject.SendMessage("OnDrop");
            }
        });
 
        // Tell the KeywordRecognizer about our keywords.
        keywordRecognizer = new KeywordRecognizer(keywords.Keys.ToArray());
 
        // Register a callback for the KeywordRecognizer and start recognizing!
        keywordRecognizer.OnPhraseRecognized += KeywordRecognizer_OnPhraseRecognized;
        keywordRecognizer.Start();
    }
 
    private void KeywordRecognizer_OnPhraseRecognized(PhraseRecognizedEventArgs args)
    {
        System.Action keywordAction;
        if (keywords.TryGetValue(args.text, out keywordAction))
        {
            keywordAction.Invoke();
        }
    }
}

  • 打開 SphereCommands腳本
  • 更新其代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
using UnityEngine;
 
public class SphereCommands : MonoBehaviour
{
    Vector3 originalPosition;
 
    // Use this for initialization
    void Start()
    {
        // Grab the original local position of the sphere when the app starts.
        originalPosition = this.transform.localPosition;
    }
 
    // Called by GazeGestureManager when the user performs a Select gesture
    void OnSelect()
    {
        // If the sphere has no Rigidbody component, add one to enable physics.
        if (!this.GetComponent<Rigidbody>())
        {
            var rigidbody = this.gameObject.AddComponent<Rigidbody>();
            rigidbody.collisionDetectionMode = CollisionDetectionMode.Continuous;
        }
    }
 
    // Called by SpeechManager when the user says the "Reset world" command
    void OnReset()
    {
        // If the sphere has a Rigidbody component, remove it to disable physics.
        var rigidbody = this.GetComponent<Rigidbody>();
        if (rigidbody != null)
        {
            DestroyImmediate(rigidbody);
        }
 
        // Put the sphere back into its original local position.
        this.transform.localPosition = originalPosition;
    }
 
    // Called by SpeechManager when the user says the "Drop sphere" command
    void OnDrop()
    {
        // Just do the same logic as a Select gesture.
        OnSelect();
    }
}

  • 重新build整個工程
  • 注視某一個球體,說出命令 "Drop Sphere".
  • 說出命令"Reset World",讓球體返回原來位置。
  • (譯者表示Emulator中也是可以使用聲音來控制的,Follow me, say " Drop sphere~")

Chapter 5 - Spatial sound


在這一章節中,我們將要添加一段音樂到應用app中,然后在特定動作下,觸發音樂。我們將要使用 聲音映射spatial sound 來 將插入的音樂定位到指定的位置上。

目標

  • 在我們的世界中,聽到Hologram

步驟

  • 進入選項 Edit > Project Settings > Audio
2016-04-26 (1).png
  • 在右邊的 Inspector Panel 中,, 找到 Spatializer Plugin 並選擇 MS HRTF Spatializer.

  • 將 Holograms 文件夾中的 Ambience 模型,拖拽到 OrigamiCollection 目錄中
  • 選中 OrigamiCollection 目錄,並在右邊Inspector panel找到 Audio Source ,修改如下屬性:
    • 選中 Spatialize 
    • 選中 Play On Awake.
    • 修改 Spatial Blend 為 3D
    • 選中 Loop
    • 展開 3D Sound Settings,並在Doppler Level 輸入 0.1 
    • 設置 Volume Rolloff   Custom Rolloff.

  • 在 Scripts 目錄中,創建一個 SphereSounds 腳本
  • 將腳本 SphereSounds 拖拽到 Sphere1 和 Sphere2 模型上
  • 打開 SphereSounds 腳本,並更新如下代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
using UnityEngine;
 
public class SphereSounds : MonoBehaviour
{
    AudioSource audioSource = null;
    AudioClip impactClip = null;
    AudioClip rollingClip = null;
 
    bool rolling = false;
 
    void Start()
    {
        // Add an AudioSource component and set up some defaults
        audioSource = gameObject.AddComponent<AudioSource>();
        audioSource.playOnAwake = false;
        audioSource.spatialize = true;
        audioSource.spatialBlend = 1.0f;
        audioSource.dopplerLevel = 0.0f;
        audioSource.rolloffMode = AudioRolloffMode.Custom;
 
        // Load the Sphere sounds from the Resources folder
        impactClip = Resources.Load<AudioClip>("Impact");
        rollingClip = Resources.Load<AudioClip>("Rolling");
    }
 
    // Occurs when this object starts colliding with another object
    void OnCollisionEnter(Collision collision)
    {
        // Play an impact sound if the sphere impacts strongly enough.
        if (collision.relativeVelocity.magnitude >= 0.1f)
        {
            audioSource.clip = impactClip;
            audioSource.Play();
        }
    }
 
    // Occurs each frame that this object continues to collide with another object
    void OnCollisionStay(Collision collision)
    {
        Rigidbody rigid = this.gameObject.GetComponent<Rigidbody>();
 
        // Play a rolling sound if the sphere is rolling fast enough.
        if (!rolling && rigid.velocity.magnitude >= 0.01f)
        {
            rolling = true;
            audioSource.clip = rollingClip;
            audioSource.Play();
        }
        // Stop the rolling sound if rolling slows down.
        else if (rolling && rigid.velocity.magnitude < 0.01f)
        {
            rolling = false;
            audioSource.Stop();
        }
    }
 
    // Occurs when this object stops colliding with another object
    void OnCollisionExit(Collision collision)
    {
        // Stop the rolling sound if the object falls off and stops colliding.
        if (rolling)
        {
            rolling = false;
            audioSource.Stop();
        }
    }
}

  • 保存代碼,重新build工程
  • 這時候兩個小球,相當於一個聲源,當移動視角,帶上耳機體驗的話,是能夠感覺到雙通道聲音的趕腳的!(棒)

Chapter 6 - Spatial mapping


現在我們要使用 spatial mapping ,將 我們的應用放置到物理世界中的實物上。

目標

  • 將真實世界代入到虛擬世界中
  • 隨意放置我們的Hologram

步驟

  • 在Unity 中,選中Holograms 目錄
  • 拖拽 Spatial Mapping 到 Hierarchy 的根目錄下
  • 選中 Spatial Mapping 
  • 在右邊的 Inspector panel 中,修改如下屬性:
    • 選中 Draw Visual Meshes 選項
    • Draw Material 選項選為 "wireframe
  • 重新編譯build工程
  • 當應用運行,可以看到 (網格模型)wireframe mesh 將在物理世界中顯示
  • 觀察小球是怎么在當前場景下落的

下面將指導你如何將 OrigamiCollection 移動到一個新的位置:

  • 在 Scripts 文件夾中,創建一個腳本名叫TapToPlaceParent.
  • Hierarchy 中,展開 OrigamiCollection 目錄,並選中Stage 模型
  • 將腳本 TapToPlaceParent 拖拽到 Stage 模型上
  • 更新代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
using UnityEngine;
 
public class TapToPlaceParent : MonoBehaviour
{
    bool placing = false;
 
    // Called by GazeGestureManager when the user performs a Select gesture
    void OnSelect()
    {
        // On each Select gesture, toggle whether the user is in placing mode.
        placing = !placing;
 
        // If the user is in placing mode, display the spatial mapping mesh.
        if (placing)
        {
            SpatialMapping.Instance.DrawVisualMeshes = true;
        }
        // If the user is not in placing mode, hide the spatial mapping mesh.
        else
        {
            SpatialMapping.Instance.DrawVisualMeshes = false;
        }
    }
 
    // Update is called once per frame
    void Update()
    {
        // If the user is in placing mode,
        // update the placement to match the user's gaze.
 
        if (placing)
        {
            // Do a raycast into the world that will only hit the Spatial Mapping mesh.
            var headPosition = Camera.main.transform.position;
            var gazeDirection = Camera.main.transform.forward;
 
            RaycastHit hitInfo;
            if (Physics.Raycast(headPosition, gazeDirection, out hitInfo,
                30.0f, SpatialMapping.PhysicsRaycastMask))
            {
                // Move this object's parent object to
                // where the raycast hit the Spatial Mapping mesh.
                this.transform.parent.position = hitInfo.point;
 
                // Rotate this object's parent object to face the user.
                Quaternion toQuat = Camera.main.transform.localRotation;
                toQuat.x = 0;
                toQuat.z = 0;
                this.transform.parent.rotation = toQuat;
            }
        }
    }
}

  • 重新編譯build工程
  • 現在我們應該可以通過凝視(gazing)將我們的目標重新定位。使用選擇手勢(Select gesture)就可以移動位置
jdfw.gif

Chapter 7 - Holographic fun

Objectives

  • Reveal the entrance to a holographic underworld.

Instructions

Now we'll show you how to uncover the holographic underworld:

  • From the Holograms folder in the Project Panel:
    • Drag Underworld into the Hierarchy to be a child of OrigamiCollection.
  • In the Scripts folder, create a script named HitTarget.
  • In the Hierarchy, expand the OrigamiCollection.
  • Expand the Stage object and select the Target object (blue fan).
  • Drag the HitTarget script onto the Target object.
  • Open the HitTarget script in Visual Studio, and update it to be the following:

HitTarget.cs[hide]
using UnityEngine;public class HitTarget : MonoBehaviour{// These public fields become settable properties in the Unity editor.public GameObject underworld;public GameObject objectToHide;// Occurs when this object starts colliding with another objectvoid OnCollisionEnter(Collision collision){// Hide the stage and show the underworld. objectToHide.SetActive(false); underworld.SetActive(true);// Disable Spatial Mapping to let the spheres enter the underworld.SpatialMapping.Instance.SetMappingEnabled(false);}}

  • In Unity, select the Target object.
  • Two public properties are now visible on the Hit Target component and need to reference objects in our scene:
    • Drag Underworld from the Hierarchy panel to the Underworld property on the Hit Target component.
    • Drag Stage from the Hierarchy panel to the Object to Hide property on the Hit Target component.
  • Export, build and deploy the app.
  • Place the Origami Collection on the floor, and then use the Select gesture to make a sphere drop.
  • When the sphere hits the target (blue fan), an explosion will occur. The collection will be hidden and a hole to the underworld will appear.

The end

And that's the end of this tutorial!

You learned:

  • How to create a holographic app in Unity.
  • How to make use of gaze, gesture, voice, sounds, and spatial mapping.
  • How to build and deploy an app using Visual Studio.

You are now ready to start creating your own holographic apps!



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM