As I described earlier, the Holotoolkit project is a set of tools that Microsoft built on Unity's underlying API encapsulation to help us quickly use unity to integrate and develop HoloLens applications.
This article mainly through the source study of spatial mapping implementation, about the underlying API details, please read my previous article: HoloLens Development Notes-unity of spatial mapping spatial mapping
0X00 Component Structure
There is a lot of content in the Spatial mapping directory, where the prefabs directory has pre-built components that we can use directly, and the focus of this article is on the Scripts directory script. The component directory structure is as follows:
This paper focuses on SpatialMappingObserver.cs and SpatialMappingSource.cs, which is the core content of current components.
0x01 SpatialMappingObserver.cs
Source Address: https://github.com/Microsoft/HoloToolkit-Unity/blob/master/Assets/HoloToolkit/SpatialMapping/Scripts/ SpatialMappingObserver.cs
Let's analyze its properties first, as follows:
//number of mesh triangles per cubic metre, controlling mesh quality Public floatTrianglespercubicmeter =500f; //spatial range of current observer detection PublicVector3 extents = Vector3.one *10.0f; //Refresh time interval Public floatTimebetweenupdates =3.5f; //core components for scanning the space plane PrivateSurfaceobserver Observer; //storing a constructed spatial mesh object Privatedictionary<int, gameobject> surfaces =Newdictionary<int, gameobject>(); //surfacedata queue, for generating spatial mesh PrivateQueue<surfacedata> Surfaceworkqueue =NewQueue<surfacedata>(); //to avoid generating too much mesh at the same time, ensure that only one mesh is generated at the same time, and this variable is used to determine if a mesh is being created at the current moment . Private BOOLSurfaceworkoutstanding =false; //used to track when the Observer object was last updated Private floatUpdateTime; //represents the current scan state, running and stopped two states PublicObserverstates Observerstate {Get;Private Set; }
Then analyze its program logic and process:
- The Awake () method is first executed, where the Surfaceobserver object is initialized.
Private void Awake () { new surfaceobserver (); = observerstates.stopped; }
- Next is the start () method, which sets the scope of the scanning space.
Private void Start () { Observer. Setvolumeasaxisalignedbox (Vector3.zero, extents); }
- The Update () method invokes the API to request space surface information or to generate mesh objects based on the current state
Private voidUpdate () {if(Observerstate = =observerstates.running) {//if no mesh is currently generated and there are objects in the surfacedata that need to be mesh-generated if(Surfaceworkoutstanding = =false&& Surfaceworkqueue.count >0) {Surfacedata surfacedata=Surfaceworkqueue.dequeue (); //If you can successfully request a mesh object, the current task status becomes generated in the meshSurfaceworkoutstanding =Observer. Requestmeshasync (Surfacedata, Surfaceobserver_ondataready); } //re-request surfacedata data if no task is currently running and the last update distance is now greater than the time interval Else if(Surfaceworkoutstanding = =false&& (time.time-updatetime) >=timebetweenupdates) {Observer. Update (surfaceobserver_onsurfacechanged); UpdateTime=Time.time; } } }
- The Surfaceobserver_ondataready () event method is used to process mesh object information that is requested by the Surfacedata for subsequent use, such as handling its material effects.
Private voidSurfaceobserver_ondataready (Surfacedata Cookeddata,BOOLOutputwritten,floatelapsedcooktimeseconds) {Gameobject surface; if(Surfaces. TryGetValue (CookedData.id.handle, outsurface)) { //sets the material for the renderer component.Meshrenderer renderer = surface. Getcomponent<meshrenderer>(); Renderer.sharedmaterial=SpatialMappingManager.Instance.SurfaceMaterial;
Whether to render mesh objects renderer.enabled=SpatialMappingManager.Instance.DrawVisualMeshes; if(SpatialMappingManager.Instance.CastShadows = =false) {Renderer.shadowcastingmode=UnityEngine.Rendering.ShadowCastingMode.Off; }} surfaceworkoutstanding=false; }
- The Surfaceobserver_onsurfacechanged () event method is used to process Surfaceobserver obtained spatial surface data for subsequent requests to mesh object operations.
Private voidsurfaceobserver_onsurfacechanged (Surfaceid ID, surfacechange changetype, Bounds Bounds, System.DateTime UpdateTime) {//determine the current scan status if(Observerstate! =observerstates.running) {return; } Gameobject surface; Switch(changetype) { Casesurfacechange.added: Casesurfacechange.updated://detects if the current surface has been scanned if(!surfaces. TryGetValue (Id.handle, outsurface)) { //creates a mesh object that is associated with the current surfaceSurface = Addsurfaceobject (NULL,string. Format ("surface-{0}", Id.handle), transform); Surface. AddComponent<WorldAnchor>(); //joins a surface object to a known space surface dictionarysurfaces. ADD (id.handle, surface); } //request to generate or update the corresponding mesh objectqueuesurfacedatarequest (ID, surface); Break; Casesurfacechange.removed://remove an associated mesh object if(Surfaces. TryGetValue (Id.handle, outsurface)) {surfaces. Remove (Id.handle); Destroy (surface); } Break; } }
Holotoolkit Project Source Code Analysis-Spatial mapping function realization