首页 > 代码库 > 微软Hololens学院教程-Hologram Gaze(凝视)
微软Hololens学院教程-Hologram Gaze(凝视)
Hololens的使用如果类比到计算机的使用,在输入操作方面,Hololens了解用户的操作意图的第一个步骤是凝视,用户的凝视射线呈现在场景中的点为凝视点,就好像是电脑中的鼠标光标点,凝视是第一步,是人与hololens操作的开始。
涉及凝视相关的知识点如下:
1 当用户看着一个全息图时,光标点会有反馈表现—表明用户看到了全息图,当用户凝视视线离开全息图时,光标点也要有反馈-表明用户没有在看全息图。
2 当用户注视到全息图时,给于用户更多反馈,例如声音,全息图当变化等。
3 使用定位技术使得用户可以选中更小的全息图。
4 添加方向指示图标指引用户找到全息图
5全息指示面板追随用户移动,一直保持在用户可见视角之内。
前提条件:
1 一台已经安装好开发工具的windows10 pc
2 一些C#编程能力
3 已经完成了教程 Holograms-101
4 一个开发者模式的Hololens 设备
项目文件:
下载该教程所需文件files
章节1-Unity 设置
步骤:
- 开启 Unity.
- 选择 New Project.
- 给项目命名为 ModelExplorer.
- 保存地址到你下载的项目文件下的 Gaze 文件夹下
- 选择为 3D项目.
- 点击 Create Project.
发布到Hololens设备前的一些Unity必要设置
- 到Unity中选择 Edit > Project Settings > Player.
- 在右侧的Inspector Panel 面板中, 选择 Windows Store 图标.
- 展开 Other Settings 组.
- 在 Rendering 部分, 勾选 Virtual Reality Supported 选框 以添加一个新的 Virtual Reality SDKs 列表.
- 验证 Windows Holographic 是否在列表中. 如果不在,选择 + 按钮将 Windows Holographic添加进列表.
- 在主工具栏中选择Edit > Project Settings > Quality.
- 依然是右侧的Inspector面板,在 Windows Store 图标下点击Default 下拉箭头.
- 选择 Fastest for Windows Store Apps.
导入美术资源
- 右击Project 面板下Assets 文件夹.
- 点击 Import Package > Custom Package.
- 定位到你下载的项目文件,然后选择 ModelExplorer.unitypackage.
- 点击 Open.
- 在出现的小窗口中,选择 Import button.
场景设置
- 删除 Hierarchy面板中的 Main Camera.
- 在Project面板下,找到 HoloToolkit 文件夹, 打开 Utilities folder, 然后打开 Prefabs folder.
- 拖拽Prefabs文件夹下的 Main Camera到Hierarchy 面板中.
- 右击Hierarchy中的Directional Light 然后选择 Delete.
- 在Project面板下的 Holograms 文件夹下, 拖拽以下资源到 Hierarchy面板中:
- AstroMan
- Lights
- SpaceAudioSource
- SpaceBackground
- Fitbox
- 选择Hierarchy 面板下的Fitbox
- 拖拽场景中的 AstroMan 到右侧Fitbox的Inspector 面板中的Hologram Collection 属性
发布项目
- 保存当前场景: File > Save Scene As.
- 点击 New Folder 命名新文件夹为 Scenes.
- 将当前场景命名为 “ModelExplorer” 然后保存在刚新建的 Scenes 文件夹下.
- 返回Unity,选择 File > Build Settings.
- 点击 Add Open Scenes 添加ModelExplorer场景.
- 选择 Windows Store然后点击Switch Platform.
- 设置 SDK 为 Universal 10 , Build Type 为 D3D.
- 勾选 Unity C# Projects.
- 点击 Build.
- 创建一个新的文件夹命名为 "App".
- 单击App文件夹
- 选择 Select Folder.
- 当Unity Build完成后, 一个新的文件窗口会出现.
- 打开其 App Folder.
- 打开 ModelExplorer Visual Studio Solution.
- 在 Visual Studio中, 右击 Package.appxmanifest 文件选择查看代码 View Code
- 定位代码中的 TargetDeviceFamily 然后将名称改掉, Name="Windows.Universal" 变为Name="Windows.Holographic".
- 点击保存 Package.appxmanifest.
- 在 Visual Studio顶部工具栏中, 将 Debug 改为 Release ,将 ARM 改为 x86.
- 点击Device 按钮的下拉箭头, 然后选择远程设备 Remote Machine.
- 输入你设备的IP地址, 然后将认证模式设为 Universal (Unencrypted Protocol). 点击 Select. 如果你不知道你设备的IP地址, 打开你的设备,在 Settings > Network & Internet > Advanced Options中可以查看到.
- 在VS的顶部工具栏, 点击 Debug -> Start Without debugging 或者 Ctrl + F5. 如果这是你第一次部署到你的设备, 你需要进行配对 pair it with Visual Studio.
- 部署完成后, 可以使用选择手势关闭Fixbox.
章节2 光标点与目标反馈
光标设计遵循以下原则:
1 光标要一直出现在视角中
2 光标不能太小也不能太大
3 光标不能遮挡内容
步骤:
- 在Hierarchy 面板的顶部点击Create 按钮.
- 选择 Create Empty.
- 点击新创建的 GameObject 然后将它名称改为为 "Managers".
- 在 Hierarchy 面板下, 选择 Managers 对象.
- 在 Inspector 面板下, 点击 Add Component 按钮.
- 在搜索框输入 Gaze Manager. 选择此结果.
- 在 Inspector 面板下, 选择 RaycastLayerMask 下拉单 将勾选的 TransparentFX 去掉.
- 在project面板下,找到HoloToolkit\Input\Prefabs 文件夹, 找到 Cursor 对象.
- 拖拽此对象 Cursor 到 Hierarchy.
- 在 Hierarchy 面板下, 选择Cursor 对象.
- 在 Inspector 面板下, 点击Add Component 按钮.
- 在搜索框输入Cursor Manager. 选择此结果.
- 展开Hierarchy 面板下的Cursor 对象.
- 拖拽 CursorOnHolograms 对象到右侧Inspector 面板下的Cursor On Holograms 属性中。
- 同理拖拽 CursorOffHolograms 对象到右侧Inspector 面板下的 Cursor Off Holograms 属性中。
接下来你需要编辑GazeManager.cs 代码,实现以下几点:
1 执行一个物理射线physics raycast,
2 存储射线交叉点的位置和法线position and normal
3 如果射线没有击中任何对象,将位置与法线设为默认值
GazeManager.cs
using HoloToolkit; using UnityEngine; /// <summary> /// GazeManager determines the location of the user‘s gaze, hit position and normals. /// </summary> public class GazeManager : Singleton<GazeManager> { [Tooltip("Maximum gaze distance for calculating a hit.")] public float MaxGazeDistance = 5.0f; [Tooltip("Select the layers raycast should target.")] public LayerMask RaycastLayerMask = Physics.DefaultRaycastLayers; /// <summary> /// Physics.Raycast result is true if it hits a Hologram. /// </summary> public bool Hit { get; private set; } /// <summary> /// HitInfo property gives access /// to RaycastHit public members. /// </summary> public RaycastHit HitInfo { get; private set; } /// <summary> /// Position of the user‘s gaze. /// </summary> public Vector3 Position { get; private set; } /// <summary> /// RaycastHit Normal direction. /// </summary> public Vector3 Normal { get; private set; } private GazeStabilizer gazeStabilizer; private Vector3 gazeOrigin; private Vector3 gazeDirection; void Awake() { /* TODO: DEVELOPER CODING EXERCISE 3.a */ // 3.a: GetComponent GazeStabilizer and assign it to gazeStabilizer. } private void Update() { // 2.a: Assign Camera‘s main transform position to gazeOrigin. gazeOrigin = Camera.main.transform.position; // 2.a: Assign Camera‘s main transform forward to gazeDirection. gazeDirection = Camera.main.transform.forward; // 3.a: Using gazeStabilizer, call function UpdateHeadStability. // Pass in gazeOrigin and Camera‘s main transform rotation. // 3.a: Using gazeStabilizer, get the StableHeadPosition and // assign it to gazeOrigin. UpdateRaycast(); } /// <summary> /// Calculates the Raycast hit position and normal. /// </summary> private void UpdateRaycast() { /* TODO: DEVELOPER CODING EXERCISE 2.a */ // 2.a: Create a variable hitInfo of type RaycastHit. RaycastHit hitInfo; // 2.a: Perform a Unity Physics Raycast. // Collect return value in public property Hit. // Pass in origin as gazeOrigin and direction as gazeDirection. // Collect the information in hitInfo. // Pass in MaxGazeDistance and RaycastLayerMask. Hit = Physics.Raycast(gazeOrigin, gazeDirection, out hitInfo, MaxGazeDistance, RaycastLayerMask); // 2.a: Assign hitInfo variable to the HitInfo public property // so other classes can access it. HitInfo = hitInfo; if (Hit) { // If raycast hit a hologram... // 2.a: Assign property Position to be the hitInfo point. Position = hitInfo.point; // 2.a: Assign property Normal to be the hitInfo normal. Normal = hitInfo.normal; } else { // If raycast did not hit a hologram... // Save defaults ... // 2.a: Assign Position to be gazeOrigin plus MaxGazeDistance times gazeDirection. Position = gazeOrigin + (gazeDirection * MaxGazeDistance); // 2.a: Assign Normal to be the user‘s gazeDirection. Normal = gazeDirection; } } }
接下来你要编辑 CusorManager.cs 代码实现以下目标:
1 判断哪个光标状态应该被激活,
2 根据光标是否在全息图上来不断更新光标状态
3 始终将光标放在用户正在注视的位置。
using HoloToolkit; using UnityEngine; /// <summary> /// CursorManager class takes Cursor GameObjects. /// One that is on Holograms and another off Holograms. /// Shows the appropriate Cursor when a Hologram is hit. /// Places the appropriate Cursor at the hit position. /// Matches the Cursor normal to the hit surface. /// </summary> public class CursorManager : Singleton<CursorManager> { [Tooltip("Drag the Cursor object to show when it hits a hologram.")] public GameObject CursorOnHolograms; [Tooltip("Drag the Cursor object to show when it does not hit a hologram.")] public GameObject CursorOffHolograms; void Awake() { if (CursorOnHolograms == null || CursorOffHolograms == null) { return; } // Hide the Cursors to begin with. CursorOnHolograms.SetActive(false); CursorOffHolograms.SetActive(false); } void Update() { /* TODO: DEVELOPER CODING EXERCISE 2.b */ if (GazeManager.Instance == null || CursorOnHolograms == null || CursorOffHolograms == null) { return; } if (GazeManager.Instance.Hit) { // 2.b: SetActive true the CursorOnHolograms to show cursor. CursorOnHolograms.SetActive(true); // 2.b: SetActive false the CursorOffHolograms hide cursor. CursorOffHolograms.SetActive(false); } else { // 2.b: SetActive true CursorOffHolograms to show cursor. CursorOffHolograms.SetActive(true); // 2.b: SetActive false CursorOnHolograms to hide cursor. CursorOnHolograms.SetActive(false); } // 2.b: Assign gameObject‘s transform position equals GazeManager‘s instance Position. gameObject.transform.position = GazeManager.Instance.Position; // 2.b: Assign gameObject‘s transform up vector equals GazeManager‘s instance Normal. gameObject.transform.up = GazeManager.Instance.Normal; } }
接下来可以再次发布部署一次APP,看一下当光标移动到全息图上时光标的变化。
全息图的凝视反馈:
步骤:
- 在 Hierarchy 面板中, 选择 Managers 对象.
- 在右侧 Inspector 面板中, 点击 Add Component 按钮.
- 在搜索框中输入 Interactible Manager. 选择此结果.
- 在 Hierarchy 面板中, 选择AstroMan 对象.
- 在右侧 Inspector 面板中, 点击 Add Component 按钮.
- 在搜索框中输入 Interactible . 选择此结果.
接下来你需要编辑 InteractibleManager.cs 和 Interactible.cs 两个代码文件来实现以下功能 :
- 在 InteractibleManager.cs 脚本中,获取凝视射线击中的点和保存碰撞对象 collided GameObject.
- 当凝视交点在你可以交互的全息对象上时发送 GazeEntered message
- 当凝视交点离开你可以交互的全息对象上时发送 GazeExited message
- 在Interactible.cs 代码中处理GazeEntered和GazeExited回调。
using HoloToolkit; using UnityEngine; /// <summary> /// InteractibleManager keeps tracks of which GameObject /// is currently in focus. /// </summary> public class InteractibleManager : Singleton<InteractibleManager> { public GameObject FocusedGameObject { get; private set; } private GameObject oldFocusedGameObject = null; void Start() { FocusedGameObject = null; } void Update() { /* TODO: DEVELOPER CODING EXERCISE 2.c */ oldFocusedGameObject = FocusedGameObject; if (GazeManager.Instance.Hit) { RaycastHit hitInfo = GazeManager.Instance.HitInfo; if (hitInfo.collider != null) { // 2.c: Assign the hitInfo‘s collider gameObject to the FocusedGameObject. FocusedGameObject = hitInfo.collider.gameObject; } else { FocusedGameObject = null; } } else { FocusedGameObject = null; } if (FocusedGameObject != oldFocusedGameObject) { ResetFocusedInteractible(); if (FocusedGameObject != null) { if (FocusedGameObject.GetComponent<Interactible>() != null) { // 2.c: Send a GazeEntered message to the FocusedGameObject. FocusedGameObject.SendMessage("GazeEntered"); } } } } private void ResetFocusedInteractible() { if (oldFocusedGameObject != null) { if (oldFocusedGameObject.GetComponent<Interactible>() != null) { // 2.c: Send a GazeExited message to the oldFocusedGameObject. oldFocusedGameObject.SendMessage("GazeExited"); } } } }
using UnityEngine; /// <summary> /// The Interactible class flags a Game Object as being "Interactible". /// Determines what happens when an Interactible is being gazed at. /// </summary> public class Interactible : MonoBehaviour { [Tooltip("Audio clip to play when interacting with this hologram.")] public AudioClip TargetFeedbackSound; private AudioSource audioSource; private Material[] defaultMaterials; void Start() { defaultMaterials = GetComponent<Renderer>().materials; // Add a BoxCollider if the interactible does not contain one. Collider collider = GetComponentInChildren<Collider>(); if (collider == null) { gameObject.AddComponent<BoxCollider>(); } EnableAudioHapticFeedback(); } private void EnableAudioHapticFeedback() { // If this hologram has an audio clip, add an AudioSource with this clip. if (TargetFeedbackSound != null) { audioSource = GetComponent<AudioSource>(); if (audioSource == null) { audioSource = gameObject.AddComponent<AudioSource>(); } audioSource.clip = TargetFeedbackSound; audioSource.playOnAwake = false; audioSource.spatialBlend = 1; audioSource.dopplerLevel = 0; } } /* TODO: DEVELOPER CODING EXERCISE 2.d */ void GazeEntered() { for (int i = 0; i < defaultMaterials.Length; i++) { // 2.d: Uncomment the below line to highlight the material when gaze enters. defaultMaterials[i].SetFloat("_Highlight", .25f); } } void GazeExited() { for (int i = 0; i < defaultMaterials.Length; i++) { // 2.d: Uncomment the below line to remove highlight on material when gaze exits. defaultMaterials[i].SetFloat("_Highlight", 0f); } } void OnSelect() { for (int i = 0; i < defaultMaterials.Length; i++) { defaultMaterials[i].SetFloat("_Highlight", .5f); } // Play the audioSource feedback when we gaze and select a hologram. if (audioSource != null && !audioSource.isPlaying) { audioSource.Play(); } /* TODO: DEVELOPER CODING EXERCISE 6.a */ // 6.a: Handle the OnSelect by sending a PerformTagAlong message. } }
接下来你可以再一次发布部署到Hololens上查看当凝视点击中全息图时,全息图的反馈状态。
章节3 定位技术
目标:更容易定位到全息对象,稳定且自然到头部移动
步骤:
- 在 Hierarchy 面板中, 选择 Managers 对象.
- 在右侧 Inspector 面板中, 点击 Add Component 按钮.
- 在搜索框中输入 Gaze Stabilizer. 选择此结果.
接下来需要更新GazeManager 脚本
- 用VS打开GazeManager脚本 .
- 粘贴以下代码到GazeManager.cs
using HoloToolkit; using UnityEngine; /// <summary> /// GazeManager determines the location of the user‘s gaze, hit position and normals. /// </summary> public class GazeManager : Singleton<GazeManager> { [Tooltip("Maximum gaze distance for calculating a hit.")] public float MaxGazeDistance = 5.0f; [Tooltip("Select the layers raycast should target.")] public LayerMask RaycastLayerMask = Physics.DefaultRaycastLayers; /// <summary> /// Physics.Raycast result is true if it hits a Hologram. /// </summary> public bool Hit { get; private set; } /// <summary> /// HitInfo property gives access /// to RaycastHit public members. /// </summary> public RaycastHit HitInfo { get; private set; } /// <summary> /// Position of the user‘s gaze. /// </summary> public Vector3 Position { get; private set; } /// <summary> /// RaycastHit Normal direction. /// </summary> public Vector3 Normal { get; private set; } private GazeStabilizer gazeStabilizer; private Vector3 gazeOrigin; private Vector3 gazeDirection; void Awake() { /* TODO: DEVELOPER CODING EXERCISE 3.a */ // 3.a: GetComponent GazeStabilizer and assign it to gazeStabilizer. gazeStabilizer = GetComponent<GazeStabilizer>(); } private void Update() { // 2.a: Assign Camera‘s main transform position to gazeOrigin. gazeOrigin = Camera.main.transform.position; // 2.a: Assign Camera‘s main transform forward to gazeDirection. gazeDirection = Camera.main.transform.forward; // 3.a: Using gazeStabilizer, call function UpdateHeadStability. // Pass in gazeOrigin and Camera‘s main transform rotation. gazeStabilizer.UpdateHeadStability(gazeOrigin, Camera.main.transform.rotation); // 3.a: Using gazeStabilizer, get the StableHeadPosition and // assign it to gazeOrigin. gazeOrigin = gazeStabilizer.StableHeadPosition; UpdateRaycast(); } /// <summary> /// Calculates the Raycast hit position and normal. /// </summary> private void UpdateRaycast() { /* TODO: DEVELOPER CODING EXERCISE 2.a */ // 2.a: Create a variable hitInfo of type RaycastHit. RaycastHit hitInfo; // 2.a: Perform a Unity Physics Raycast. // Collect return value in public property Hit. // Pass in origin as gazeOrigin and direction as gazeDirection. // Collect the information in hitInfo. // Pass in MaxGazeDistance and RaycastLayerMask. Hit = Physics.Raycast(gazeOrigin, gazeDirection, out hitInfo, MaxGazeDistance, RaycastLayerMask); // 2.a: Assign hitInfo variable to the HitInfo public property // so other classes can access it. HitInfo = hitInfo; if (Hit) { // If raycast hit a hologram... // 2.a: Assign property Position to be the hitInfo point. Position = hitInfo.point; // 2.a: Assign property Normal to be the hitInfo normal. Normal = hitInfo.normal; } else { // If raycast did not hit a hologram... // Save defaults ... // 2.a: Assign Position to be gazeOrigin plus MaxGazeDistance times gazeDirection. Position = gazeOrigin + (gazeDirection * MaxGazeDistance); // 2.a: Assign Normal to be the user‘s gazeDirection. Normal = gazeDirection; } } }
章节4 方向指示器
给光标添加一个方向箭头使得用户更容易找到全息对象。
步骤:
- 点击Hierarchy 面板下的AstroMan 对象然后点击小箭头展开它
- 选中AstroMan下的DirectionalIndicator.
- 在右侧的 Inspector面板中点击Add Component 按钮.
- 在搜索框输入Direction Indicator. 选择此结果.
- 此时拖拽Hierarchy面板下的Cursor 对象 到右侧Inspector面板下Cursor属性中.
- 在 Project 面板下, 拖拽 Holograms 文件夹下的 DirectionalIndicator 资源到右侧Inspector中的Directional Indicator 属性里
- 部署发布项目
- 看方向指示器如何帮助你找到宇航员
章节5 广告牌
我们使用一个广告牌来使得全息对象始终面向用户
- 在 Hierarchy 面板中, 选择 AstroMan 对象.
- 在右侧的 Inspector面板中点击Add Component 按钮.
- 在搜索框输入Billboard. 选择此结果.
- 在Inspector面板中 将Pivot Axis属性设置为Y.
- 现在可以发布到Hololens上看看效果
- 看看全息图是不是一直都面向你,无论你怎么转换视角
在做接下来的教程时先把 AstroMan 中的Billboard 脚本删掉
章节6 追随标签
使用追随标签可以使得我们的全息对象追随我们到房间的任何位置。
追随全息对象的设计应遵循以下原则:
1 全息内容应该在视角范围内一眼就可以看到
2全息内容不能显示在用户前进路上
3 头部锁定内容是不舒服的
我们可以想象这个Tag-along全息对象一直保持在我们视角的边缘,无论我们走到哪里,我们都可以一眼就看到它。
步骤:
- 在 Hierarchy 面板中, 选择 Managers 对象.
- 在右侧 Inspector 面板中, 点击 Add Component 按钮.
- 在搜索框中输入 Gesture Manager. 选择此结果.
接下来将使用SimpleTagalong.cs 文件,它会做到:
- 确定 Tag-Along 对象是否在摄像机边界内.
- 如果不在视椎体内, 定位 Tag-Along 对象部分到摄像机到视椎体内.
- 否则, 定位 Tag-Along 对象到离用户固定距离的位置上。
接下来要做:
- 在 Holograms 文件夹下找到 Tagalong asset并点击.
- 在右侧 Inspector面板中, 上方有个Tag 下拉列表,点击 Add Tag ….
- 点击+ ,然后将 Tag 0 命名为 TagAlong.
- 在 Holograms 文件夹下点击 Tagalong asset然后点击右侧Inspector面板中的Tag dropdown.
- 选择 TagAlong 标签.
- 我们必须编辑 Interactible.cs 脚本 发送信息到 InteractibleAction.
using UnityEngine; /// <summary> /// The Interactible class flags a Game Object as being "Interactible". /// Determines what happens when an Interactible is being gazed at. /// </summary> public class Interactible : MonoBehaviour { [Tooltip("Audio clip to play when interacting with this hologram.")] public AudioClip TargetFeedbackSound; private AudioSource audioSource; private Material[] defaultMaterials; void Start() { defaultMaterials = GetComponent<Renderer>().materials; // Add a BoxCollider if the interactible does not contain one. Collider collider = GetComponentInChildren<Collider>(); if (collider == null) { gameObject.AddComponent<BoxCollider>(); } EnableAudioHapticFeedback(); } private void EnableAudioHapticFeedback() { // If this hologram has an audio clip, add an AudioSource with this clip. if (TargetFeedbackSound != null) { audioSource = GetComponent<AudioSource>(); if (audioSource == null) { audioSource = gameObject.AddComponent<AudioSource>(); } audioSource.clip = TargetFeedbackSound; audioSource.playOnAwake = false; audioSource.spatialBlend = 1; audioSource.dopplerLevel = 0; } } /* TODO: DEVELOPER CODING EXERCISE 2.d */ void GazeEntered() { for (int i = 0; i < defaultMaterials.Length; i++) { // 2.d: Uncomment the below line to highlight the material when gaze enters. defaultMaterials[i].SetFloat("_Highlight", .25f); } } void GazeExited() { for (int i = 0; i < defaultMaterials.Length; i++) { // 2.d: Uncomment the below line to remove highlight on material when gaze exits. defaultMaterials[i].SetFloat("_Highlight", 0f); } } void OnSelect() { for (int i = 0; i < defaultMaterials.Length; i++) { defaultMaterials[i].SetFloat("_Highlight", .5f); } // Play the audioSource feedback when we gaze and select a hologram. if (audioSource != null && !audioSource.isPlaying) { audioSource.Play(); } /* TODO: DEVELOPER CODING EXERCISE 6.a */ // 6.a: Handle the OnSelect by sending a PerformTagAlong message. SendMessage("PerformTagAlong"); } }
InteractibleAction.cs脚本在您注视全息图时执行自定义操作。 让我们更新它与标签一起使用。
- Complete the coding exercise or change it to this:
- 在 Hierarchy 面板的顶部的搜索框内输入ChestButton_Center 然后选择它.
- 在右侧Inspector 面板下点击 Add Component 按钮.
- 在搜索框内输入 Interactible Action. 并选择
- 在project面板下 Holograms 文件夹中找到 Tagalong asset.
- 选中Hierarchy面板下的 ChestButton_Center 对象. 拖拽 TagAlong 对象从 Project 面板到右侧 Inspector 面板中到 Object to TagAlong property.
- Double click the InteractibleAction script to open it in Visual Studio.
using HoloToolkit; using UnityEngine; /// <summary> /// InteractibleAction performs custom actions when you gaze at the holograms. /// </summary> public class InteractibleAction : MonoBehaviour { [Tooltip("Drag the Tagalong prefab asset you want to display.")] public GameObject ObjectToTagAlong; void PerformTagAlong() { if (ObjectToTagAlong == null) { return; } // Recommend having only one tagalong. GameObject existingTagAlong = GameObject.FindGameObjectWithTag("TagAlong"); if (existingTagAlong != null) { return; } GameObject instantiatedObjectToTagAlong = GameObject.Instantiate(ObjectToTagAlong); instantiatedObjectToTagAlong.SetActive(true); /* TODO: DEVELOPER CODING EXERCISE 6.b */ // 6.b: AddComponent Billboard to instantiatedObjectToTagAlong. // So it‘s always facing the user as they move. instantiatedObjectToTagAlong.AddComponent<Billboard>(); // 6.b: AddComponent SimpleTagalong to instantiatedObjectToTagAlong. // So it‘s always following the user as they move. instantiatedObjectToTagAlong.AddComponent<SimpleTagalong>(); // 6.b: Set any public properties you wish to experiment with. } }
发布部署到设备上查看
原文链接https://developer.microsoft.com/en-us/windows/holographic/holograms_210
如有翻译上的错误请指正。谢谢
微软Hololens学院教程-Hologram Gaze(凝视)