这是老版本的教程,为了不耽误大家的时间,请直接看原文,本文仅供参考哦!原文链接:https://developer.microsoft.com/EN-US/WINDOWS/HOLOGRAPHIC/holograms_101
这篇文章将通过一个完整的实例来了解设备的核心特性,包括凝视,手势,声音输入和空间声音与空间映射。
先决条件
1.一个 Windows 10 PC 并安装有相应的软件tools installed..
2. 开发者模式的HoloLensconfigured for development. .
项目文件
1.下载此项目所需文件files。
2.将其保存在桌面或者其他易于找到的位置, 保持文件名为 Origami.
章节 1.“Holo”world
1设置Unity。
2制作全息对象。
3看到你做的全息对象。
- 打开 Unity.
- 选择 Open.
- 选择本地项目 Origami 文件夹
- 选择 Origami 点击 .
- 由于 Origami项目中不含有场景, 需要将默认的场景保存成项目场景: 打开File / Save Scene As.
- 将新场景命名为 Origami 然后点击保存按钮.
设置主相机
- 在Hierarchy 面板中, 选择Main Camera.
- 在Inspector 设置 transform position 为 0,0,0.
- 找到Clear Flags 属性, 打开下拉列表将 Skybox 改为Solid color.
- 点击 Background 的颜色选择器.
- 设置 R, G, B, A 都为 0.
配置场景
- 在Hierarchy 面板中, 点击Create -》 Create Empty.
- 右击 新GameObject 为它重新命名为 OrigamiCollection.
- 在 Project 面板中选择Holograms 文件夹,并双击打开:
- 拖拽Stage 到 Hierarchy面板中 ,使其成为 OrigamiCollection的子对象.
- 同理拖拽Sphere1
- 同理拖拽 Sphere2
- 删除Hierarchy 面板中的Directional Light
- 从 Holograms 文件夹中, 拖拽 Lights 到Hierarchy面板中.
- 在Hierarchy中, 选中 OrigamiCollection.
- 在Inspector面板中, 设置其transform position 为0, -0.5, 2.0.
- 点击Play 按钮 来预览你的全息对象.
- 你会在你的预览窗口看到你的Origami 对象.
- 再次点击 Play 按钮停止预览模式.
将项目从 Unity 导出到Visual Studio
- 在Unity中选择File > Build Settings.
- 在Platform 列表下选择 Windows Store 然后点击Switch Platform.
- 设置 SDK 为 Universal 10 ,设置 Build Type 为D3D.
- 勾选 Unity C# Projects.
- 点击 Add Open Scenes 来添加场景.
- 点击 Build.
- 创建一个新的文件夹命名为 "App".
- 单击 App 文件夹.
- 选中此文件夹.
- Unity发布完成后, 一个新的 File Explorer 窗口将出现.
- 打开 App 文件夹.
- 双击打开Origami.sln.
- 在 Visual Studio上部工具栏中, 将 Debug 设置为 Release ,将 ARM 变为 X86.
- 点击 Device button旁边的箭头, 然后选择 Remote Device.
- 设置 Address 为你的hololens的 IP 地址 . 如果你不知道你的设备的IP 地址, 开启hololens,选择 Settings > Network & Internet > Advanced Options 查看或者询问 Cortana "Hey Cortana, What's my IP address?"
- 将 Authentication Mode 设置为 Universal.
- 点击 Select
- 点击 Debug > Start Without debugging 或者点击 Ctrl + F5. 如果这是你第一次发布应用到hololens, 你需要配对,具体需要输入设备的PIN码,在设置-》update-》for developers-》paired devices中查看。 pair it with Visual Studio.
- 然后Origami项目开始发布部署到你的设备上并运行 .
- 请戴上你的hololens来欣赏你发布的全息应用吧.
章节 2.Gaze 凝视
这一章将介绍hololens交互的三大方式的第一种,凝视
目标
- 使用一个光标来可视化你的凝视点.
说明
- 回到 Unity 项目, 如果 Build Settings 窗口还开着请把它关掉 .
- 在 Project 面板中选择Holograms文件夹.
- 拖拽 Cursor 对象 到 Hierarchy 面板 的根节点下.
- 双击Cursor 对象近距离查看、.
- 在 Project 面板下右击Scripts 文件夹.
- 点击Create sub-menu.
- 选择C# Script.
- 给脚本命名 WorldCursor
- 选择 Hierarchy 面板中的Cursor 对象.
- 拖拽 WorldCursor 脚本到 Inspector 面板中.
- 双击WorldCursor 脚本用 Visual Studio打开.
- 复制粘贴以下代码到WorldCursor.cs 然后保存.
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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 = 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; } } }
- 从新发布APP,通过File > Build Settings.从文件>构建设置重建应用程序。
- 返回到以前用于部署到HoloLens的Visual Studio解决方案
- 出现提示时,选择“重新加载所有”。
- 单击调试 - >开始无调试或按Ctrl + F5。
- 现在看看场景,注意光标如何与对象的形状进行交互。
章节 3.手势
这一章,将添加手势支持,当用户选择场景中的纸球时,通过Unity设置有物理重力的纸球会掉落。
目标
- 通过手势控制场景中的全息对象.
说明
- 在Scripts 文件夹, 创建一个新的脚本并命名为 GazeGestureManager.
- 拖拽GazeGestureManager 脚本到Hierarchy面板中的 OrigamiCollection 对象上 .
- 用VS打开GazeGestureManager 脚本,将以下代码粘贴其中:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
using UnityEngine; using UnityEngine.VR.WSA.Input; public class GazeGestureManager : MonoBehaviour { public static GazeGestureManager Instance { get; private set; } // Represents the hologram that is currently being gazed at. public GameObject FocusedObject { get; private set; } GestureRecognizer recognizer; // Use this for initialization void Awake() { 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(); } } }
- 在Scripts 文件夹下创建一个新的脚本命名为 SphereCommands.
- 展开Hierarchy面板中的OrigamiCollection 对象.
- 拖拽SphereCommands 脚本到 Sphere1 对象上.
- 拖拽SphereCommands 脚本到 Sphere2 对象上.
- 用VS打开这个脚本并编辑,将以下代码复制粘贴到其中:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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; } } }
- 再一次导出,发布部署 app 到你的 HoloLens.
- 看着一个球.
- 使用手势点击观看其下落效果.
章节 4.语音
这一章将添加两个语音指令,“Reset world”来返回初始场景状态,“Drop sphere”使得球体下落。
目标
- 添加语音指令.
- 创建一个对语音指令做出反应的全息对象.
说明
- 在Scripts 文件夹下, 创建一个新的脚本并命名为 SpeechManager.
- 拖拽SpeechManager 脚本到 OrigamiCollection 对象上
- 用VS打开SpeechManager 脚本.
- 复制粘贴以下代码到 SpeechManager.cs 中然后保存:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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(); } } }
- 用VS打开SphereCommands 脚本.
- 更新为如下代码:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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(); } }
- 从新导出发布部署APP到 HoloLens.
- 看着其中一个球,说"Drop Sphere".
- 说"Reset World" 使他们回到初始的位置.
章节 5.空间声音
这一章,我们会为APP添加音乐,在特定操作上触发声音效果,我们将使用spatial sound特性给声音一个3D空间位置。
目标
- 在你的世界中听见全息对象.
说明
- 在Unity 选择 Edit > Project Settings > Audio
- 在右侧的 Inspector 面板中, 找到 Spatializer Plugin 设置然后选择 MS HRTF Spatializer.
- 在 Project 面板下从Holograms文件夹, 拖拽 Ambience 对象到 到 Hierarchy 面板下的OrigamiCollection 对象上.
- 选择OrigamiCollection 对象,在右侧的Inspector面板 中找到Audio Source 组件. 改变以下属性值:
- 选择 Spatialize property.
- 选择Play On Awake.
- 将Spatial Blend 改成 3D
- 选择Loop property.
- 展开 3D Sound Settings, 在Doppler Level 输入0.1.
- 设置Volume Rolloff 为 Custom Rolloff.
- 在Scripts 文件夹下, 创建一个新的脚本并命名为 SphereSounds.
- 拖拽SphereSounds 脚本到 Sphere1 和 Sphere2 对象上.
- 用VS打开SphereSounds 脚本, 更新为以下代码并保存.
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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(); } } }
- 保存脚本,返回到Unity中.
- 导出发布并部署 app 到你的 HoloLens.
- 移动远近来感受声音的变化.
章节 6.空间映射
现在我们将使用空间映射特性将游戏板放置在现实世界中的真实对象上。
目标
- 把你的现实世界变成一个虚拟世界.
- 把你的全息图放在你想把它放置的位置.
步骤
- 在Unity 中, 点击Project 面板下的 Holograms 文件夹.
- 将 Spatial Mapping asset 拖拽到 Hierarchy面板的根节点.
- 点击Hierarchy 面板下的Spatial Mapping 对象 .
- 在右侧的 Inspector 面板, 改变如下设置:
- 选择 Draw Visual Meshes box.
- 定位到Draw Material 然后点击它右侧的圆. 在顶部的搜索字段中键入“wireframe”。单击结果,然后关闭窗口。执行此操作时,Draw Material的值应设置为线框.
- 导出,发布并将应用程序部署到您的HoloLens。
- 当应用程序运行时,线框网格将覆盖你的现实世界。
- 观看滚动球体将如何从平台掉落到地板上!
现在,我们将向您展示如何将OrigamiCollection移动到新位置:
- 在Scripts 文件夹下, 创建一个新的脚本并命名为 TapToPlaceParent.
- 在Hierarchy 面板下,展开 OrigamiCollection 然后选择 Stage 对象.
- 拖拽TapToPlaceParent 脚本到 Stage 对象上.
- 用VS打开TapToPlaceParent 脚本, 更新为如下代码:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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; } } } }
- 导出,构建和部署应用程序.
- 现在,您现在应该能够通过注视它,使用选择手势,然后移动到一个新的位置,并再次使用选择手势,将对象放在特定的位置。
章节 7.全息的乐趣
目标
- 显示全息对象背后的世界入口的效果.
步骤
- 在 Project 面板下打开Holograms 文件夹:
- 拖拽Underworld 到 Hierarchy 面板下成为 OrigamiCollection 的孩子.
- 在 Scripts 文件夹下, 创建一个新的脚本并命名为 HitTarget.
- 在Hierarchy 面板下, 展开 OrigamiCollection.
- 展开Stage 对象然后选择 Target 对象 (blue fan).
- 拖拽HitTarget 脚本到 Target 对象上.
- 用VS打开HitTarget 脚本, 更新为以下代码:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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 object void 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.MappingEnabled = false; } }
- 在Unity, 选择 Target 对象.
- 在 Hit Target 组件中可见两个公共属性, 需要引用场景中的对象:
- 拖拽Hierarchy 面板下的 Underworld 对象到 Hit Target 组件下的 Underworld 属性中.
- 拖拽Hierarchy 面板下的 Stage对象到 Hit Target 组件下的 Object to Hide 属性中。
- 导出发布部署 app.
- 将折纸集合放在地板上,然后使用选择手势使球体下降。
- 当球碰到目标(blue fan)时,将发生爆炸。收集将被隐藏,一个洞会出现。
原文链接:https://developer.microsoft.com/en-us/windows/holographic/holograms_101
如有翻译上的错误请指正,谢谢