543 lines
23 KiB
C++
543 lines
23 KiB
C++
|
|
#include "stdafx.h"
|
|
|
|
#include "BasicHologramMain.h"
|
|
#include "Common/DirectXHelper.h"
|
|
|
|
#include <windows.graphics.directx.direct3d11.interop.h>
|
|
|
|
using namespace BasicHologram;
|
|
using namespace concurrency;
|
|
using namespace Microsoft::WRL;
|
|
using namespace std::placeholders;
|
|
using namespace winrt::Windows::Foundation::Numerics;
|
|
using namespace winrt::Windows::Gaming::Input;
|
|
using namespace winrt::Windows::Graphics::Holographic;
|
|
using namespace winrt::Windows::Graphics::DirectX::Direct3D11;
|
|
using namespace winrt::Windows::Perception::Spatial;
|
|
using namespace winrt::Windows::UI::Input::Spatial;
|
|
|
|
// Loads and initializes application assets when the application is loaded.
|
|
BasicHologramMain::BasicHologramMain(std::shared_ptr<DX::DeviceResources> const& deviceResources) :
|
|
m_deviceResources(deviceResources)
|
|
{
|
|
// Register to be notified if the device is lost or recreated.
|
|
m_deviceResources->RegisterDeviceNotify(this);
|
|
|
|
// If connected, a game controller can also be used for input.
|
|
m_gamepadAddedEventToken = Gamepad::GamepadAdded(bind(&BasicHologramMain::OnGamepadAdded, this, _1, _2));
|
|
m_gamepadRemovedEventToken = Gamepad::GamepadRemoved(bind(&BasicHologramMain::OnGamepadRemoved, this, _1, _2));
|
|
|
|
for (Gamepad const& gamepad : Gamepad::Gamepads())
|
|
{
|
|
OnGamepadAdded(nullptr, gamepad);
|
|
}
|
|
|
|
m_canGetHolographicDisplayForCamera = winrt::Windows::Foundation::Metadata::ApiInformation::IsPropertyPresent(L"Windows.Graphics.Holographic.HolographicCamera", L"Display");
|
|
m_canGetDefaultHolographicDisplay = winrt::Windows::Foundation::Metadata::ApiInformation::IsMethodPresent(L"Windows.Graphics.Holographic.HolographicDisplay", L"GetDefault");
|
|
m_canCommitDirect3D11DepthBuffer = winrt::Windows::Foundation::Metadata::ApiInformation::IsMethodPresent(L"Windows.Graphics.Holographic.HolographicCameraRenderingParameters", L"CommitDirect3D11DepthBuffer");
|
|
|
|
if (m_canGetDefaultHolographicDisplay)
|
|
{
|
|
// Subscribe for notifications about changes to the state of the default HolographicDisplay
|
|
// and its SpatialLocator.
|
|
m_holographicDisplayIsAvailableChangedEventToken = HolographicSpace::IsAvailableChanged(bind(&BasicHologramMain::OnHolographicDisplayIsAvailableChanged, this, _1, _2));
|
|
}
|
|
|
|
// Acquire the current state of the default HolographicDisplay and its SpatialLocator.
|
|
OnHolographicDisplayIsAvailableChanged(nullptr, nullptr);
|
|
}
|
|
|
|
void BasicHologramMain::SetHolographicSpace(
|
|
HWND hWnd,
|
|
HolographicSpace const& holographicSpace)
|
|
{
|
|
UnregisterHolographicEventHandlers();
|
|
|
|
m_holographicSpace = holographicSpace;
|
|
|
|
//
|
|
// TODO: Add code here to initialize your holographic content.
|
|
//
|
|
|
|
#ifdef DRAW_SAMPLE_CONTENT
|
|
// Initialize the sample hologram.
|
|
m_spinningCubeRenderer = std::make_unique<SpinningCubeRenderer>(m_deviceResources);
|
|
m_spatialInputHandler = std::make_unique<SpatialInputHandler>(hWnd);
|
|
#endif
|
|
|
|
// Respond to camera added events by creating any resources that are specific
|
|
// to that camera, such as the back buffer render target view.
|
|
// When we add an event handler for CameraAdded, the API layer will avoid putting
|
|
// the new camera in new HolographicFrames until we complete the deferral we created
|
|
// for that handler, or return from the handler without creating a deferral. This
|
|
// allows the app to take more than one frame to finish creating resources and
|
|
// loading assets for the new holographic camera.
|
|
// This function should be registered before the app creates any HolographicFrames.
|
|
m_cameraAddedToken = m_holographicSpace.CameraAdded(std::bind(&BasicHologramMain::OnCameraAdded, this, _1, _2));
|
|
|
|
// Respond to camera removed events by releasing resources that were created for that
|
|
// camera.
|
|
// When the app receives a CameraRemoved event, it releases all references to the back
|
|
// buffer right away. This includes render target views, Direct2D target bitmaps, and so on.
|
|
// The app must also ensure that the back buffer is not attached as a render target, as
|
|
// shown in DeviceResources::ReleaseResourcesForBackBuffer.
|
|
m_cameraRemovedToken = m_holographicSpace.CameraRemoved(std::bind(&BasicHologramMain::OnCameraRemoved, this, _1, _2));
|
|
|
|
// Notes on spatial tracking APIs:
|
|
// * Stationary reference frames are designed to provide a best-fit position relative to the
|
|
// overall space. Individual positions within that reference frame are allowed to drift slightly
|
|
// as the device learns more about the environment.
|
|
// * When precise placement of individual holograms is required, a SpatialAnchor should be used to
|
|
// anchor the individual hologram to a position in the real world - for example, a point the user
|
|
// indicates to be of special interest. Anchor positions do not drift, but can be corrected; the
|
|
// anchor will use the corrected position starting in the next frame after the correction has
|
|
// occurred.
|
|
}
|
|
|
|
void BasicHologramMain::UnregisterHolographicEventHandlers()
|
|
{
|
|
if (m_holographicSpace != nullptr)
|
|
{
|
|
// Clear previous event registrations.
|
|
m_holographicSpace.CameraAdded(m_cameraAddedToken);
|
|
m_cameraAddedToken = {};
|
|
m_holographicSpace.CameraRemoved(m_cameraRemovedToken);
|
|
m_cameraRemovedToken = {};
|
|
}
|
|
|
|
if (m_spatialLocator != nullptr)
|
|
{
|
|
m_spatialLocator.LocatabilityChanged(m_locatabilityChangedToken);
|
|
}
|
|
}
|
|
|
|
BasicHologramMain::~BasicHologramMain()
|
|
{
|
|
// Deregister device notification.
|
|
m_deviceResources->RegisterDeviceNotify(nullptr);
|
|
|
|
UnregisterHolographicEventHandlers();
|
|
|
|
Gamepad::GamepadAdded(m_gamepadAddedEventToken);
|
|
Gamepad::GamepadRemoved(m_gamepadRemovedEventToken);
|
|
HolographicSpace::IsAvailableChanged(m_holographicDisplayIsAvailableChangedEventToken);
|
|
}
|
|
|
|
// Updates the application state once per frame.
|
|
HolographicFrame BasicHologramMain::Update()
|
|
{
|
|
// Before doing the timer update, there is some work to do per-frame
|
|
// to maintain holographic rendering. First, we will get information
|
|
// about the current frame.
|
|
|
|
// The HolographicFrame has information that the app needs in order
|
|
// to update and render the current frame. The app begins each new
|
|
// frame by calling CreateNextFrame.
|
|
HolographicFrame holographicFrame = m_holographicSpace.CreateNextFrame();
|
|
|
|
// Wait for the frame to be ready before pose-dependent updates and rendering.
|
|
// NOTE: This API call will throw an exception if a wait occurs at the wrong time, or out
|
|
// of sequence.
|
|
m_holographicSpace.WaitForNextFrameReady();
|
|
|
|
// Get a prediction of where holographic cameras will be when this frame
|
|
// is presented.
|
|
HolographicFramePrediction prediction = holographicFrame.CurrentPrediction();
|
|
|
|
// Back buffers can change from frame to frame. Validate each buffer, and recreate
|
|
// resource views and depth buffers as needed.
|
|
m_deviceResources->EnsureCameraResources(holographicFrame, prediction);
|
|
|
|
#ifdef DRAW_SAMPLE_CONTENT
|
|
if (m_stationaryReferenceFrame != nullptr)
|
|
{
|
|
// Check for new input state since the last frame.
|
|
for (GamepadWithButtonState& gamepadWithButtonState : m_gamepads)
|
|
{
|
|
bool buttonDownThisUpdate = ((gamepadWithButtonState.gamepad.GetCurrentReading().Buttons & GamepadButtons::A) == GamepadButtons::A);
|
|
if (buttonDownThisUpdate && !gamepadWithButtonState.buttonAWasPressedLastFrame)
|
|
{
|
|
m_pointerPressed = true;
|
|
}
|
|
gamepadWithButtonState.buttonAWasPressedLastFrame = buttonDownThisUpdate;
|
|
}
|
|
|
|
SpatialInteractionSourceState pointerState = m_spatialInputHandler->CheckForInput();
|
|
SpatialPointerPose pose = nullptr;
|
|
if (pointerState != nullptr)
|
|
{
|
|
pose = pointerState.TryGetPointerPose(m_stationaryReferenceFrame.CoordinateSystem());
|
|
}
|
|
else if (m_pointerPressed)
|
|
{
|
|
pose = SpatialPointerPose::TryGetAtTimestamp(m_stationaryReferenceFrame.CoordinateSystem(), prediction.Timestamp());
|
|
}
|
|
m_pointerPressed = false;
|
|
|
|
// When a Pressed gesture is detected, the sample hologram will be repositioned
|
|
// two meters in front of the user.
|
|
m_spinningCubeRenderer->PositionHologram(pose);
|
|
}
|
|
#endif
|
|
|
|
m_timer.Tick([this]()
|
|
{
|
|
//
|
|
// TODO: Update scene objects.
|
|
//
|
|
// Put time-based updates here. By default this code will run once per frame,
|
|
// but if you change the StepTimer to use a fixed time step this code will
|
|
// run as many times as needed to get to the current step.
|
|
//
|
|
|
|
#ifdef DRAW_SAMPLE_CONTENT
|
|
m_spinningCubeRenderer->Update(m_timer);
|
|
#endif
|
|
});
|
|
|
|
if (!m_canCommitDirect3D11DepthBuffer)
|
|
{
|
|
// On versions of the platform that do not support the CommitDirect3D11DepthBuffer API, we can control
|
|
// image stabilization by setting a focus point with optional plane normal and velocity.
|
|
for (HolographicCameraPose const& cameraPose : prediction.CameraPoses())
|
|
{
|
|
#ifdef DRAW_SAMPLE_CONTENT
|
|
|
|
// The HolographicCameraRenderingParameters class provides access to set
|
|
// the image stabilization parameters.
|
|
HolographicCameraRenderingParameters renderingParameters = holographicFrame.GetRenderingParameters(cameraPose);
|
|
|
|
// SetFocusPoint informs the system about a specific point in your scene to
|
|
// prioritize for image stabilization. The focus point is set independently
|
|
// for each holographic camera. When setting the focus point, put it on or
|
|
// near content that the user is looking at.
|
|
// In this example, we put the focus point at the center of the sample hologram.
|
|
// You can also set the relative velocity and facing of the stabilization
|
|
// plane using overloads of this method.
|
|
if (m_stationaryReferenceFrame != nullptr)
|
|
{
|
|
renderingParameters.SetFocusPoint(
|
|
m_stationaryReferenceFrame.CoordinateSystem(),
|
|
m_spinningCubeRenderer->GetPosition()
|
|
);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
// The holographic frame will be used to get up-to-date view and projection matrices and
|
|
// to present the swap chain.
|
|
return holographicFrame;
|
|
}
|
|
|
|
// Renders the current frame to each holographic camera, according to the
|
|
// current application and spatial positioning state. Returns true if the
|
|
// frame was rendered to at least one camera.
|
|
bool BasicHologramMain::Render(HolographicFrame const& holographicFrame)
|
|
{
|
|
// Don't try to render anything before the first Update.
|
|
if (m_timer.GetFrameCount() == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// TODO: Add code for pre-pass rendering here.
|
|
//
|
|
// Take care of any tasks that are not specific to an individual holographic
|
|
// camera. This includes anything that doesn't need the final view or projection
|
|
// matrix, such as lighting maps.
|
|
//
|
|
|
|
// Lock the set of holographic camera resources, then draw to each camera
|
|
// in this frame.
|
|
return m_deviceResources->UseHolographicCameraResources<bool>(
|
|
[this, holographicFrame](std::map<UINT32, std::unique_ptr<DX::CameraResources>>& cameraResourceMap)
|
|
{
|
|
// Up-to-date frame predictions enhance the effectiveness of image stablization and
|
|
// allow more accurate positioning of holograms.
|
|
holographicFrame.UpdateCurrentPrediction();
|
|
HolographicFramePrediction prediction = holographicFrame.CurrentPrediction();
|
|
|
|
bool atLeastOneCameraRendered = false;
|
|
for (HolographicCameraPose const& cameraPose : prediction.CameraPoses())
|
|
{
|
|
// This represents the device-based resources for a HolographicCamera.
|
|
DX::CameraResources* pCameraResources = cameraResourceMap[cameraPose.HolographicCamera().Id()].get();
|
|
|
|
// Get the device context.
|
|
const auto context = m_deviceResources->GetD3DDeviceContext();
|
|
const auto depthStencilView = pCameraResources->GetDepthStencilView();
|
|
|
|
// Set render targets to the current holographic camera.
|
|
ID3D11RenderTargetView *const targets[1] = { pCameraResources->GetBackBufferRenderTargetView() };
|
|
context->OMSetRenderTargets(1, targets, depthStencilView);
|
|
|
|
// Clear the back buffer and depth stencil view.
|
|
if (m_canGetHolographicDisplayForCamera &&
|
|
cameraPose.HolographicCamera().Display().IsOpaque())
|
|
{
|
|
context->ClearRenderTargetView(targets[0], DirectX::Colors::CornflowerBlue);
|
|
}
|
|
else
|
|
{
|
|
context->ClearRenderTargetView(targets[0], DirectX::Colors::Transparent);
|
|
}
|
|
context->ClearDepthStencilView(depthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
|
|
|
|
//
|
|
// TODO: Replace the sample content with your own content.
|
|
//
|
|
// Notes regarding holographic content:
|
|
// * For drawing, remember that you have the potential to fill twice as many pixels
|
|
// in a stereoscopic render target as compared to a non-stereoscopic render target
|
|
// of the same resolution. Avoid unnecessary or repeated writes to the same pixel,
|
|
// and only draw holograms that the user can see.
|
|
// * To help occlude hologram geometry, you can create a depth map using geometry
|
|
// data obtained via the surface mapping APIs. You can use this depth map to avoid
|
|
// rendering holograms that are intended to be hidden behind tables, walls,
|
|
// monitors, and so on.
|
|
// * On HolographicDisplays that are transparent, black pixels will appear transparent
|
|
// to the user. On such devices, you should clear the screen to Transparent as shown
|
|
// above. You should still use alpha blending to draw semitransparent holograms.
|
|
//
|
|
|
|
|
|
// The view and projection matrices for each holographic camera will change
|
|
// every frame. This function refreshes the data in the constant buffer for
|
|
// the holographic camera indicated by cameraPose.
|
|
if (m_stationaryReferenceFrame)
|
|
{
|
|
pCameraResources->UpdateViewProjectionBuffer(m_deviceResources, cameraPose, m_stationaryReferenceFrame.CoordinateSystem());
|
|
}
|
|
|
|
// Attach the view/projection constant buffer for this camera to the graphics pipeline.
|
|
bool cameraActive = pCameraResources->AttachViewProjectionBuffer(m_deviceResources);
|
|
|
|
#ifdef DRAW_SAMPLE_CONTENT
|
|
// Only render world-locked content when positional tracking is active.
|
|
if (cameraActive)
|
|
{
|
|
// Draw the sample hologram.
|
|
m_spinningCubeRenderer->Render();
|
|
if (m_canCommitDirect3D11DepthBuffer)
|
|
{
|
|
// On versions of the platform that support the CommitDirect3D11DepthBuffer API, we can
|
|
// provide the depth buffer to the system, and it will use depth information to stabilize
|
|
// the image at a per-pixel level.
|
|
HolographicCameraRenderingParameters renderingParameters = holographicFrame.GetRenderingParameters(cameraPose);
|
|
|
|
IDirect3DSurface interopSurface = DX::CreateDepthTextureInteropObject(pCameraResources->GetDepthStencilTexture2D());
|
|
|
|
// Calling CommitDirect3D11DepthBuffer causes the system to queue Direct3D commands to
|
|
// read the depth buffer. It will then use that information to stabilize the image as
|
|
// the HolographicFrame is presented.
|
|
renderingParameters.CommitDirect3D11DepthBuffer(interopSurface);
|
|
}
|
|
}
|
|
#endif
|
|
atLeastOneCameraRendered = true;
|
|
}
|
|
|
|
return atLeastOneCameraRendered;
|
|
});
|
|
}
|
|
|
|
void BasicHologramMain::SaveAppState()
|
|
{
|
|
//
|
|
// TODO: Insert code here to save your app state.
|
|
// This method is called when the app is about to suspend.
|
|
//
|
|
// For example, store information in the SpatialAnchorStore.
|
|
//
|
|
}
|
|
|
|
void BasicHologramMain::LoadAppState()
|
|
{
|
|
//
|
|
// TODO: Insert code here to load your app state.
|
|
// This method is called when the app resumes.
|
|
//
|
|
// For example, load information from the SpatialAnchorStore.
|
|
//
|
|
}
|
|
|
|
void BasicHologramMain::OnPointerPressed()
|
|
{
|
|
m_pointerPressed = true;
|
|
}
|
|
|
|
// Notifies classes that use Direct3D device resources that the device resources
|
|
// need to be released before this method returns.
|
|
void BasicHologramMain::OnDeviceLost()
|
|
{
|
|
#ifdef DRAW_SAMPLE_CONTENT
|
|
m_spinningCubeRenderer->ReleaseDeviceDependentResources();
|
|
#endif
|
|
}
|
|
|
|
// Notifies classes that use Direct3D device resources that the device resources
|
|
// may now be recreated.
|
|
void BasicHologramMain::OnDeviceRestored()
|
|
{
|
|
#ifdef DRAW_SAMPLE_CONTENT
|
|
m_spinningCubeRenderer->CreateDeviceDependentResources();
|
|
#endif
|
|
}
|
|
|
|
void BasicHologramMain::OnLocatabilityChanged(SpatialLocator const& sender, winrt::Windows::Foundation::IInspectable const& /*args*/)
|
|
{
|
|
switch (sender.Locatability())
|
|
{
|
|
case SpatialLocatability::Unavailable:
|
|
// Holograms cannot be rendered.
|
|
{
|
|
winrt::hstring message(L"Warning! Positional tracking is " + std::to_wstring(int(sender.Locatability())) + L".\n");
|
|
OutputDebugStringW(message.data());
|
|
}
|
|
break;
|
|
|
|
// In the following three cases, it is still possible to place holograms using a
|
|
// SpatialLocatorAttachedFrameOfReference.
|
|
case SpatialLocatability::PositionalTrackingActivating:
|
|
// The system is preparing to use positional tracking.
|
|
|
|
case SpatialLocatability::OrientationOnly:
|
|
// Positional tracking has not been activated.
|
|
|
|
case SpatialLocatability::PositionalTrackingInhibited:
|
|
// Positional tracking is temporarily inhibited. User action may be required
|
|
// in order to restore positional tracking.
|
|
break;
|
|
|
|
case SpatialLocatability::PositionalTrackingActive:
|
|
// Positional tracking is active. World-locked content can be rendered.
|
|
break;
|
|
}
|
|
}
|
|
|
|
void BasicHologramMain::OnCameraAdded(
|
|
HolographicSpace const& /*sender*/,
|
|
HolographicSpaceCameraAddedEventArgs const& args
|
|
)
|
|
{
|
|
winrt::Windows::Foundation::Deferral deferral = args.GetDeferral();
|
|
HolographicCamera holographicCamera = args.Camera();
|
|
create_task([this, deferral, holographicCamera]()
|
|
{
|
|
//
|
|
// TODO: Allocate resources for the new camera and load any content specific to
|
|
// that camera. Note that the render target size (in pixels) is a property
|
|
// of the HolographicCamera object, and can be used to create off-screen
|
|
// render targets that match the resolution of the HolographicCamera.
|
|
//
|
|
|
|
// Create device-based resources for the holographic camera and add it to the list of
|
|
// cameras used for updates and rendering. Notes:
|
|
// * Since this function may be called at any time, the AddHolographicCamera function
|
|
// waits until it can get a lock on the set of holographic camera resources before
|
|
// adding the new camera. At 60 frames per second this wait should not take long.
|
|
// * A subsequent Update will take the back buffer from the RenderingParameters of this
|
|
// camera's CameraPose and use it to create the ID3D11RenderTargetView for this camera.
|
|
// Content can then be rendered for the HolographicCamera.
|
|
m_deviceResources->AddHolographicCamera(holographicCamera);
|
|
|
|
// Holographic frame predictions will not include any information about this camera until
|
|
// the deferral is completed.
|
|
deferral.Complete();
|
|
});
|
|
}
|
|
|
|
void BasicHologramMain::OnCameraRemoved(
|
|
HolographicSpace const& /*sender*/,
|
|
HolographicSpaceCameraRemovedEventArgs const& args
|
|
)
|
|
{
|
|
create_task([this]()
|
|
{
|
|
//
|
|
// TODO: Asynchronously unload or deactivate content resources (not back buffer
|
|
// resources) that are specific only to the camera that was removed.
|
|
//
|
|
});
|
|
|
|
// Before letting this callback return, ensure that all references to the back buffer
|
|
// are released.
|
|
// Since this function may be called at any time, the RemoveHolographicCamera function
|
|
// waits until it can get a lock on the set of holographic camera resources before
|
|
// deallocating resources for this camera. At 60 frames per second this wait should
|
|
// not take long.
|
|
m_deviceResources->RemoveHolographicCamera(args.Camera());
|
|
}
|
|
|
|
void BasicHologramMain::OnGamepadAdded(winrt::Windows::Foundation::IInspectable, Gamepad const& args)
|
|
{
|
|
for (GamepadWithButtonState const& gamepadWithButtonState : m_gamepads)
|
|
{
|
|
if (args == gamepadWithButtonState.gamepad)
|
|
{
|
|
// This gamepad is already in the list.
|
|
return;
|
|
}
|
|
}
|
|
|
|
GamepadWithButtonState newGamepad = { args, false };
|
|
m_gamepads.push_back(newGamepad);
|
|
}
|
|
|
|
void BasicHologramMain::OnGamepadRemoved(winrt::Windows::Foundation::IInspectable, Gamepad const& args)
|
|
{
|
|
m_gamepads.erase(std::remove_if(m_gamepads.begin(), m_gamepads.end(), [&](GamepadWithButtonState& gamepadWithState)
|
|
{
|
|
return gamepadWithState.gamepad == args;
|
|
}),
|
|
m_gamepads.end());
|
|
}
|
|
|
|
void BasicHologramMain::OnHolographicDisplayIsAvailableChanged(winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable)
|
|
{
|
|
// Get the spatial locator for the default HolographicDisplay, if one is available.
|
|
SpatialLocator spatialLocator = nullptr;
|
|
if (m_canGetDefaultHolographicDisplay)
|
|
{
|
|
HolographicDisplay defaultHolographicDisplay = HolographicDisplay::GetDefault();
|
|
if (defaultHolographicDisplay)
|
|
{
|
|
spatialLocator = defaultHolographicDisplay.SpatialLocator();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
spatialLocator = SpatialLocator::GetDefault();
|
|
}
|
|
|
|
if (m_spatialLocator != spatialLocator)
|
|
{
|
|
// If the spatial locator is disconnected or replaced, we should discard all state that was
|
|
// based on it.
|
|
if (m_spatialLocator != nullptr)
|
|
{
|
|
m_spatialLocator.LocatabilityChanged(m_locatabilityChangedToken);
|
|
m_spatialLocator = nullptr;
|
|
}
|
|
|
|
m_stationaryReferenceFrame = nullptr;
|
|
|
|
if (spatialLocator != nullptr)
|
|
{
|
|
// Use the SpatialLocator from the default HolographicDisplay to track the motion of the device.
|
|
m_spatialLocator = spatialLocator;
|
|
|
|
// Respond to changes in the positional tracking state.
|
|
m_locatabilityChangedToken = m_spatialLocator.LocatabilityChanged(std::bind(&BasicHologramMain::OnLocatabilityChanged, this, _1, _2));
|
|
|
|
// The simplest way to render world-locked holograms is to create a stationary reference frame
|
|
// based on a SpatialLocator. This is roughly analogous to creating a "world" coordinate system
|
|
// with the origin placed at the device's position as the app is launched.
|
|
m_stationaryReferenceFrame = m_spatialLocator.CreateStationaryFrameOfReferenceAtCurrentLocation();
|
|
}
|
|
}
|
|
}
|