DirectX'te sistemleri koordine eder

Not

Bu makale, eski WinRT yerel API'leriyle ilgilidir. Yeni yerel uygulama projeleri için OpenXR API'sini kullanmanızı öneririz.

Koordinat sistemleri, Windows Mixed Reality API'ler tarafından sunulan uzamsal anlayışın temelini oluşturur.

Günümüzün yerleşik VR veya tek odalı VR cihazları, izlenen alanları için tek bir birincil koordinat sistemi kurar. HoloLens gibi Karma Gerçeklik cihazlar büyük tanımsız ortamlar için tasarlanmıştır ve cihaz, kullanıcı gezindikçe çevresini keşfeder ve öğrenir. Cihaz, kullanıcının odaları hakkındaki bilgileri sürekli geliştirmeye uyum sağlar, ancak uygulamaların kullanım ömrü boyunca birbiriyle ilişkilerini değiştiren koordinat sistemleriyle sonuçlanabilir. Windows Mixed Reality, yerleşik çevreleyici kulaklıklardan dünyaya bağlı referans çerçevelerine kadar geniş bir cihaz yelpazesini destekler.

Not

Bu makaledeki kod parçacıkları şu anda C++ holografik proje şablonunda kullanılan C++17 uyumlu C++/WinRT yerine C++/CX kullanımını göstermektedir. Kavramlar C++/WinRT projesi için eşdeğerdir, ancak kodu çevirmeniz gerekir.

Windows'ta uzamsal koordinat sistemleri

Windows'ta gerçek dünya koordinat sistemleri hakkında gerekçe vermek için kullanılan çekirdek türü SpatialCoordinateSystem'dır. Bu türün bir örneği rastgele bir koordinat sistemini temsil eder ve her birinin ayrıntılarını anlamadan iki koordinat sistemi arasında dönüşüm yapmak için kullanabileceğiniz dönüştürme matrisi verilerini almak için bir yöntem sağlar.

Uzamsal bilgi döndüren yöntemler, bu koordinatların döndürülmesi için en kullanışlı koordinat sistemine karar vermenize olanak tanıyan spatialcoordinateSystem parametresini kabul eder. Uzamsal bilgiler kullanıcının çevresindeki noktalar, ışınlar veya birimler olarak temsil edilir ve bu koordinatların birimleri her zaman metre cinsinden olur.

SpatialCoordinateSystem, cihazın konumunu temsil eden sistemler de dahil olmak üzere diğer koordinat sistemleriyle dinamik bir ilişkiye sahiptir. Herhangi bir noktada cihaz bazı koordinat sistemlerini bulabilir ve diğerlerini bulamaz. Çoğu koordinat sistemi için uygulamanızın bulunamayacakları zaman aralıklarını işlemeye hazır olması gerekir.

Uygulamanız SpatialCoordinateSystems'ı doğrudan oluşturmamalıdır; bunun yerine Algı API'leri aracılığıyla kullanılmalıdır. Algı API'lerinde koordinat sistemlerinin üç temel kaynağı vardır ve bunların her biri Koordinat sistemleri sayfasında açıklanan bir kavramla eşlenir:

Bu nesneler tarafından döndürülen tüm koordinat sistemleri sağ elle kullanılır ve +y yukarı, sağda +x ve geriye doğru +z olur. Sol veya sağ elinizin parmaklarını pozitif x yönünde işaret ederek ve pozitif y yönüne kıvrarak pozitif z ekseni noktalarının hangi yönü olduğunu hatırlayabilirsiniz. Başparmak noktanızın size doğru veya sizden uzak yönü, bu koordinat sistemi için pozitif z ekseni noktalarının yönüdür. Aşağıdaki çizimde bu iki koordinat sistemi gösterilmektedir.

Sol ve sağ koordinat sistemleri
Sol ve sağ koordinat sistemleri

SpatialLocator sınıfını kullanarak HoloLens konumuna göre bir SpatialCoordinateSystem içine bootstrap için ekli veya sabit bir başvuru çerçevesi oluşturun. Bu işlem hakkında daha fazla bilgi edinmek için sonraki bölüme geçin.

Uzamsal bir aşama kullanarak hologramları dünyaya yerleştirme

Donuk Windows Mixed Reality çevreleyici başlıklar için koordinat sistemine static SpatialStageFrameOfReference::Current özelliği kullanılarak erişilir. Bu API şunları sağlar:

  • Koordinat sistemi
  • Oyuncunun koltuğunda mı yoksa cep telefonunda mı olduğu hakkında bilgi
  • Oyuncu hareket halindeyken gezinmek için güvenli bir alanın sınırı
  • Mikrofonlu kulaklığın yön bilgisi olup olmadığını gösteren bir gösterge.
  • Uzamsal aşamaya yönelik güncelleştirmeler için bir olay işleyicisi.

İlk olarak uzamsal aşamayı alacağız ve güncelleştirmelere abone olacağız:

Uzamsal aşama başlatma kodu

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);
}

OnCurrentChanged yönteminde uygulamanız uzamsal aşamayı incelemeli ve oynatıcı deneyimini güncelleştirmelidir. Bu örnekte, aşama sınırının ve kullanıcı tarafından belirtilen başlangıç konumunun ve aşamanın görünüm aralığının ve hareket özellikleri aralığının bir görselleştirmesini sağlarız. Ayrıca bir aşama sağlanamadığında kendi sabit koordinat sistemimize geri döneriz.

Uzamsal aşama güncelleştirmesi için kod

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);
        }
    }
}

Aşama sınırını tanımlayan köşe kümesi saat yönünde sağlanır. Windows Mixed Reality kabuğu, kullanıcı yaklaştığında sınıra bir çit çeker, ancak izlenebilir alanı kendi amaçlarınız için üçgenleştirmek isteyebilirsiniz. Aşamayı üçgenleştirmek için aşağıdaki algoritma kullanılabilir.

Uzamsal aşama üçgenleştirme kodu

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;
}

Sabit bir başvuru çerçevesi kullanarak hologramları dünyaya yerleştirme

SpatialStationaryFrameOfReference sınıfı, kullanıcı hareket ettikçe kullanıcının çevresine göre sabit kalan bir başvuru çerçevesini temsil eder. Bu başvuru çerçevesi, koordinatların cihaz yakınında kararlı tutulmasına öncelik sağlar. SpatialStationaryFrameOfReference'ın temel kullanımlarından biri, hologramları oluştururken bir işleme altyapısı içinde temel dünya koordinat sistemi olarak hareket etmektir.

SpatialStationaryFrameOfReference almak için SpatialLocator sınıfını kullanın ve CreateStationaryFrameOfReferenceAtCurrentLocation öğesini çağırın.

Windows Holographic uygulama şablonu kodundan:

           // 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();
  • Sabit başvuru çerçeveleri, genel alana göre en uygun konumu sağlayacak şekilde tasarlanmıştır. Bu başvuru çerçevesi içindeki tek tek konumların biraz kaymalarına izin verilir. Cihaz ortam hakkında daha fazla bilgi edindiği için bu normaldir.
  • Tek hologramların hassas bir şekilde yerleştirilmesi gerektiğinde, tek hologramı gerçek dünyadaki bir konuma sabitlemek için bir SpatialAnchor kullanılmalıdır; örneğin, kullanıcının özel ilgi çekici olduğunu belirttiği bir nokta. Yer işareti konumları kaymaz, ancak düzeltilebilir; yer işareti, düzeltme gerçekleştikten sonra sonraki çerçeveden başlayarak düzeltilmiş konumu kullanır.

Uzamsal yer işaretleri kullanarak hologramları dünyaya yerleştirme

Uzamsal tutturucular hologramları gerçek dünyada belirli bir yere yerleştirmek için harika bir yoldur ve sistem yer işaretin zaman içinde yerinde kalmasını sağlar. Bu konuda yer işareti oluşturma ve kullanma ve yer işareti verileriyle çalışma açıklanmaktadır.

SpatialCoordinateSystem içinde istediğiniz konumda ve yönlendirmede bir SpatialAnchor oluşturabilirsiniz. Cihazın şu anda bu koordinat sistemini bulabilmesi ve sistemin uzamsal yer işareti sınırına ulaşmamış olması gerekir.

Tanımlandıktan sonra SpatialAnchor'un koordinat sistemi, ilk konumunun tam konumunu ve yönlendirmesini korumak için sürekli olarak ayarlanır. Daha sonra bu SpatialAnchor'u kullanarak kullanıcının çevresinde tam olarak o konumda sabit görünecek hologramları işleyebilirsiniz.

Yer işaretinden uzaklık arttıkça, tutturucuyu yerinde tutan ayarlamaların etkileri büyütülmektedir. İçeriğin yer işaretinden yaklaşık 3 metre uzakta olan bir yer işaretine göre işlenmesini önlemeniz gerekir.

CoordinateSystem özelliği, yer işaretine göre içerik yerleştirmenize olanak tanıyan bir koordinat sistemi alır ve cihaz tutturucunun hassas konumunu ayarlarken kolaylaştırma uygulanır.

Bu ayarlamaları kendiniz yönetmek için RawCoordinateSystem özelliğini ve buna karşılık gelen RawCoordinateSystemAdjusted olayını kullanın.

Uzamsal tutturucuları kalıcı hale ve paylaşma

SpatialAnchorStore sınıfını kullanarak SpatialAnchor'u yerel olarak kalıcı hale getirebilirsiniz ve ardından aynı HoloLens cihazında gelecekteki bir uygulama oturumunda geri alabilirsiniz.

Azure Spatial Anchors'ı kullanarak, uygulamanızın birden çok HoloLens, iOS ve Android cihazında bulabildiği yerel bir SpatialAnchor'dan dayanıklı bir bulut bağlantısı oluşturabilirsiniz. Birden çok cihaz arasında ortak bir uzamsal yer işareti paylaşan her kullanıcı, gerçek zamanlı olarak aynı fiziksel konumda yer işaretine göre işlenen içeriği görebilir.

HoloLens, iOS ve Android cihazlarda zaman uyumsuz hologram kalıcılığı için Azure Spatial Anchors'ı da kullanabilirsiniz. Dayanıklı bir bulut uzamsal tutturucuyu paylaşarak, bu cihazlar aynı anda birlikte bulunmasa bile, birden çok cihaz zaman içinde aynı kalıcı hologramı gözlemleyebilir.

HoloLens uygulamanızda paylaşılan deneyimler oluşturmaya başlamak için 5 dakikalık Azure Spatial Anchors HoloLens hızlı başlangıcını deneyin.

Azure Spatial Anchors ile çalışmaya başlayıp çalışmaya devam ettikten sonra HoloLens'te yer işaretleri oluşturabilir ve bulabilirsiniz. İzlenecek yollar Android ve iOS için de kullanılabilir ve tüm cihazlarda aynı yer işaretleri paylaşmanızı sağlar.

Holografik içerik için SpatialAnchors oluşturma

Bu kod örneği için, Basılı hareket algılandığında yer işaretleri oluşturmak için Windows Holographic uygulama şablonunu değiştirdik. Küp daha sonra işleme geçişi sırasında yer işaretine yerleştirilir.

Yardımcı sınıfı tarafından birden çok yer işareti desteklendiği için, bu kod örneğini kullanmak istediğimiz kadar küp yerleştirebiliriz!

Not

Yer işaretleri için kimlikler, uygulamanızda denetlediğiniz bir şeydir. Bu örnekte, uygulamanın tutturucu koleksiyonunda depolanan yer işareti sayısına bağlı olarak sıralı bir adlandırma düzeni oluşturduk.

   // 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);
           }
       }
   }

SpatialAnchorStore'nu zaman uyumsuz olarak yükleme ve önbelleğe alma

Bu kalıcılığı işlemeye yardımcı olan bir SampleSpatialAnchorHelper sınıfının nasıl yazıldığını görelim:

  • Platform::String anahtarı tarafından dizine alınan bellek içi yer işaretleri koleksiyonunu depolama.
  • Sistemin yerel bellek içi koleksiyonundan ayrı tutulan SpatialAnchorStore'ndan tutturucular yükleniyor.
  • Uygulama bunu yapmayı seçtiğinde yerel bellek içi yer işaretleri koleksiyonunu SpatialAnchorStore'na kaydetme.

SpatialAnchorStore'nda SpatialAnchor nesnelerini kaydetme burada anlatılı.

Sınıf başlatıldığında SpatialAnchorStore'nu zaman uyumsuz olarak istiyoruz. Api yer işareti deposunu yükledikçe sistem G/Ç'sini içerir ve G/Ç'nin engelleyici olmadığından bu API zaman uyumsuz hale getirilir.

   // 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;
   });

Yer işaretleri kaydetmek için kullanabileceğiniz bir SpatialAnchorStore verilir. Bu, Dize olan anahtar değerlerini SpatialAnchor olan veri değerleriyle ilişkilendiren bir IMapView'dır. Örnek kodumuzda bunu yardımcı sınıfımızın genel işlevi aracılığıyla erişilebilen özel sınıf üyesi değişkeninde depolarız.

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

Not

Tutturucu depoyu kaydetmek ve yüklemek için askıya alma/sürdürme olaylarını bağlamayı unutmayın.

   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();
   }

İçeriği yer işareti deposuna kaydetme

Sistem uygulamanızı askıya alırken uzamsal yer işaretlerinizi yer işareti deposuna kaydetmeniz gerekir. Ayrıca, uygulamanızın uygulaması için gerekli olduğunu fark ettiğiniz için tutturucuları diğer zamanlarda yer işareti deposuna kaydetmeyi de seçebilirsiniz.

Bellek içi sabit noktalarını SpatialAnchorStore'na kaydetmeye hazır olduğunuzda, koleksiyonunuzda döngü yapabilir ve her birini kaydetmeyi deneyebilirsiniz.

   // 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;
   }

Uygulama devam ettiğinde yer işareti deposundan içerik yükleme

AnchorStore'nda kaydedilmiş tutturucuları, uygulamanız devam ettiğinde veya istediğiniz zaman anchor store'un IMapView'ından kendi bellek içi SpatialAnchors veritabanınıza aktararak geri yükleyebilirsiniz.

SpatialAnchorStore'ndan tutturucuları geri yüklemek için ilgilendiğiniz her birini kendi bellek içi koleksiyonunuza geri yükleyin.

Dizeleri oluşturduğunuz SpatialAnchors ile ilişkilendirmek için kendi bellek içi SpatialAnchors veritabanınıza ihtiyacınız vardır. Örnek kodumuzda, sabitleri depolamak için Windows::Foundation::Collections::IMap kullanmayı seçiyoruz; bu da SpatialAnchorStore için aynı anahtarı ve veri değerini kullanmayı kolaylaştırır.

   // 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;

Not

Geri yüklenen bir yer işareti hemen locatable olmayabilir. Örneğin, ayrı bir odada veya tamamen farklı bir binada yer işareti olabilir. AnchorStore'ndan alınan yer işaretleri kullanmadan önce locatability için test edilmelidir.


Not

Bu örnek kodda AnchorStore'ndan tüm yer işaretleri alınıyor. Bu bir gereksinim değildir; uygulamanız uygulamanız için anlamlı dize anahtar değerlerini kullanarak belirli bir yer işareti alt kümesini seçip seçebilir.

   // 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);
           }
       }
   }

Gerektiğinde yer işareti depoyu temizleyin

Bazen uygulama durumunu temizlemeniz ve yeni veriler yazmanız gerekir. SpatialAnchorStore ile bunu şu şekilde yapabilirsiniz.

Yardımcı sınıfımızı kullanarak Clear işlevini sarmalamanız neredeyse gereksizdir. Bunu örnek uygulamamızda yapmayı tercih ediyoruz çünkü yardımcı sınıfımıza SpatialAnchorStore örneğine sahip olmak sorumluluğu verilir.

   // 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();
       }
   }

Örnek: Yer işareti koordinat sistemlerini sabit referans çerçeve koordinat sistemleriyle ilişkili

Bir tutturucunuz olduğunu ve yer işaretinizin koordinat sistemindeki bir şeyi diğer içeriğiniz için zaten kullanmakta olduğunuz SpatialStationaryReferenceFrame ile ilişkilendirmek istediğinizi varsayalım. Yer işareti koordinat sisteminden sabit başvuru çerçevesine bir dönüşüm almak için TryGetTransformTo kullanabilirsiniz:

   // 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;
   }

Bu işlem sizin için iki şekilde yararlıdır:

  1. İki başvuru çerçevesinin birbirine göre anlaşılıp anlaşılamadığını ve
  2. Bu durumda, doğrudan bir koordinat sisteminden diğerine geçmeniz için bir dönüşüm sağlar.

Bu bilgilerle, iki başvuru çerçevesi arasındaki nesneler arasındaki uzamsal ilişkiyi anlamış olacaksınız.

İşleme için genellikle nesneleri özgün başvuru çerçevelerine veya tutturucularına göre gruplandırarak daha iyi sonuçlar elde edebilirsiniz. Her grup için ayrı bir çizim geçişi gerçekleştirin. Görünüm matrisleri, başlangıçta aynı koordinat sistemi kullanılarak oluşturulan model dönüşümlerine sahip nesneler için daha doğru olur.

Cihaza bağlı başvuru çerçevesini kullanarak hologramlar oluşturma

Bazen cihazın konumuna bağlı olarak kalan bir hologramı işlemek isteyebilirsiniz. Örneğin, hata ayıklama bilgileri içeren bir panel veya cihazın boşluktaki konumunu değil yalnızca yönlendirmesini belirleyebileceği bir bilgilendirme iletisi. Bunu başarmak için ekli bir başvuru çerçevesi kullanırız.

SpatialLocatorAttachedFrameOfReference sınıfı, gerçek dünya yerine cihaza göre olan koordinat sistemlerini tanımlar. Bu çerçevenin, kullanıcının çevresine göre, başvuru çerçevesi oluşturulduğunda kullanıcının karşılaştığı yöne işaret eden sabit bir başlığı vardır. Bundan sonra, bu başvuru çerçevesindeki tüm yönlendirmeler, kullanıcı cihazı döndürse bile bu sabit başlığa göre belirlenir.

HoloLens için, bu çerçevenin koordinat sisteminin kaynağı kullanıcının kafasının döndürme merkezinde bulunur, böylece konumu baş döndürmeden etkilenmez. Uygulamanız, hologramları kullanıcının önüne yerleştirmek için bu noktaya göre bir uzaklık belirtebilir.

SpatialLocatorAttachedFrameOfReference almak için SpatialLocator sınıfını kullanın ve CreateAttachedFrameOfReferenceAtCurrentHeading öğesini çağırın.

Bu, Windows Mixed Reality cihaz aralığının tamamı için geçerlidir.

Cihaza bağlı bir başvuru çerçevesi kullanma

Bu bölümlerde, bu API'yi kullanarak cihaza bağlı bir başvuru çerçevesini etkinleştirmek için Windows Holographic uygulama şablonunda nelerin değiştirildiği anlatılır. Bu "bağlı" hologram sabit veya sabit hologramlarla birlikte çalışır ve cihaz dünyadaki konumunu geçici olarak bulamadıklarında da kullanılabilir.

İlk olarak şablonu SpatialStationaryFrameOfReference yerine SpatialLocatorAttachedFrameOfReference depolamak üzere değiştirdik:

HolographicTagAlongSampleMain.h'den:

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

HolographicTagAlongSampleMain.cpp dosyasından:

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

Güncelleştirme sırasında artık kare tahminiyle elde edilen zaman damgasında koordinat sistemini elde ediyoruz.

   // 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);

Uzamsal işaretçi pozu alın ve kullanıcının Bakışını izleyin

Holografik kabuğun kullanıcının bakışını izlemesine benzer şekilde, örnek hologramımızın kullanıcının bakışını izlemesini istiyoruz. Bunun için SpatialPointerPose'u aynı zaman damgasından almalıyız.

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

Bu SpatialPointerPose, hologramı kullanıcının geçerli başlığına göre konumlandırmak için gereken bilgilere sahiptir.

Kullanıcı rahatlığı için, belirli bir süre boyunca konum değişikliğini düzeltmek için doğrusal ilişkilendirme ("lerp") kullanırız. Bu, kullanıcı için hologramı bakışlarına kilitlemekten daha rahattır. Etiketle birlikte hologramın konumunun lerlenmesi, hareketi sönümleyerek hologramı dengelememizi de sağlar. Bu nemlendirmeyi biz yapmasaydık, normalde kullanıcının kafasının algılanamaz hareketleri olarak kabul edilenler nedeniyle kullanıcı hologram dalgalanmasını görebilirdi.

StationaryQuadRenderer::P ositionHologram'dan:

   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);
   }

Not

Hata ayıklama paneli söz konusu olduğunda, hologramı görünümünüzü engellememesi için biraz kenara konumlandırmayı seçebilirsiniz. Bunu nasıl yapabileceğinize dair bir örnek aşağıda verilmiştir.

StationaryQuadRenderer::P ositionHologram için:

       // 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));
       */

Hologramı kamerayla yüz yüze gelecek şekilde döndürme

Hologramı konumlandırmak yeterli değildir, bu durumda dörtlüdür; ayrıca nesneyi kullanıcıyla yüz yüze gelecek şekilde döndürmemiz gerekir. Bu dönüş dünya uzayında gerçekleşir, çünkü bu tür reklam panoları hologramın kullanıcının ortamının bir parçası olarak kalmasına izin verir. Hologram ekran yönüne kilitlendiğinden, görüntüleme alanı reklam panoları o kadar rahat değildir; Bu durumda, stereo işlemeyi kesintiye uğratmayan bir görüntüleme alanı reklam panosu dönüşümü elde etmek için sol ve sağ görünüm matrisleri arasında da ilişkilendirmeniz gerekir. Burada, kullanıcıyla yüzleşmek için X ve Z eksenlerinde döndüreceğiz.

StationaryQuadRenderer::Update'den:

   // 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));

Ekli hologramı işleme

Bu örnekte hologramı, hologramı konumlandırdığımız SpatialLocatorAttachedReferenceFrame koordinat sisteminde işlemeyi de seçiyoruz. (Başka bir koordinat sistemi kullanarak işlemeye karar verseydik, cihaz bağlı başvuru çerçevesinin koordinat sisteminden bu koordinat sistemine bir dönüşüm elde etmemiz gerekirdi.)

HolographicTagAlongSampleMain::Render'dan:

   // 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)
       );

İşte bu kadar! Hologram artık kullanıcının bakış yönünün 2 metre önünde bir konumu "kovalayacak".

Not

Bu örnek ayrıca ek içerik de yükler. Bkz. StationaryQuadRenderer.cpp.

İzleme kaybını işleme

Cihaz kendini dünyada bulamıyorsa, uygulama "kayıp izleme" deneyimi yaşar. Windows Mixed Reality uygulamaların konum izleme sisteminde bu tür kesintileri işleyebilmesi gerekir. Bu kesintiler, varsayılan SpatialLocator üzerindeki LocatabilityChanged olayı kullanılarak gözlemlenebilir ve yanıtlar oluşturulabilir.

AppMain::SetHolographicSpace'den:

   // 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)
               );

Uygulamanız bir LocatabilityChanged olayı aldığında, davranışı gerektiği gibi değiştirebilir. Örneğin, PositionalTrackingInhibited durumunda uygulamanız normal işlemi duraklatabilir ve uyarı iletisi görüntüleyen bir etiket boyunca hologram işleyebilir.

Windows Holographic uygulama şablonu, sizin için önceden oluşturulmuş bir LocatabilityChanged işleyicisi ile birlikte gelir. Varsayılan olarak, konum izleme kullanılamadığında hata ayıklama konsolunda bir uyarı görüntüler. Uygulamanızdan gerektiğinde yanıt sağlamak için bu işleyiciye kod ekleyebilirsiniz.

AppMain.cpp dosyasından:

   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;
       }
   }

Uzamsal eşleme

Uzamsal eşleme API'leri, yüzey çizgileri için model dönüşümleri almak için koordinat sistemlerini kullanır.

Ayrıca bkz.