酱学堂|Hololens 开发入门(hololens开发教程)
开发要求
Hololens 运行与Win10,应用程序是与UWP(通用windows开发平台)构建的,开发Hololens 这样的全息体验对电脑的配置要求也是相当高的。
硬件配置:
1.64位Windows 10专业版,企业版或教育版(家庭版不支持Hyper-V)
2.64位CPU
3.8GB以上的RAM
4.在BIOS中,必须具备以下功能:
-
硬件辅助虚拟化
二级地址转换(SLAT)
基于硬件的数据执行保护(DEP)
5.对于GPU,需DirectX 11.0或更高版本,WDDM 1.2驱动程序或更高版本
关于Hyper-V,它是微软的一款虚拟化产品,采用类似Vmware和Citrix开源Xen一样的基于hypervisor的技术。
第二部分:安装
1.启用虚拟化,即在PC上启用硬件虚拟化。
详细步骤请看:
https://msdn.microsoft.com/library/windows/apps/jj863509(v=vs.105).aspx
2.启用Hyper-V
3.安装Visual Studio 2017或Visual Studio 2015 Update3(https://developer.microsoft.com/en-us/windows/downloads)
4.安装HoloLens emulator(https://developer.microsoft.com/en-us/windows/mixed-reality/hololens_emulator_archive)
5.安装Unity(https://unity3d.com/cn/get-unity/download)
关于详细的安装视频,可以看看老外的这个教程:
不过不知道什么原因,视频腾讯过不了所以大家可以在优酷看,或者点击阅读原文
视频:
第三部分:关于Hololens 模拟器
HoloLens模拟器允许你在没有Hololens的情况下在PC上测试全息应用程序,并附带Hololens开发工具集。仿真器使用Hyper-V虚拟机。
关于输入:
-
向前,向后,向左和向右走 – 使用键盘上的W,A,S和D键或Xbox控制器上的左键。
查找向上,向下,向左和向右 – 单击并拖动鼠标,使用键盘上的箭头键或Xbox控制器上的右键。
空气敲击手势 – 右键单击鼠标,按键盘上的Enter键,或使用Xbox控制器上的A按钮。
绽放手势 – 按键盘上的Windows键或F2键,或按Xbox控制器上的B按钮。手动移动滚动 – 按住Alt键,按住鼠标右键,向上/向下拖动鼠标,或者在Xbox控制器中按住右侧触发器和A按钮,向上和向下移动右侧手柄。
关于工具栏:
在主窗口的右侧,您将找到仿真器工具栏。工具栏包含以下按钮:
-
关闭:关闭模拟器。
最小化:最小化仿真器窗口。
人工输入:鼠标和键盘用于模拟模拟器的人工输入。
键盘和鼠标输入:键盘和鼠标输入直接传递到HoloLens操作系统作为键盘和鼠标事件,就像连接了蓝牙键盘和鼠标一样。
适合屏幕:适合模拟器屏幕。
缩放:使仿真器越来越大。
帮助:打开模拟器帮助。
打开设备门户:在仿真器中打开HoloLens OS的Windows设备门户。
工具:打开“ 其他工具 ”窗格。
开发—-Hello,HoloLens!
首先我们在unity中新建一个项目,接着添加一个简单的3D模型进行测试,比如:
接着部署Windows Store
接着,点击Build,生成VS项目:
启动VS:
一般默认情况下,从Unity导出的UWP应用程序在任何Windows 10设备上运行。由于HoloLens是不同的,应用程序应该利用仅在HoloLens上可用的功能。为此,您需要在Visual Studio TargetDeviceFamily中的Package.appxmanifest文件中设置为“Windows.Holographic” ,如下:
接下来,就可以运行啦:
第五部分:输入事件总结
1
GAZE凝视操作
在Hololens中,使用的是用户的头部位置与方向来gaze,而不是眼睛。
示例代码(PS:核心在于RayCast):
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();
}
// 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;
}
}
}
2
手势输入
示例代码:
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 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();
}
}
}
Update方法会持续检查是否有任何对象被注视并将对象设置为焦点,以便在点击时向对象发送一个轻击的事件。GestureRecognizer负责识别用户的手势。
3
语音输入
示例代码:
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Windows.Speech;
public class SpeechManager : MonoBehaviour
{
KeywordRecognizer keywordRecognizer = null;
Dictionarykeywords = new Dictionary();
// Use this for initialization
void Start()
{
keywords.Add(“Reset world”, () =>
{
// Call the OnReset method on every descendant object.
this.BroadcastMessage(“OnReset”);
});
keywords.Add(“Drop Object”, () =>
{
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();
}
}
}
4
.音频输入
示例代码:
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.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(“Impact”);
rollingClip = Resources.Load(“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();
// 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();
}
}
}
OnCollisionEnter,OnCollisionStay而OnCollisionExit事件确定何时开始播放音频剪辑,是否继续音频剪辑以及何时停止播放音频剪辑。
AR酱原创,转载务必注明
微信号AR酱(ARchan_TT)
AR酱官网:www.arjiang.com