27 June 2017

A HoloLens helper class to get a position dead ahead of the user–on a physical object or at a max distance

This is a little tidbit I use in a lot of apps, for instance in the CubeBouncer and for floating info screens in my other apps. Basically I want to know a position dead ahead of the user, at a certain maximum distance, or closer by if the user is looking at a physical object that is closer by. Think of an invisible ray coming out of the HoloLens – I want to have a point where it strikes a physical object – and if there is no such thing within a certain maximum distance, I want a point along that ray at a maximum distance.

I made a little helper class for that, and it’s called LookingDirectionHelpers

using HoloToolkit.Unity.InputModule;
using HoloToolkit.Unity.SpatialMapping;
using UnityEngine;

namespace HoloToolkitExtensions.Utilities
{
    public static class LookingDirectionHelpers
    {
        public static Vector3 GetPostionInLookingDirection(float maxDistance = 2, 
            BaseRayStabilizer stabilizer = null )
        {
            RaycastHit hitInfo;
            var headReady = stabilizer != null
                ? stabilizer.StableRay
                : new Ray(Camera.main.transform.position, Camera.main.transform.forward);

            if (SpatialMappingManager.Instance != null &&
                Physics.Raycast(headReady, out hitInfo, maxDistance,
SpatialMappingManager.Instance.LayerMask)) { return hitInfo.point; } return CalculatePositionDeadAhead(maxDistance); } public static Vector3 CalculatePositionDeadAhead(float distance = 2, BaseRayStabilizer stabilizer = null) { return (stabilizer != null ? stabilizer.StableRay.origin + stabilizer.StableRay.direction : Camera.main.transform.position + Camera.main.transform.forward) .normalized * distance; } } }

Although it’s a small thing, it actually does quite a lot. If you call GetPostionInLookingDirection

  • It first tries to determine a so-called head ray. This can either come from the stabilizer or be directly calculated from the location and angle of the camera (that is, your head). I would recommend feeding it a stabilizer, as that makes for getting a much more reliable location.
  • If it actually finds a hit, it returns that point
  • If it does not, it uses CalculatePositionDeadAhead to, well, calculate a position dead ahead. It takes once again either the stabilizer head ray or calculates one from the camera, then normalizes it (i.e. makes it’s length 1) and then multiplies it with the desired distance. This effectively gives a point distance meters right before the user’s eyes.

This script requires the presence of a SpatialMappingManager prefab, for that’s the only way to find out which Unity layer contains the spatial mesh. If you want to call this script using a stabilizer (and I think you should), the InputManager should be present as well, as that will create a GazeManager singleton, which contains the stabilizer. So you can call this helper class like this:

var pos = LookingDirectionHelpers.GetPostionInLookingDirection(2.0f, GazeManager.Instance.Stabilizer);

And that will return you a point at either a Spatial Mesh, or at 2 meters distance from the user.

Although and the code involved is not very voluminous, I have gone all the way and made and – albeit pretty lame – minimalist demo for it that you can download here. This is based upon a HoloToolkit based setup as described here. All it does it, when you move around, is print the location onto the debug log. So this will only work in the Unity editor, on the HoloLens emulator, or on an app running in debug mode on an actual HoloLens – but you won’t see much happening on the device itself, just in debug windows on your screen.

image

But it shows how it works and can be used, and that is the point. Later in this blog we will see a better application for this.

No comments: