首先卸奉,進(jìn)行Hololens項(xiàng)目的基本設(shè)置,并添加Spatial Mapping和Spatial Understanding 組件到Hierarchy面板中颖御。Spatial Understanding模型主要暴露了三種類(lèi)型的接口择卦,簡(jiǎn)單平面的拓?fù)洌臻g查詢(xún),物體形狀檢測(cè)秉继。要通過(guò)Spatial Understanding放置游戲?qū)ο蟮綁ι匣蛘咭巫由掀碓耄紫刃枰@取Spaital Understanding掃描到的房間數(shù)據(jù)。
勾選Spatial Understanding 組件的Auto Begin Scanning參數(shù)尚辑,應(yīng)用就會(huì)在啟動(dòng)時(shí)開(kāi)始掃描房間辑鲤。或者通過(guò)RequestBeginScanning()方法來(lái)手動(dòng)開(kāi)始掃描杠茬。無(wú)論使用哪種方法開(kāi)始掃描月褥,都要通過(guò)RequsetFinishScan()方法來(lái)結(jié)束掃描。關(guān)于掃描的進(jìn)度和狀態(tài)瓢喉,可以通過(guò)ScanStates來(lái)獲取宁赤。
public enum ScanStates
{
//當(dāng)前沒(méi)有掃描進(jìn)程
None,
//應(yīng)用已就緒,可以開(kāi)始掃描
ReadyToScan,
//正在掃描中
Scanning,
//已結(jié)束掃描
Finishing,
//掃描進(jìn)程結(jié)束
Done
}
//如果當(dāng)前掃描狀態(tài)是沒(méi)有掃描
if(SpatialUnderstanding.Instace.ScanState == SpatialUnderstanding.ScanState.Done){
//Do
}
SpatialUnderstandingDll.cs開(kāi)始掃描后栓票,SpatialUnderstandingDll.cs腳本就會(huì)被調(diào)用决左,掃描的主要邏輯都會(huì)在這個(gè)腳本中完成。此腳本中的功能主要被分成了三部分:
1 SpatialUnderstandingDllTopology
2 SpatialUnderstandingDllShapes
3 SpatialUnderstandingObjectPlacement
在使用SpatialUnderstandingDll中的功能前走贪,必須首先調(diào)用SpatialUnderstanding_Init()方法進(jìn)行初始化佛猛。以上三個(gè)部分都在單獨(dú)的腳本中實(shí)現(xiàn),SpatialUnderstandingDllTopology.cs坠狡、SpatialUnderstandingDllShape.cs继找、SpatialUnderstandingObjectPlacement.cs,每個(gè)腳本所實(shí)現(xiàn)的功能將在后文中介紹逃沿。SpatialUnderstandingDllTopology.cs此腳本中封裝了關(guān)于當(dāng)前環(huán)境的信息婴渡,它能分析出哪里是墻,哪里是地面凯亮,哪里是天花板等信息边臼。這些信息都存儲(chǔ)在PlaySpaceInfos結(jié)構(gòu)體中。也可以根據(jù)參數(shù)指定數(shù)據(jù)触幼,腳本中提供的方法有:
1 QueryTopology_FindPositionsOnWalls
2 QueryTopology_FindLargePositionsOnWalls
3 QueryTopology_FindLargestWall
4 QueryTopology_FindPositionsOnFloor
5 QueryTopology_FindLargestPositionsOnFloor
6 QueryTopology_FindPositionsSittable
具體參數(shù)可以查看腳本源碼。以下是一個(gè)簡(jiǎn)單示例究飞,查詢(xún)環(huán)境中符合條件的墻的數(shù)量置谦。
//定義存儲(chǔ)查詢(xún)結(jié)果的數(shù)組
private SpatialUnderstandingDllTopology.TopologyResult[] resultsTopology = new SpatialUnderstandingDllTopology.TopologyResult;
public void Query_Topology_FindPositionOnWall()
{
// 確定當(dāng)前SpatialUnderstanding組件狀態(tài)為可用。
if (!SpatialUnderstanding.Instance.AllowSpatialUnderstanding){
return;
}
// 定義參數(shù)亿傅,分別是墻面的最小高度媒峡,最小寬度,最高點(diǎn)和地面的距離葵擎,最后一個(gè)我也不知道..
float minHeightOfWallSpace = 0.5f;
float minWidthOfWallSpace = 0.75f;
float minHeightAboveFloor = 1.25f;
float minFacingClearance = 1.5f;
// 在內(nèi)存中掛起resultTopology谅阿,避免內(nèi)存地址變化
IntPtr resultsTopologyPtr = SpatialUnderstanding.Instance.UnderstandingDLL.PinObject(resultsTopology);
//執(zhí)行查詢(xún)操作并將數(shù)量返回給locationCount
int locationCount = SpatialUnderstandingDllTopology.QueryTopology_FindPositionsOnWalls(
minHeightOfWallSpace, minWidthOfWallSpace, minHeightAboveFloor, minFacingClearance,
resultsTopology.Length, resultsTopologyPtr);
}
SpaitalUnderstandingDllShapes.cs此腳本實(shí)現(xiàn)了查詢(xún)某種形狀的物體的功能。開(kāi)發(fā)者可以指定各個(gè)參數(shù),然后腳本會(huì)根據(jù)參數(shù)签餐,找出環(huán)境中符合參數(shù)的地點(diǎn)寓涨。
//形狀的組件
shapeComponents = new List<ShapeComponent>()
{
new ShapeComponent(
//形狀組件約束
new List<ShapeComponentConstraint>()
{
//定義高度
ShapeComponentConstraint.Create_SurfaceHeight_Between(0.2f, 0.6f),
ShapeComponentConstraint.Create_SurfaceCount_Min(1),
//定義面積
ShapeComponentConstraint.Create_SurfaceArea_Min(0.035f),
}
),
};
AddShape("Sittable", shapeComponents);
以上代碼定義了一個(gè)可以”坐”的區(qū)域。更多示例可以在ShapeDefinition.cs中找到氯檐。SpatialUnderstandingObjectPlacement.cs如果需要放置對(duì)象在指定地點(diǎn)戒良,比如放置一個(gè)方塊在椅子上,就需要使用Solver.PlaceObject()方法了冠摄。這個(gè)方法是一個(gè)查詢(xún)語(yǔ)句糯崎,如果找到符合條件的地點(diǎn),就會(huì)返回一個(gè)1(即true)河泳,否則返回0(false)沃呢。
//解算器_處對(duì)象
public static int Solver_PlaceObject(
//注意,此參數(shù)不是需要放置的對(duì)象的名字拆挥。而是此語(yǔ)句的名字薄霜。
string objectName,
//想要放置的地點(diǎn),具體參數(shù)在ObjectPlacementDefinition結(jié)構(gòu)體中定義
IntPtr placementDefinition,// ObjectPlacementDefinition
//規(guī)則的數(shù)量
int placementRuleCount,
//具體有哪些規(guī)則
IntPtr placementRules, // ObjectPlacementRule
//約束的數(shù)量
int constraintCount,
//具體的約束條件
IntPtr placementConstraints,// ObjectPlacementConstraint
//返回結(jié)果
IntPtr placementResult)
{
return 0;
}
以上語(yǔ)句會(huì)根據(jù)指定參數(shù)竿刁,在環(huán)境中找到符合要求的地點(diǎn)黄锤,并將結(jié)果返回到placementResult中。通過(guò)placementResult即可獲得結(jié)果中的各個(gè)數(shù)據(jù)食拜。關(guān)于放置地點(diǎn)的參數(shù)鸵熟,ObjectPlacementDefinition結(jié)構(gòu)體中定義了9種參數(shù):
public enum PlacementType{
Place_OnFloor,
Place_OnWall,
Place_OnCeiling,
Place_OnShape,
Place_OnEdge,
Place_OnFloorAndCeiling,
Place_RandomInAir,
Place_InMidAir,
Place_UnderPlatformEdge,
};
規(guī)則有3種:
public enum ObjectPlacementRuleType{
Rule_AwayFromPosition,
Rule_AwayFromWalls,
Rule_AwayFromOtherObjects,
};
約束條件有6種:
public enum ObjectPlacementConstraintType{
Constraint_NearPoint,
Constraint_NearWall,
Constraint_AwayFromWalls,
Constraint_NearCenter,
Constraint_AwayFromOtherObjects,
Constraint_AwayFromPoint
};
下面是實(shí)際使用中的示例:
public void CreateOnFloor() {
//對(duì)象位置規(guī)則
List<SpatialUnderstandingDllObjectPlacement.ObjectPlacementRule> placementRules = null;
//對(duì)象位置約束
List<SpatialUnderstandingDllObjectPlacement.ObjectPlacementConstraint> placementConstraints = null;
//一半的大小
float halfDimSize = UnityEngine.Random.Range(0.15f, 0.35f);
SpatialUnderstandingDllObjectPlacement.ObjectPlacementDefinition myPlacementDefinition =
SpatialUnderstandingDllObjectPlacement.ObjectPlacementDefinition.Create_OnFloor(new Vector3(halfDimSize,
halfDimSize, halfDimSize * 2));
if (SpatialUnderstandingDllObjectPlacement.Solver_PlaceObject("place a chen on floor",
SpatialUnderstanding.Instance.UnderstandingDLL.PinObject(myPlacementDefinition),
(placementRules != null) ? placementRules.Count : 0,
((placementRules != null) && (placementRules.Count > 0)) ? SpatialUnderstanding.Instance.UnderstandingDLL.PinObject(placementRules.ToArray()) : IntPtr.Zero,
(placementConstraints != null) ? placementConstraints.Count : 0,
((placementConstraints != null) && (placementConstraints.Count > 0)) ? SpatialUnderstanding.Instance.UnderstandingDLL.PinObject(placementConstraints.ToArray()) : IntPtr.Zero,
SpatialUnderstanding.Instance.UnderstandingDLL.GetStaticObjectPlacementResultPtr()) > 0
) {SpatialUnderstandingDllObjectPlacement.ObjectPlacementResult placementResult = SpatialUnderstanding.Instance.UnderstandingDLL.GetStaticObjectPlacementResult();
//Instantiate chan on result position
GameObject myChan =Instantiate(chan,placementResult.Position,Quaternion.LookRotation(holoCamera.transform.position));
if (myChan != null) {
nofityText.text = "已定位";
}else {
nofityText.text = "未找到合適地點(diǎn)";
}
}
}
以上代碼中,首先設(shè)置規(guī)則和約束條件為null负甸,即不進(jìn)行約束流强。然后將查詢(xún)條件設(shè)置為Create_OnFloor。隨后通過(guò)If語(yǔ)句判斷查詢(xún)是否成功呻待。如果查詢(xún)到可用地點(diǎn)打月,則通過(guò)GetStaticObjectPlacementResult()方法取出查詢(xún)到的結(jié)果。獲取查詢(xún)到的結(jié)果后蚕捉,通過(guò)placementResult.Position獲取符合條件的坐標(biāo)點(diǎn)奏篙。再使用該坐標(biāo)點(diǎn)生成游戲?qū)ο蟆R陨洗a沒(méi)有設(shè)置規(guī)則和約束條件迫淹,只是指定為Floor秘通,所以會(huì)在地面上生成對(duì)象,坐標(biāo)為攝像機(jī)原點(diǎn)敛熬。更多詳細(xì)的示例都在HoloToolkit-Examples/SpatialUnderstanding中肺稀。
查看完整版本: SpatialUnderstanding