Ground Plane API Overview

The Ground Plane feature detects and tracks planar surfaces and Anchors from hit tests in the environment.

With Ground Plane, you can place any digital content on horizontal surfaces with the use of anchors that are grounded to the plane or in mid-air. Place digital content with the Anchor Target Observer which is responsible for both hitTests to detect surfaces and for creating 6 DoF (degrees of freedom) anchor points in world space. The Anchor Observation will continually produce information from the anchor points to the state as the world space grows and changes in a Ground Plane session. The world space is provided by the Device Pose Observer and must be enabled to use this feature.

General Setup

Please see the Vuforia Engine Lifecycle for a general introduction to the Vuforia Engine lifecycle as the Engine is required for creating and using Observers.

Create an Anchor Observer

To successfully track and create anchors in environments, you must first create and activate an Anchor Target Observer. This is achieved by associating the Device Pose Observer to the anchor configuration. To create a Device Pose Observer, please refer to Device Tracking

// Create an Anchor config
VuAnchorObserverConfig anchorObserverConfig = vuAnchorObserverConfigDefault();
anchorObserverConfig.devicePoseObserver = devicePoseObserver; // dependency

// Create an Anchor Observer
VuObserver* anchorObserver = { NULL };
vuEngineCreateAnchorObserver(engine, &anchorObserver, anchorObserverConfig, NULL);

The above code snippet first creates an anchor configuration with default values. The Device Pose Observer is mandatory to create and activate anchors. The Anchor Target Observer is activated on creation by default.

After creating your Observer, you can start the Engine and wait a little for the Device Pose Observer to initialize and begin tracking the world space. Then, you can create an anchor from the Anchor Target Observer and render content to that location.

Create anchor from Pose

// Create an anchor
VuAnchorCreationConfig anchorConfig = {};
// set pose just using translation for a world-aligned anchor
anchorConfig.pose = vuMatrix44FTRSMatrix(myTrans, 0.0f, vuIdentityVector3F(), vuIdentityVector3F()); 

int32_t anchorId = { 0 };
vuAnchorObserverCreateAnchor(anchorObserver, &anchorId, anchorConfig);

Alternatively, create anchors directly from ray casting using the VuAnchorCreationHitTestConfig as described below.

Create anchor from hitTest

Use ray casting and user interactions to identify suitable surfaces by ray casting on horizontal planes in the world space. This is usually performed by a user interaction on the screen. A hit test will approximate a deviceHeight in meters between the device and the plane:

VuAnchorCreationHitTestConfig anchorWithHitTestConfig { hitTest };

int32_t anchorId = 0;
vuAnchorObserverCreateAnchorWithHitTest(observer, &anchorWithHitTestConfig, &anchorId);

The hitTest cannot be performed before or during initialization of the Device Pose Observer as indicated by its status info VuDevicePoseObservationStatusInfo()

NOTE: Hit testing should use the same State as the frame rendering for the vuHitTestGetPose to be accurate.

Create an anchor mid-air

To create an anchor above a ground plane, you can let user interactions, such as tapping at the screen, trigger an anchor creation from pose:

 // Retrieve latest cached device pose from a custom method
auto latestDevicePoseData = getLatestDevicePoseData();
const VuMatrix44F& latestDevicePose = latestDevicePoseData.mPose;

auto anchorConfig = vuAnchorCreationConfigDefault();
anchorConfig.pose = latestDevicePose;

int32_t anchorId = 0;
vuAnchorObserverCreateAnchor(observer, &anchorConfig, &anchorId);

Fusion Provider Platform

The VuHitTestConfig depends on the active Fusion provider of the device. It means vuPlatformControllerGetFusionProviderType() will determine if deviceHeight is used or not.

Observation

The Anchor Target Observer produces Observations that is collected in the State. Get the anchor observations from the State or from the managed anchors from an Anchor Target Observer.

Creation of Observation list

// create observation list
VuObservationList* obsList = { NULL };
vuObservationListCreate(&obsList);

// Get and parse anchor target observations list
vuStateGetAnchorObservations(state,obsList);

int32_t listSize = 0;
vuObservationListGetSize(obsList, &listSize);

Then, parse the observation list to get status info on the anchor target(s).

// Parse the anchor list
for (int i = 0; i < listSize; i++)
{
    VuObservation* obs = { NULL };
    vuObservationListGetElement(obsList, i, &obs);

    VuPoseInfo poseInfo;
    vuObservationGetPoseInfo(obs, &poseInfo);

    if (poseInfo.poseStatus != OBSERVATION_POSE_STATUS_NO_POSE)
    {
        // Do something with poseInfo
    }
}

You can also replace the vuObservationListCreate and vuObservationGetPoseInfo with the following to get the pose from a hitTest.

vuHitTestListCreate(VuHitTestList** list);
vuHitTestGetPose(const VuHitTest* hitTest, VuMatrix44F* pose);

Destroy Observer and Observation

Destroy the Observer and Observation list after use to free up memory.

Destroy an Anchor Observer.

vuAnchorObserverDestroyAnchor(observer, anchorId);
// Or destroy all anchors
vuAnchorObserverDestroyAnchors(observer);

Destroy the hitTest list

vuHitTestListDestroy(VuHitTestList* list);