Chapter0 - 前言
最近在根據微軟的HoloLens教程學習HoloLens的基礎,昨天突發奇想用電腦現有的mmd模型、動作資料加入Unity中然後部署到HoloLens進行基于環境的放置與跳舞操作。(老師不在實驗室系列)百度了一下之後找到了日本大佬的MMD4Mecanim插件,可以将MMD模型以及音樂和動作導入到Unity中,便開始進行部署。
Chapter1 - 基本工作與環境
- 使用的工具包括 Unity 2018.1 , Visual Studio 2017,MMD4Mecanim插件,HoloLens emulator,HoloLens。
- MMD4Mecanim下載下傳位址,同時也是作者的官網。
- 想要導入的MMD模型檔案,動作檔案與比對的音樂檔案(本文未獲得作者允許,故不提供模型與動作下載下傳連結)。
-
其他東西百度很快能找到。
[注] 若隻是要導入MMD模型到Unity隻需要Unity和插件就行。
Chapter2 - 導入模型到Unity
- 建立一個Unity項目,注意選擇3D。
- 在資源欄右鍵添加Unity Package,将下載下傳的插件中的 MMD4Mecanim.unitypackage 導入Asset當中。
- 将想要導入的MMD模型檔案直接拖入Asset當中,以及需要的動作資料檔案和音樂。
- 導入後點選MMD檔案夾可以看到插件自動轉化的.MMD4Mecanim檔案,選擇一個點選,在右方Inspector面闆最下方選中所有協定,同意。
- 在下一個界面中,将動作檔案.vmd拖入相應的vmd處,單擊process。此時插件會開始自動導入模型檔案然後變成Unity檔案。
- 有時候模型有多個元件,可隻導入人物模型。
- 導入完成後,拖拽生成的模型到Hierarchy中,模型導入完成。
Chapter3 - 添加動作與音樂
- 在模型檔案夾下右鍵 Create > Animator Controller 添加一個新的動作控制器,輕按兩下打開;
- 将模型中的vmd檔案拖拽到控制器中與Entry連接配接;
- 在Hierarchy中單擊模型,在右方 Animator 中找到 Controller ;在Hierarchy中單擊模型,在右方 Animator 中找到 Controller ;
- 單擊齒輪選擇之前建立的動作控制器,此時點選播放按鈕,模型已經可以開始跳舞了;
- 在Hierarchy中單擊模型,在Inspector最下方單擊 Add Component 。選擇 Audio > Audio Source,将音樂檔案拖入AudioClip中,下方Volume可以調節音量;
- 因為實在HoloLens中實作,故将Spatial Blend調至3D,聲音最大距離也可随意修改。
Chapter4 - 添加光标,地圖以及放置代碼
-
在微軟HoloLens官網教程中下載下傳素材檔案;
HoloLens教程素材
- 在Unity項目的Asset中建立檔案夾 101-Asset 存放素材,導入 Origami 中的 Asset 檔案;
- 将 Hologram 中的 Cursor 以及 Spatial Mapping 添加入Hierarchy中;
- 單擊MMD模型,右鍵建立一個方塊來作為模型的底座;
- 調整方塊位置以及模型大小,依照自我喜好調整,cursor是用來作為凝視點光标的,改變模型大小的同時也可以修改cursor的大小;
- 調整 Main Camera 到合适的位置,能夠拍攝到模型,将 Clear Flags 改為 Solid Color, Background 改為純黑色;
- 在Asset中建立檔案夾 Script 用于存放代碼;
- 在 script 中右鍵建立 C# Script ,命名為 WorldCursor,輕按兩下在vs中打開,添加如下代碼,特别注意,命名要正确:
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 thecursor 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;
}
}
}
- 完成後儲存,将腳本拖拽到Hierarchy中的cursor上,成功完成後cursor的component中會有該腳本;
- 在script中右鍵建立C# script,命名為GazeGestureManager,輕按兩下後添加如下代碼:
using UnityEngine;
using UnityEngine.XR.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.Tapped += (args) =>
{
// Send an OnSelect message to the focused object and its ancestors.
if (FocusedObject != null)
{
FocusedObject.SendMessageUpwards("OnSelect", SendMessageOptions.DontRequireReceiver);
}
};
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();
}
}
}
- 拖拽該腳本到MMD模型上;
- 建立C# Script 命名為 TapToPlaceParent ,添加如下代碼:
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;
}*/
SpatialMapping.Instance.DrawVisualMeshes = true; //添加
}
// 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;*/
this.transform.parent.LookAt(Camera.main.transform); //添加
Quaternion toQuat = this.transform.parent.localRotation; //
toQuat.x = 0;toQuat.z = 0; //
this.transform.parent.rotation = toQuat; //添加
}
}
}
}
[注] 該代碼中相對于微軟源碼有兩處代碼進行了修改,第一處是用于拿起模型等待放置時顯示地圖的網格,微軟源碼是拿起時顯示網格,放下隐藏網格。我改為了始終顯示網格,可根據個人需要選擇代碼。第二處為了使模型正面面對相機。
- 儲存,将腳本拖拽到MMD模型下屬的 Cube 上。
- 腳本基本完成,開始進行build。
Chapter5 - Building Setting
- 開始進入build環節,在 Edit > Project Setting > Quality 中将品質改為最低;
- 點選 File > Build Setting 選擇 Universal Windows Platform ,點選 Swich Platform ,然後點選 Player Settings ,在 Other Settings 中把 Scripting Backend 改為 .NET 。在 XR Settings 中勾選 Visual Reality Supported ;
- 在 Publishing settings 中 Capability 中勾選 SpatialPerception;
- 設定如圖,SDK和vs可以直接預設,點選 Build ,建立檔案夾 App 然後build;
- 等待完成後打開App檔案夾,輕按兩下.sln檔案,在vs上運作。
Chapter6 - vs中運作模拟器或部署到裝置
- 配置如圖所示,部署到虛拟機;
- 直接點選或 Ctrl + F5;
- 部署完成後光标移至底座然後點選就可在環境中進行放置。
運作結果: