Sistemas de coordenadas de DirectXCoordinate systems in DirectX

Nota

Este artículo está relacionado con las API nativas de WinRT heredadas.This article relates to the legacy WinRT native APIs. En el caso de los nuevos proyectos de aplicaciones nativas, se recomienda usar la API de OpenXR.For new native app projects, we recommend using the OpenXR API.

Los sistemas de coordenadas constituyen la base para la comprensión espacial ofrecida por las API de Windows Mixed Reality.Coordinate systems form the basis for spatial understanding offered by Windows Mixed Reality APIs.

Los dispositivos de la plataforma de VR de una sola habitación o de la primera sala establecen un sistema de coordenadas principal para su espacio de seguimiento.Today's seated VR or single-room VR devices establish one primary coordinate system for their tracked space. Los dispositivos de realidad mixta como HoloLens están diseñados para entornos de gran tamaño sin definir, con el dispositivo que detecta y aprende sobre su entorno a medida que el usuario se recorre.Mixed Reality devices like HoloLens are designed for large undefined environments, with the device discovering and learning about its surroundings as the user walks around. El dispositivo se adapta para mejorar continuamente el conocimiento sobre los salones del usuario, pero los sistemas de coordenadas cambian su relación entre sí a lo largo de la duración de las aplicaciones.The device adapts to continually improving knowledge about the user's rooms, but results in coordinate systems that change their relationship to one another over the apps lifetime. Windows Mixed Reality es compatible con una amplia gama de dispositivos, desde los auriculares envolventes colocados a través de fotogramas de referencia conectados al mundo.Windows Mixed Reality supports a wide spectrum of devices, ranging from seated immersive headsets through world-attached reference frames.

Nota

Los fragmentos de código de este artículo muestran actualmente el uso de C++/CX en lugar de C + +17 compatible con C++/WinRT tal y como se usa en la plantilla de proyecto de C++ Holographic.The code snippets in this article currently demonstrate use of C++/CX rather than C++17-compliant C++/WinRT as used in the C++ holographic project template. Los conceptos son equivalentes para un proyecto/WinRT de C++, aunque tendrá que traducir el código.The concepts are equivalent for a C++/WinRT project, though you will need to translate the code.

Sistemas de coordenadas espaciales en WindowsSpatial coordinate systems in Windows

El tipo básico que se usa para los sistemas de coordenadas del mundo real en Windows es el SpatialCoordinateSystem.The core type used to reason about real-world coordinate systems in Windows is the SpatialCoordinateSystem. Una instancia de este tipo representa un sistema de coordenadas arbitrario, que proporciona un método para obtener los datos de la matriz de transformación que se pueden usar para transformar entre dos sistemas de coordenadas sin conocer los detalles de cada uno de ellos.An instance of this type represents an arbitrary coordinate system, providing a method for getting transformation matrix data that you can use to transform between two coordinate systems without understanding the details of each.

Los métodos que devuelven información espacial aceptarán un parámetro SpatialCoordinateSystem para permitirle decidir el sistema de coordenadas en el que es más útil para las coordenadas que se van a devolver.Methods that return spatial information will accept a SpatialCoordinateSystem parameter to let you decide the coordinate system in which it's most useful for those coordinates to be returned. La información espacial se representa como puntos, rayos o volúmenes en el entorno del usuario, y las unidades de estas coordenadas siempre estarán en metros.Spatial information is represented as points, rays, or volumes in the user's surroundings, and the units for these coordinates will always be in meters.

Un SpatialCoordinateSystem tiene una relación dinámica con otros sistemas de coordenadas, incluidos los que representan la posición del dispositivo.A SpatialCoordinateSystem has a dynamic relationship with other coordinate systems, including those that represent the device's position. En cualquier momento, el dispositivo puede localizar algunos sistemas de coordenadas y no otros.At any point, the device can locate some coordinate systems and not others. Para la mayoría de los sistemas de coordenadas, la aplicación debe estar preparada para controlar los períodos de tiempo durante los cuales no se pueden encontrar.For most coordinate systems, your app must be ready to handle periods of time during which they cannot be located.

La aplicación no debe crear SpatialCoordinateSystems directamente, sino que se deben usar a través de las API de percepción.Your application shouldn't create SpatialCoordinateSystems directly - rather they should be consumed via the Perception APIs. Existen tres orígenes principales de sistemas de coordenadas en las API de percepción, cada uno de los cuales se asigna a un concepto descrito en la página sistemas de coordenadas :There are three primary sources of coordinate systems in the Perception APIs, each of which map to a concept described on the Coordinate systems page:

Todos los sistemas de coordenadas devueltos por estos objetos son zurdos, con + y hacia arriba, + x a la derecha y + z hacia atrás.All of the coordinate systems returned by these objects are right-handed, with +y up, +x to the right and +z backwards. Puede recordar en qué dirección apunta el eje z positivo apuntando los dedos de la mano izquierda o derecha en la dirección x positiva y enrollándose en la dirección y positiva.You can remember which direction the positive z-axis points by pointing the fingers of either your left or right hand in the positive x direction and curling them into the positive y direction. La dirección en la que se encuentra el punto de control, ya sea hacia delante o fuera, es la dirección en la que apunta el eje z positivo para ese sistema de coordenadas.The direction your thumb points, either toward or away from you, is the direction that the positive z-axis points for that coordinate system. En la ilustración siguiente se muestran estos dos sistemas de coordenadas.The following illustration shows these two coordinate systems.

Sistemas de coordenadas del lado izquierdo y derechoLeft-hand and right-hand coordinate systems
Sistemas de coordenadas del lado izquierdo y derechoLeft-hand and right-hand coordinate systems

Use la clase SpatialLocator para crear un marco fijo o adjunto de referencia para arrancar en un SpatialCoordinateSystem basado en la posición de HoloLens.Use the SpatialLocator class to create either an attached or stationary frame of reference to bootstrap into a SpatialCoordinateSystem based on the HoloLens position. Continúe con la siguiente sección para obtener más información sobre este proceso.Continue to the next section to learn more about this process.

Colocar hologramas en el mundo mediante una fase espacialPlace holograms in the world using a spatial stage

Se tiene acceso al sistema de coordenadas para los auriculares con forma de la realidad mixta de Windows con la que se usa la propiedad estática SpatialStageFrameOfReference:: Current .The coordinate system for opaque Windows Mixed Reality immersive headsets is accessed using the static SpatialStageFrameOfReference::Current property. Esta API proporciona:This API provides:

  • Un sistema de coordenadasA coordinate system
  • Información sobre si el reproductor está sentado o es móvilInformation about whether the player is seated or mobile
  • El límite de un área segura para recorrer si el reproductor es móvilThe boundary of a safe area for walking around if the player is mobile
  • Una indicación de si el casco es direccional.An indication of whether the headset is directional.
  • Un controlador de eventos para las actualizaciones de la fase espacial.An event handler for updates to the spatial stage.

En primer lugar, se obtiene la fase espacial y se suscriben las actualizaciones a ella:First, we get the spatial stage and subscribe for updates to it:

Código para la inicialización de la fase espacialCode for Spatial stage initialization

SpatialStageManager::SpatialStageManager(
    const std::shared_ptr<DX::DeviceResources>& deviceResources, 
    const std::shared_ptr<SceneController>& sceneController)
    : m_deviceResources(deviceResources), m_sceneController(sceneController)
{
    // Get notified when the stage is updated.
    m_spatialStageChangedEventToken = SpatialStageFrameOfReference::CurrentChanged +=
        ref new EventHandler<Object^>(std::bind(&SpatialStageManager::OnCurrentChanged, this, _1));

    // Make sure to get the current spatial stage.
    OnCurrentChanged(nullptr);
}

En el método OnCurrentChanged, la aplicación debe inspeccionar la fase espacial y actualizar la experiencia del reproductor.In the OnCurrentChanged method, your app should inspect the spatial stage and update the player experience. En este ejemplo, se proporciona una visualización del límite de fase y la posición de inicio especificada por el usuario, así como el intervalo de vista y rango de propiedades de movimiento de la fase.In this example, we provide a visualization of the stage boundary and the start position specified by the user and the stage's range of view and range of movement properties. También reviertemos a nuestro propio sistema de coordenadas estacionales, cuando no se puede proporcionar una fase.We also fall back to our own stationary coordinate system, when a stage cannot be provided.

Código para la actualización de la fase espacialCode for Spatial stage update

void SpatialStageManager::OnCurrentChanged(Object^ /*o*/)
{
    // The event notifies us that a new stage is available.
    // Get the current stage.
    m_currentStage = SpatialStageFrameOfReference::Current;

    // Clear previous content.
    m_sceneController->ClearSceneObjects();

    if (m_currentStage != nullptr)
    {
        // Obtain stage geometry.
        auto stageCoordinateSystem = m_currentStage->CoordinateSystem;
        auto boundsVertexArray = m_currentStage->TryGetMovementBounds(stageCoordinateSystem);

        // Visualize the area where the user can move around.
        std::vector<float3> boundsVertices;
        boundsVertices.resize(boundsVertexArray->Length);
        memcpy(boundsVertices.data(), boundsVertexArray->Data, boundsVertexArray->Length * sizeof(float3));
        std::vector<unsigned short> indices = TriangulatePoints(boundsVertices);
        m_stageBoundsShape =
            std::make_shared<SceneObject>(
                    m_deviceResources,
                    reinterpret_cast<std::vector<XMFLOAT3>&>(boundsVertices),
                    indices,
                    XMFLOAT3(DirectX::Colors::SeaGreen),
                    stageCoordinateSystem);
        m_sceneController->AddSceneObject(m_stageBoundsShape);

        // In this sample, we draw a visual indicator for some spatial stage properties.
        // If the view is forward-only, the indicator is a half circle pointing forward - otherwise, it
        // is a full circle.
        // If the user can walk around, the indicator is blue. If the user is seated, it is red.

        // The indicator is rendered at the origin - which is where the user declared the center of the
        // stage to be during setup - above the plane of the stage bounds object.
        float3 visibleAreaCenter = float3(0.f, 0.001f, 0.f);

        // Its shape depends on the look direction range.
        std::vector<float3> visibleAreaIndicatorVertices;
        if (m_currentStage->LookDirectionRange == SpatialLookDirectionRange::ForwardOnly)
        {
            // Half circle for forward-only look direction range.
            visibleAreaIndicatorVertices = CreateCircle(visibleAreaCenter, 0.25f, 9, XM_PI);
        }
        else
        {
            // Full circle for omnidirectional look direction range.
            visibleAreaIndicatorVertices = CreateCircle(visibleAreaCenter, 0.25f, 16, XM_2PI);
        }

        // Its color depends on the movement range.
        XMFLOAT3 visibleAreaColor;
        if (m_currentStage->MovementRange == SpatialMovementRange::NoMovement)
        {
            visibleAreaColor = XMFLOAT3(DirectX::Colors::OrangeRed);
        }
        else
        {
            visibleAreaColor = XMFLOAT3(DirectX::Colors::Aqua);
        }

        std::vector<unsigned short> visibleAreaIndicatorIndices = TriangulatePoints(visibleAreaIndicatorVertices);

        // Visualize the look direction range.
        m_stageVisibleAreaIndicatorShape =
            std::make_shared<SceneObject>(
                    m_deviceResources,
                    reinterpret_cast<std::vector<XMFLOAT3>&>(visibleAreaIndicatorVertices),
                    visibleAreaIndicatorIndices,
                    visibleAreaColor,
                    stageCoordinateSystem);
        m_sceneController->AddSceneObject(m_stageVisibleAreaIndicatorShape);
    }
    else
    {
        // No spatial stage was found.
        // Fall back to a stationary coordinate system.
        auto locator = SpatialLocator::GetDefault();
        if (locator)
        {
            m_stationaryFrameOfReference = locator->CreateStationaryFrameOfReferenceAtCurrentLocation();

            // Render an indicator, so that we know we fell back to a mode without a stage.
            std::vector<float3> visibleAreaIndicatorVertices;
            float3 visibleAreaCenter = float3(0.f, -2.0f, 0.f);
            visibleAreaIndicatorVertices = CreateCircle(visibleAreaCenter, 0.125f, 16, XM_2PI);
            std::vector<unsigned short> visibleAreaIndicatorIndices = TriangulatePoints(visibleAreaIndicatorVertices);
            m_stageVisibleAreaIndicatorShape =
                std::make_shared<SceneObject>(
                    m_deviceResources,
                    reinterpret_cast<std::vector<XMFLOAT3>&>(visibleAreaIndicatorVertices),
                    visibleAreaIndicatorIndices,
                    XMFLOAT3(DirectX::Colors::LightSlateGray),
                    m_stationaryFrameOfReference->CoordinateSystem);
            m_sceneController->AddSceneObject(m_stageVisibleAreaIndicatorShape);
        }
    }
}

El conjunto de vértices que definen el límite de la fase se proporciona en el orden de las agujas del reloj.The set of vertices that define the stage boundary are provided in clockwise order. El shell de Windows Mixed Reality dibuja una barrera en el límite cuando el usuario la trata, pero es posible que desee triangular el área que se puede examinar para sus propios fines.The Windows Mixed Reality shell draws a fence at the boundary when the user approaches it, but you may want to triangularize the walkable area for your own purposes. El siguiente algoritmo se puede usar para triangular de la fase.The following algorithm can be used to triangularize the stage.

Código para triangulación en la fase espacialCode for Spatial stage triangularization

std::vector<unsigned short> SpatialStageManager::TriangulatePoints(std::vector<float3> const& vertices)
{
    size_t const& vertexCount = vertices.size();

    // Segments of the shape are removed as they are triangularized.
    std::vector<bool> vertexRemoved;
    vertexRemoved.resize(vertexCount, false);
    unsigned int vertexRemovedCount = 0;

    // Indices are used to define triangles.
    std::vector<unsigned short> indices;

    // Decompose into convex segments.
    unsigned short currentVertex = 0;
    while (vertexRemovedCount < (vertexCount - 2))
    {
        // Get next triangle:
        // Start with the current vertex.
        unsigned short index1 = currentVertex;

        // Get the next available vertex.
        unsigned short index2 = index1 + 1;

        // This cycles to the next available index.
        auto CycleIndex = [=](unsigned short indexToCycle, unsigned short stopIndex)
        {
            // Make sure the index does not exceed bounds.
            if (indexToCycle >= unsigned short(vertexCount))
            {
                indexToCycle -= unsigned short(vertexCount);
            }

            while (vertexRemoved[indexToCycle])
            {
                // If the vertex is removed, go to the next available one.
                ++indexToCycle;

                // Make sure the index does not exceed bounds.
                if (indexToCycle >= unsigned short(vertexCount))
                {
                    indexToCycle -= unsigned short(vertexCount);
                }

                // Prevent cycling all the way around.
                // Should not be needed, as we limit with the vertex count.
                if (indexToCycle == stopIndex)
                {
                    break;
                }
            }

            return indexToCycle;
        };
        index2 = CycleIndex(index2, index1);

        // Get the next available vertex after that.
        unsigned short index3 = index2 + 1;
        index3 = CycleIndex(index3, index1);

        // Vertices that may define a triangle inside the 2D shape.
        auto& v1 = vertices[index1];
        auto& v2 = vertices[index2];
        auto& v3 = vertices[index3];

        // If the projection of the first segment (in clockwise order) onto the second segment is 
        // positive, we know that the clockwise angle is less than 180 degrees, which tells us 
        // that the triangle formed by the two segments is contained within the bounding shape.
        auto v2ToV1 = v1 - v2;
        auto v2ToV3 = v3 - v2;
        float3 normalToV2ToV3 = { -v2ToV3.z, 0.f, v2ToV3.x };
        float projectionOntoNormal = dot(v2ToV1, normalToV2ToV3);
        if (projectionOntoNormal >= 0)
        {
            // Triangle is contained within the 2D shape.

            // Remove peak vertex from the list.
            vertexRemoved[index2] = true;
            ++vertexRemovedCount;

            // Create the triangle.
            indices.push_back(index1);
            indices.push_back(index2);
            indices.push_back(index3);

            // Continue on to the next outer triangle.
            currentVertex = index3;
        }
        else
        {
            // Triangle is a cavity in the 2D shape.
            // The next triangle starts at the inside corner.
            currentVertex = index2;
        }
    }

    indices.shrink_to_fit();
    return indices;
}

Colocar hologramas en el mundo con un marco estacionario de referenciaPlace holograms in the world using a stationary frame of reference

La clase SpatialStationaryFrameOfReference representa un marco de referencia que permanece estacionario en relación con el entorno del usuario a medida que el usuario se desplaza.The SpatialStationaryFrameOfReference class represents a frame of reference that remains stationary relative to the user's surroundings as the user moves around. Este marco de referencia prioriza la conservación de las coordenadas al lado del dispositivo.This frame of reference prioritizes keeping coordinates stable near the device. Un uso clave de una SpatialStationaryFrameOfReference es actuar como el sistema de coordenadas universal subyacente dentro de un motor de representación al representar hologramas.One key use of a SpatialStationaryFrameOfReference is to act as the underlying world coordinate system within a rendering engine when rendering holograms.

Para obtener un SpatialStationaryFrameOfReference, use la clase SpatialLocator y llame a CreateStationaryFrameOfReferenceAtCurrentLocation.To get a SpatialStationaryFrameOfReference, use the SpatialLocator class and call CreateStationaryFrameOfReferenceAtCurrentLocation.

En el código de plantilla de la aplicación Holographic de Windows:From the Windows Holographic app template code:

           // The simplest way to render world-locked holograms is to create a stationary reference frame
           // when the app is launched. This is roughly analogous to creating a "world" coordinate system
           // with the origin placed at the device's position as the app is launched.
           referenceFrame = locator.CreateStationaryFrameOfReferenceAtCurrentLocation();
  • Los fotogramas de referencia estacionarios están diseñados para proporcionar una posición con ajuste perfecto en relación con el espacio global.Stationary reference frames are designed to provide a best-fit position relative to the overall space. Las posiciones individuales dentro de ese marco de referencia pueden desplazarse ligeramente.Individual positions within that reference frame are allowed to drift slightly. Esto es normal, ya que el dispositivo aprende más sobre el entorno.This is normal as the device learns more about the environment.
  • Cuando se requiere una ubicación precisa de hologramas individuales, se debe usar un SpatialAnchor para delimitar el holograma individual a una posición en el mundo real; por ejemplo, un punto que el usuario indica que sea de especial interés.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. Las posiciones de anclaje no se desplazan, pero se pueden corregir. el delimitador usará la posición corregida a partir del fotograma siguiente después de que se haya realizado la corrección.Anchor positions don't drift, but can be corrected; the anchor will use the corrected position starting in the next frame after the correction has occurred.

Colocar hologramas en el mundo mediante delimitadores espacialesPlace holograms in the world using spatial anchors

Los delimitadores espaciales son una excelente manera de colocar hologramas en un lugar específico del mundo real, con el sistema que garantiza que el delimitador permanece en su lugar con el tiempo.Spatial anchors are a great way to place holograms at a specific place in the real world, with the system ensuring the anchor stays in place over time. En este tema se explica cómo crear y usar un delimitador y cómo trabajar con datos de delimitador.This topic explains how to create and use an anchor, and how to work with anchor data.

Puede crear un SpatialAnchor en cualquier posición y orientación dentro del SpatialCoordinateSystem de su elección.You can create a SpatialAnchor at any position and orientation within the SpatialCoordinateSystem of your choosing. El dispositivo debe ser capaz de localizar ese sistema de coordenadas en el momento y el sistema no debe haber alcanzado el límite de delimitadores espaciales.The device must be able to locate that coordinate system at the moment, and the system must not have reached its limit of spatial anchors.

Una vez definido, el sistema de coordenadas de un SpatialAnchor se ajusta continuamente para mantener la posición y orientación precisas de su ubicación inicial.Once defined, the coordinate system of a SpatialAnchor adjusts continually to keep the precise position and orientation of its initial location. Después, puede usar esta SpatialAnchor para representar hologramas que aparecerán fijos en el entorno del usuario en esa ubicación exacta.You can then use this SpatialAnchor to render holograms that will appear fixed in the user's surroundings at that exact location.

Los efectos de los ajustes que mantienen el anclaje en su lugar se amplían a medida que el delimitador aumenta.The effects of the adjustments that keep the anchor in place are magnified as distance from the anchor increases. Debe evitar la representación del contenido en relación con un delimitador que supere los 3 metros del origen de ese delimitador.You should avoid rendering content relative to an anchor that is more than about 3 meters from that anchor's origin.

La propiedad coordenadas obtiene un sistema de coordenadas que le permite colocar el contenido en relación con el delimitador, con una aceleración aplicada cuando el dispositivo ajusta la ubicación precisa del delimitador.The CoordinateSystem property gets a coordinate system that lets you place content relative to the anchor, with easing applied when the device adjusts the anchor's precise location.

Use la propiedad RawCoordinateSystem y el evento RawCoordinateSystemAdjusted correspondiente para administrar estos ajustes.Use the RawCoordinateSystem property and the corresponding RawCoordinateSystemAdjusted event to manage these adjustments yourself.

Persistencia y uso compartido de delimitadores espacialesPersist and share spatial anchors

Puede conservar un SpatialAnchor localmente mediante la clase SpatialAnchorStore y, a continuación, recuperarlo en una sesión de aplicación futura en el mismo dispositivo HoloLens.You can persist a SpatialAnchor locally using the SpatialAnchorStore class and then get it back in a future app session on the same HoloLens device.

Mediante el uso de anclajes espaciales de Azure, puede crear un delimitador de la nube durable desde un SpatialAnchor local, que la aplicación puede ubicar en varios dispositivos HoloLens, iOS y Android.By using Azure Spatial Anchors, you can create a durable cloud anchor from a local SpatialAnchor, which your app can then locate across multiple HoloLens, iOS and Android devices. Al compartir un delimitador espacial común en varios dispositivos, cada usuario puede ver el contenido representado en relación con ese delimitador en la misma ubicación física en tiempo real.By sharing a common spatial anchor across multiple devices, each user can see content rendered relative to that anchor in the same physical location in real time.

También puede usar delimitadores espaciales de Azure para la persistencia asincrónica de hologramas en dispositivos de HoloLens, iOS y Android.You can also use Azure Spatial Anchors for asynchronous hologram persistence across HoloLens, iOS, and Android devices. Al compartir un delimitador espacial en la nube duradero, varios dispositivos pueden observar el mismo holograma persistente con el tiempo, incluso si esos dispositivos no están presentes juntos al mismo tiempo.By sharing a durable cloud spatial anchor, multiple devices can observe the same persisted hologram over time, even if those devices aren't present together at the same time.

Para empezar a crear experiencias compartidas en la aplicación de HoloLens, pruebe la guía de inicio rápido de HoloLens de 5 minutos de delimitadores espaciales de Azure.To get started building shared experiences in your HoloLens app, try out the 5-minute Azure Spatial Anchors HoloLens quickstart.

Una vez que esté en funcionamiento con los anclajes espaciales de Azure, puede crear y buscar delimitadores en HoloLens.Once you're up and running with Azure Spatial Anchors, you can then create and locate anchors on HoloLens. También hay tutoriales disponibles para Android e iOS , lo que le permite compartir los mismos delimitadores en todos los dispositivos.Walkthroughs are available for Android and iOS as well, enabling you to share the same anchors on all devices.

Crear SpatialAnchors para contenido holográficaCreate SpatialAnchors for holographic content

En este ejemplo de código, se modificó la plantilla de aplicación de Windows Holographic para crear delimitadores cuando se detecta el gesto presionado .For this code sample, we modified the Windows Holographic app template to create anchors when the Pressed gesture is detected. Después, el cubo se coloca en el delimitador durante la fase de representación.The cube is then placed at the anchor during the render pass.

Dado que la clase auxiliar admite varios delimitadores, podemos colocar tantos cubos como deseen usar este ejemplo de código.Since multiple anchors are supported by the helper class, we can place as many cubes as we want to use this code sample!

Nota

Los identificadores de los delimitadores son algo que usted controla en la aplicación.The IDs for anchors are something you control in your app. En este ejemplo, se ha creado un esquema de nomenclatura que es secuencial en función del número de delimitadores almacenados actualmente en la colección de delimitadores de la aplicación.In this example, we have created a naming scheme that is sequential based on the number of anchors currently stored in the app's collection of anchors.

   // Check for new input state since the last frame.
   SpatialInteractionSourceState^ pointerState = m_spatialInputHandler->CheckForInput();
   if (pointerState != nullptr)
   {
       // Try to get the pointer pose relative to the SpatialStationaryReferenceFrame.
       SpatialPointerPose^ pointerPose = pointerState->TryGetPointerPose(currentCoordinateSystem);
       if (pointerPose != nullptr)
       {
           // When a Pressed gesture is detected, the anchor will be created two meters in front of the user.

           // Get the gaze direction relative to the given coordinate system.
           const float3 headPosition = pointerPose->Head->Position;
           const float3 headDirection = pointerPose->Head->ForwardDirection;

           // The anchor position in the StationaryReferenceFrame.
           static const float distanceFromUser = 2.0f; // meters
           const float3 gazeAtTwoMeters = headPosition + (distanceFromUser * headDirection);

           // Create the anchor at position.
           SpatialAnchor^ anchor = SpatialAnchor::TryCreateRelativeTo(currentCoordinateSystem, gazeAtTwoMeters);

           if ((anchor != nullptr) && (m_spatialAnchorHelper != nullptr))
           {
               // In this example, we store the anchor in an IMap.
               auto anchorMap = m_spatialAnchorHelper->GetAnchorMap();

               // Create an identifier for the anchor.
               String^ id = ref new String(L"HolographicSpatialAnchorStoreSample_Anchor") + anchorMap->Size;

               anchorMap->Insert(id->ToString(), anchor);
           }
       }
   }

Cargar y almacenar en caché de forma asincrónica el SpatialAnchorStoreAsynchronously load, and cache, the SpatialAnchorStore

Veamos cómo escribir una clase SampleSpatialAnchorHelper que ayude a controlar esta persistencia, incluidos:Let's see how to write a SampleSpatialAnchorHelper class that helps handle this persistence, including:

  • Almacenar una colección de delimitadores en memoria, indizada por una clave Platform:: String.Storing a collection of in-memory anchors, indexed by a Platform::String key.
  • Cargar delimitadores de la SpatialAnchorStore del sistema, que se mantiene independiente de la colección en memoria local.Loading anchors from the system's SpatialAnchorStore, which is kept separate from the local in-memory collection.
  • Guardar la colección local en memoria de los delimitadores en el SpatialAnchorStore cuando la aplicación decida hacerlo.Saving the local in-memory collection of anchors to the SpatialAnchorStore when the app chooses to do so.

Aquí se muestra cómo guardar objetos SpatialAnchor en SpatialAnchorStore.Here's how to save SpatialAnchor objects in the SpatialAnchorStore.

Cuando se inicia la clase, se solicita SpatialAnchorStore de forma asincrónica.When the class starts up, we request the SpatialAnchorStore asynchronously. Esto implica la e/s del sistema, ya que la API carga el almacén de delimitadores y esta API se hace asincrónica para que la e/s no sea de bloqueo.This involves system I/O as the API loads the anchor store, and this API is made asynchronous so that the I/O is non-blocking.

   // Request the spatial anchor store, which is the WinRT object that will accept the imported anchor data.
   return create_task(SpatialAnchorManager::RequestStoreAsync())
       .then([](task<SpatialAnchorStore^> previousTask)
   {
       std::shared_ptr<SampleSpatialAnchorHelper> newHelper = nullptr;

       try
       {
           SpatialAnchorStore^ anchorStore = previousTask.get();

           // Once the SpatialAnchorStore has been loaded by the system, we can create our helper class.

           // Using "new" to access private constructor
           newHelper = std::shared_ptr<SampleSpatialAnchorHelper>(new SampleSpatialAnchorHelper(anchorStore));

           // Now we can load anchors from the store.
           newHelper->LoadFromAnchorStore();
       }
       catch (Exception^ exception)
       {
           PrintWstringToDebugConsole(
               std::wstring(L"Exception while loading the anchor store: ") +
               exception->Message->Data() +
               L"\n"
               );
       }

       // Return the initialized class instance.
       return newHelper;
   });

Se le proporcionará un SpatialAnchorStore que puede usar para guardar los delimitadores.You'll be given a SpatialAnchorStore that you can use to save the anchors. Se trata de un IMapView que asocia valores de clave que son cadenas, con valores de datos que son SpatialAnchors.This is an IMapView that associates key values that are Strings, with data values that are SpatialAnchors. En el código de ejemplo, se almacena en una variable de miembro de clase privada que es accesible a través de una función pública de nuestra clase auxiliar.In our sample code, we store this in a private class member variable that is accessible through a public function of our helper class.

   SampleSpatialAnchorHelper::SampleSpatialAnchorHelper(SpatialAnchorStore^ anchorStore)
   {
       m_anchorStore = anchorStore;
       m_anchorMap = ref new Platform::Collections::Map<String^, SpatialAnchor^>();
   }

Nota

No olvide enlazar los eventos de suspensión y reanudación para guardar y cargar el almacén delimitado.Don't forget to hook up the suspend/resume events to save and load the anchor store.

   void HolographicSpatialAnchorStoreSampleMain::SaveAppState()
   {
       // For example, store information in the SpatialAnchorStore.
       if (m_spatialAnchorHelper != nullptr)
       {
           m_spatialAnchorHelper->TrySaveToAnchorStore();
       }
   }
   void HolographicSpatialAnchorStoreSampleMain::LoadAppState()
   {
       // For example, load information from the SpatialAnchorStore.
       LoadAnchorStore();
   }

Guardar el contenido en el almacén delimitadoSave content to the anchor store

Cuando el sistema suspende la aplicación, debe guardar los anclajes espaciales en el almacén delimitado.When the system suspends your app, you need to save your spatial anchors to the anchor store. También puede optar por guardar los delimitadores en el almacén de delimitadores en otros momentos, según considere que es necesario para la implementación de la aplicación.You may also choose to save anchors to the anchor store at other times, as you find to be necessary for your app's implementation.

Cuando esté listo para intentar guardar los delimitadores en memoria en SpatialAnchorStore, puede crear un bucle a través de la colección e intentar guardar cada una de ellas.When you're ready to try saving the in-memory anchors to the SpatialAnchorStore, you can loop through your collection and try to save each one.

   // TrySaveToAnchorStore: Stores all anchors from memory into the app's anchor store.
   //
   // For each anchor in memory, this function tries to store it in the app's AnchorStore. The operation will fail if
   // the anchor store already has an anchor by that name.
   //
   bool SampleSpatialAnchorHelper::TrySaveToAnchorStore()
   {
       // This function returns true if all the anchors in the in-memory collection are saved to the anchor
       // store. If zero anchors are in the in-memory collection, we will still return true because the
       // condition has been met.
       bool success = true;

       // If access is denied, 'anchorStore' will not be obtained.
       if (m_anchorStore != nullptr)
       {
           for each (auto& pair in m_anchorMap)
           {
               auto const& id = pair->Key;
               auto const& anchor = pair->Value;

               // Try to save the anchors.
               if (!m_anchorStore->TrySave(id, anchor))
               {
                   // This may indicate the anchor ID is taken, or the anchor limit is reached for the app.
                   success=false;
               }
           }
       }

       return success;
   }

Carga de contenido desde el almacén delimitado cuando se reanuda la aplicaciónLoad content from the anchor store when the app resumes

Puede restaurar los delimitadores guardados en el AnchorStore si los transfiere del IMapView del almacén delimitador a su propia base de datos en memoria de SpatialAnchors cuando se reanuda la aplicación o en cualquier momento.You can restore saved anchors in the AnchorStore by transferring them from the anchor store's IMapView to your own in-memory database of SpatialAnchors when your app resumes or at any time.

Para restaurar los delimitadores de SpatialAnchorStore, restaure cada uno que le interese a su propia colección en memoria.To restore anchors from the SpatialAnchorStore, restore each one that you're interested in to your own in-memory collection.

Necesita su propia base de datos en memoria de SpatialAnchors para asociar cadenas con el SpatialAnchors que cree.You need your own in-memory database of SpatialAnchors to associate Strings with the SpatialAnchors that you create. En el código de ejemplo, elegimos usar un Windows:: Foundation:: Collections:: IMap para almacenar los delimitadores, lo que facilita el uso de la misma clave y el mismo valor de datos para el SpatialAnchorStore.In our sample code, we choose to use a Windows::Foundation::Collections::IMap to store the anchors, which makes it easy to use the same key and data value for the SpatialAnchorStore.

   // This is an in-memory anchor list that is separate from the anchor store.
   // These anchors may be used, reasoned about, and so on before committing the collection to the store.
   Windows::Foundation::Collections::IMap<Platform::String^, Windows::Perception::Spatial::SpatialAnchor^>^ m_anchorMap;

Nota

Un delimitador que se restaure podría no ser localizable de inmediato.An anchor that is restored might not be locatable right away. Por ejemplo, podría tratarse de un delimitador en un salón independiente o en un edificio diferente.For example, it might be an anchor in a separate room or in a different building altogether. Los delimitadores recuperados de AnchorStore deben probarse para encontrar la ubicación antes de usarlos.Anchors retrieved from the AnchorStore should be tested for locatability before using them.


Nota

En este código de ejemplo, recuperamos todos los delimitadores de AnchorStore.In this example code, we retrieve all anchors from the AnchorStore. Esto no es un requisito; también podría elegir un determinado subconjunto de delimitadores usando valores de clave de cadena que son significativos para su implementación.This is not a requirement; your app could just as well pick and choose a certain subset of anchors by using String key values that are meaningful to your implementation.

   // LoadFromAnchorStore: Loads all anchors from the app's anchor store into memory.
   //
   // The anchors are stored in memory using an IMap, which stores anchors using a string identifier. Any string can be used as
   // the identifier; it can have meaning to the app, such as "Game_Leve1_CouchAnchor," or it can be a GUID that is generated
   // by the app.
   //
   void SampleSpatialAnchorHelper::LoadFromAnchorStore()
   {
       // If access is denied, 'anchorStore' will not be obtained.
       if (m_anchorStore != nullptr)
       {
           // Get all saved anchors.
           auto anchorMapView = m_anchorStore->GetAllSavedAnchors();
           for each (auto const& pair in anchorMapView)
           {
               auto const& id = pair->Key;
               auto const& anchor = pair->Value;
               m_anchorMap->Insert(id, anchor);
           }
       }
   }

Borrar el almacén delimitador, cuando sea necesarioClear the anchor store, when needed

A veces, debe borrar el estado de la aplicación y escribir datos nuevos.Sometimes, you need to clear app state and write new data. Aquí se muestra cómo hacerlo con el SpatialAnchorStore.Here's how you do that with the SpatialAnchorStore.

Con nuestra clase auxiliar, casi innecesaria para encapsular la función Clear.Using our helper class, it's almost unnecessary to wrap the Clear function. Decidimos hacerlo en nuestra implementación de ejemplo, porque a nuestra clase auxiliar se le da la responsabilidad de poseer la instancia de SpatialAnchorStore.We choose to do so in our sample implementation, because our helper class is given the responsibility of owning the SpatialAnchorStore instance.

   // ClearAnchorStore: Clears the AnchorStore for the app.
   //
   // This function clears the AnchorStore. It has no effect on the anchors stored in memory.
   //
   void SampleSpatialAnchorHelper::ClearAnchorStore()
   {
       // If access is denied, 'anchorStore' will not be obtained.
       if (m_anchorStore != nullptr)
       {
           // Clear all anchors from the store.
           m_anchorStore->Clear();
       }
   }

Ejemplo: vinculación de sistemas de coordenadas de anclaje a sistemas de coordenadas de fotogramas de referencia estacionalesExample: Relating anchor coordinate systems to stationary reference frame coordinate systems

Supongamos que tiene un delimitador y quiere relacionar algo en el sistema de coordenadas del delimitador con el SpatialStationaryReferenceFrame que ya está usando para el otro contenido.Let's say you have an anchor, and you want to relate something in your anchor's coordinate system to the SpatialStationaryReferenceFrame you’re already using for your other content. Puede usar TryGetTransformTo para obtener una transformación del sistema de coordenadas del delimitador al marco de referencia estacionaria:You can use TryGetTransformTo to get a transform from the anchor’s coordinate system to that of the stationary reference frame:

   // In this code snippet, someAnchor is a SpatialAnchor^ that has been initialized and is valid in the current environment.
   float4x4 anchorSpaceToCurrentCoordinateSystem;
   SpatialCoordinateSystem^ anchorSpace = someAnchor->CoordinateSystem;
   const auto tryTransform = anchorSpace->TryGetTransformTo(currentCoordinateSystem);
   if (tryTransform != nullptr)
   {
       anchorSpaceToCurrentCoordinateSystem = tryTransform->Value;
   }

Este proceso resulta útil de dos maneras:This process is useful to you in two ways:

  1. Indica si los dos fotogramas de referencia se pueden entender entre sí, y;It tells you if the two reference frames can be understood relative to one another, and;
  2. En ese caso, proporciona una transformación para pasar directamente de un sistema de coordenadas a otro.If so, it provides you a transform to go directly from one coordinate system to the other.

Con esta información, se conoce la relación espacial entre los objetos entre los dos fotogramas de referencia.With this information, you have an understanding of the spatial relation between objects between the two reference frames.

Para la representación, a menudo puede obtener mejores resultados mediante la agrupación de objetos según su marco de referencia original o el delimitador.For rendering, you can often obtain better results by grouping objects according to their original reference frame or anchor. Realice un paso de dibujo independiente para cada grupo.Perform a separate drawing pass for each group. Las matrices de vistas son más precisas para los objetos con transformaciones del modelo que se crean Inicialmente mediante el mismo sistema de coordenadas.The view matrices are more accurate for objects with model transforms that are created initially using the same coordinate system.

Crear hologramas mediante un marco de referencia conectado al dispositivoCreate holograms using a device-attached frame of reference

Hay ocasiones en las que desea representar un holograma que permanece adjunto a la ubicación del dispositivo, por ejemplo un panel con información de depuración o un mensaje informativo cuando el dispositivo solo puede determinar su orientación y no su posición en el espacio.There are times when you want to render a hologram that remains attached to the device's location, for example a panel with debugging information or an informational message when the device is only able to determine its orientation and not its position in space. Para ello, usamos un marco de referencia asociado.To accomplish this, we use an attached frame of reference.

La clase SpatialLocatorAttachedFrameOfReference define los sistemas de coordenadas, que son relativos al dispositivo en lugar de al mundo real.The SpatialLocatorAttachedFrameOfReference class defines coordinate systems, which are relative to the device rather than to the real-world. Este marco tiene un encabezado fijo en relación con el entorno del usuario que apunta a la dirección a la que estaba situado el usuario cuando se creó el marco de referencia.This frame has a fixed heading relative to the user's surroundings that points in the direction the user was facing when the reference frame was created. A partir de entonces, todas las orientaciones de este marco de referencia son relativas a ese título fijo, incluso cuando el usuario gira el dispositivo.From then on, all orientations in this frame of reference are relative to that fixed heading, even as the user rotates the device.

En el caso de HoloLens, el origen del sistema de coordenadas de este fotograma se encuentra en el centro de rotación del encabezado del usuario, de modo que su posición no se ve afectada por la rotación del cabezal.For HoloLens, the origin of this frame's coordinate system is located at the center of rotation of the user's head, so that its position is not affected by head rotation. La aplicación puede especificar un desplazamiento relativo a este punto para colocar los hologramas delante del usuario.Your app can specify an offset relative to this point to position holograms in front of the user.

Para obtener un SpatialLocatorAttachedFrameOfReference, use la clase SpatialLocator y llame a CreateAttachedFrameOfReferenceAtCurrentHeading.To get a SpatialLocatorAttachedFrameOfReference, use the SpatialLocator class and call CreateAttachedFrameOfReferenceAtCurrentHeading.

Esto se aplica a todo el intervalo de dispositivos de Windows Mixed Reality.This applies to the entire range of Windows Mixed Reality devices.

Uso de un marco de referencia conectado al dispositivoUse a reference frame attached to the device

En estas secciones se habla sobre lo que hemos cambiado en la plantilla de aplicación de Windows Holographic para habilitar un marco de referencia de dispositivo de referencia mediante esta API.These sections talk about what we changed in the Windows Holographic app template to enable a device-attached frame of reference using this API. Este holograma "adjunto" funcionará junto con los hologramas fijos o anclados y también se puede usar cuando el dispositivo no pueda encontrar su posición en el mundo temporalmente.This "attached" hologram will work alongside stationary or anchored holograms, and may also be used when the device is temporarily unable to find its position in the world.

En primer lugar, hemos cambiado la plantilla para almacenar un SpatialLocatorAttachedFrameOfReference en lugar de un SpatialStationaryFrameOfReference:First, we changed the template to store a SpatialLocatorAttachedFrameOfReference instead of a SpatialStationaryFrameOfReference:

Desde HolographicTagAlongSampleMain. h:From HolographicTagAlongSampleMain.h:

   // A reference frame attached to the holographic camera.
   Windows::Perception::Spatial::SpatialLocatorAttachedFrameOfReference^   m_referenceFrame;

Desde HolographicTagAlongSampleMain. cpp:From HolographicTagAlongSampleMain.cpp:

   // In this example, we create a reference frame attached to the device.
   m_referenceFrame = m_locator->CreateAttachedFrameOfReferenceAtCurrentHeading();

Durante la actualización, ahora obtenemos el sistema de coordenadas en la marca de tiempo obtenida de con la predicción de fotogramas.During the update, we now obtain the coordinate system at the time stamp obtained from with the frame prediction.

   // Next, we get a coordinate system from the attached frame of reference that is
   // associated with the current frame. Later, this coordinate system is used for
   // for creating the stereo view matrices when rendering the sample content.
   SpatialCoordinateSystem^ currentCoordinateSystem =
       m_referenceFrame->GetStationaryCoordinateSystemAtTimestamp(prediction->Timestamp);

Obtener una pose de puntero espacial y seguir elGet a spatial pointer pose, and follow the user's Gaze

Queremos que el holograma de ejemplo siga la miradadel usuario, de forma similar a cómo el shell holográfica puede seguir a la mirada del usuario.We want our example hologram to follow the user's gaze, similar to how the holographic shell can follow the user's gaze. Para ello, es necesario obtener el SpatialPointerPose de la misma marca de tiempo.For this, we need to get the SpatialPointerPose from the same time stamp.

SpatialPointerPose^ pose = SpatialPointerPose::TryGetAtTimestamp(currentCoordinateSystem, prediction->Timestamp);

Este SpatialPointerPose tiene la información necesaria para colocar el holograma según el encabezado actual del usuario.This SpatialPointerPose has the information needed to position the hologram according to the user's current heading.

Para la comodidad del usuario, usamos la interpolación lineal ("lerp") para suavizar el cambio en la posición en un período de tiempo.For user comfort, we use linear interpolation ("lerp") to smooth the change in position over a period of time. Esto es más cómodo para el usuario que bloquear el holograma a su mirada.This is more comfortable for the user than locking the hologram to their gaze. Lerping la posición de la etiqueta en el holograma también nos permite estabilizar el holograma mediante la amortiguación del movimiento.Lerping the tag-along hologram's position also allows us to stabilize the hologram by dampening the movement. Si no hacemos esto, el usuario verá la vibración del holograma debido a lo que se suele considerar como movimientos imperceptibles del encabezado del usuario.If we didn't do this dampening, the user would see the hologram jitter because of what are normally considered to be imperceptible movements of the user's head.

Desde StationaryQuadRenderer::P ositionhologram:From StationaryQuadRenderer::PositionHologram:

   const float& dtime = static_cast<float>(timer.GetElapsedSeconds());

   if (pointerPose != nullptr)
   {
       // Get the gaze direction relative to the given coordinate system.
       const float3 headPosition  = pointerPose->Head->Position;
       const float3 headDirection = pointerPose->Head->ForwardDirection;

       // The tag-along hologram follows a point 2.0m in front of the user's gaze direction.
       static const float distanceFromUser = 2.0f; // meters
       const float3 gazeAtTwoMeters = headPosition + (distanceFromUser * headDirection);

       // Lerp the position, to keep the hologram comfortably stable.
       auto lerpedPosition = lerp(m_position, gazeAtTwoMeters, dtime * c_lerpRate);

       // This will be used as the translation component of the hologram's
       // model transform.
       SetPosition(lerpedPosition);
   }

Nota

En el caso de un panel de depuración, puede optar por volver a colocar el holograma en la parte lateral un poco para que no obstruya la vista.In the case of a debugging panel, you might choose to reposition the hologram off to the side a little so that it doesn't obstruct your view. Este es un ejemplo de cómo podría hacerlo.Here's an example of how you might do that.

Para StationaryQuadRenderer::P ositionhologram:For StationaryQuadRenderer::PositionHologram:

       // If you're making a debug view, you might not want the tag-along to be directly in the
       // center of your field of view. Use this code to position the hologram to the right of
       // the user's gaze direction.
       /*
       const float3 offset = float3(0.13f, 0.0f, 0.f);
       static const float distanceFromUser = 2.2f; // meters
       const float3 gazeAtTwoMeters = headPosition + (distanceFromUser * (headDirection + offset));
       */

Girar el holograma para que se enfrente a la cámaraRotate the hologram to face the camera

No basta con colocar el holograma, que en este caso es un cuádruple; También debemos girar el objeto para que se enfrente al usuario.It isn't enough to position the hologram, which in this case is a quad; we must also rotate the object to face the user. Esta rotación se produce en el espacio universal, ya que este tipo de cartelera permite que el holograma siga siendo parte del entorno del usuario.This rotation occurs in world space, because this type of billboarding allows the hologram to remain a part of the user's environment. La cartelera de espacio de vista no es tan cómoda porque el holograma se bloquea a la orientación de la pantalla. en ese caso, también tendría que interpolar entre las matrices de la vista izquierda y derecha para adquirir una transformación de la cartelera de espacio de vista que no interrumpa la representación de estéreo.View-space billboarding isn't as comfortable because the hologram becomes locked to the display orientation; in that case, you would also have to interpolate between the left and right view matrices to acquire a view-space billboard transform that doesn't disrupt stereo rendering. Aquí, giramos en los ejes X y Z para que se enfrente al usuario.Here, we rotate on the X and Z axes to face the user.

Desde StationaryQuadRenderer:: Update:From StationaryQuadRenderer::Update:

   // Seconds elapsed since previous frame.
   const float& dTime = static_cast<float>(timer.GetElapsedSeconds());

   // Create a direction normal from the hologram's position to the origin of person space.
   // This is the z-axis rotation.
   XMVECTOR facingNormal = XMVector3Normalize(-XMLoadFloat3(&m_position));

   // Rotate the x-axis around the y-axis.
   // This is a 90-degree angle from the normal, in the xz-plane.
   // This is the x-axis rotation.
   XMVECTOR xAxisRotation = XMVector3Normalize(XMVectorSet(XMVectorGetZ(facingNormal), 0.f, -XMVectorGetX(facingNormal), 0.f));

   // Create a third normal to satisfy the conditions of a rotation matrix.
   // The cross product  of the other two normals is at a 90-degree angle to
   // both normals. (Normalize the cross product to avoid floating-point math
   // errors.)
   // Note how the cross product will never be a zero-matrix because the two normals
   // are always at a 90-degree angle from one another.
   XMVECTOR yAxisRotation = XMVector3Normalize(XMVector3Cross(facingNormal, xAxisRotation));

   // Construct the 4x4 rotation matrix.

   // Rotate the quad to face the user.
   XMMATRIX rotationMatrix = XMMATRIX(
       xAxisRotation,
       yAxisRotation,
       facingNormal,
       XMVectorSet(0.f, 0.f, 0.f, 1.f)
       );

   // Position the quad.
   const XMMATRIX modelTranslation = XMMatrixTranslationFromVector(XMLoadFloat3(&m_position));

   // The view and projection matrices are provided by the system; they are associated
   // with holographic cameras, and updated on a per-camera basis.
   // Here, we provide the model transform for the sample hologram. The model transform
   // matrix is transposed to prepare it for the shader.
   XMStoreFloat4x4(&m_modelConstantBufferData.model, XMMatrixTranspose(rotationMatrix * modelTranslation));

Representar el holograma adjuntoRender the attached hologram

En este ejemplo, también optamos por representar el holograma en el sistema de coordenadas de SpatialLocatorAttachedReferenceFrame, que es donde colocamos el holograma.For this example, we also choose to render the hologram in the coordinate system of the SpatialLocatorAttachedReferenceFrame, which is where we positioned the hologram. (Si se hubiera decidido representar con otro sistema de coordenadas, es necesario adquirir una transformación del sistema de coordenadas del fotograma de referencia conectado al dispositivo a ese sistema de coordenadas).(If we had decided to render using another coordinate system, we would need to acquire a transform from the device-attached reference frame's coordinate system to that coordinate system.)

Desde HolographicTagAlongSampleMain:: Render:From HolographicTagAlongSampleMain::Render:

   // 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.
   pCameraResources->UpdateViewProjectionBuffer(
       m_deviceResources,
       cameraPose,
       m_referenceFrame->GetStationaryCoordinateSystemAtTimestamp(prediction->Timestamp)
       );

Ya está.That's it! Ahora, el holograma "persecución" es una posición de 2 metros delante de la dirección del usuario.The hologram will now "chase" a position that is 2 meters in front of the user's gaze direction.

Nota

En este ejemplo también se carga contenido adicional; Consulte StationaryQuadRenderer. cpp.This example also loads additional content - see StationaryQuadRenderer.cpp.

Control de la pérdida de seguimientoHandling tracking loss

Cuando el dispositivo no se encuentra en el mundo, la aplicación experimenta "pérdida de seguimiento".When the device can't locate itself in the world, the app experiences "tracking loss". Las aplicaciones de Windows Mixed Reality deben ser capaces de controlar tales interrupciones en el sistema de seguimiento posicional.Windows Mixed Reality apps should be able to handle such disruptions to the positional tracking system. Estas interrupciones se pueden observar y las respuestas se crean mediante el evento LocatabilityChanged en el SpatialLocator predeterminado.These disruptions can be observed, and responses created, by using the LocatabilityChanged event on the default SpatialLocator.

Desde AppMain:: SetHolographicSpace:From AppMain::SetHolographicSpace:

   // Be able to respond to changes in the positional tracking state.
   m_locatabilityChangedToken =
       m_locator->LocatabilityChanged +=
           ref new Windows::Foundation::TypedEventHandler<SpatialLocator^, Object^>(
               std::bind(&HolographicApp1Main::OnLocatabilityChanged, this, _1, _2)
               );

Cuando la aplicación recibe un evento LocatabilityChanged, puede cambiar el comportamiento según sea necesario.When your app receives a LocatabilityChanged event, it can change behavior as needed. Por ejemplo, en el estado PositionalTrackingInhibited, la aplicación puede pausar el funcionamiento normal y representar una etiqueta a lo largo de un holograma que muestre un mensaje de advertencia.For example, in the PositionalTrackingInhibited state, your app can pause normal operation and render a tag-along hologram that displays a warning message.

La plantilla de aplicación de Windows Holographic incluye un controlador LocatabilityChanged que ya se ha creado.The Windows Holographic app template comes with a LocatabilityChanged handler already created for you. De forma predeterminada, se muestra una advertencia en la consola de depuración cuando el seguimiento posicional no está disponible.By default, it displays a warning in the debug console when positional tracking is unavailable. Puede agregar código a este controlador para proporcionar una respuesta según sea necesario desde la aplicación.You can add code to this handler to provide a response as needed from your app.

Desde AppMain. cpp:From AppMain.cpp:

   void HolographicApp1Main::OnLocatabilityChanged(SpatialLocator^ sender, Object^ args)
   {
       switch (sender->Locatability)
       {
       case SpatialLocatability::Unavailable:
           // Holograms cannot be rendered.
           {
               String^ message = L"Warning! Positional tracking is " +
                                           sender->Locatability.ToString() + 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;
       }
   }

Asignación espacialSpatial mapping

Las API de asignación espacial hacen uso de los sistemas de coordenadas para obtener las transformaciones del modelo para las mallas de superficie.The spatial mapping APIs make use of coordinate systems to get model transforms for surface meshes.

Consulte tambiénSee also