DirectX'te koordinat sistemleri
Not
Bu makale, eski WinRT yerel API'leriyle ilgilidir. Yeni yerel uygulama projeleri için OpenXR API'sini kullanmanızı öneririz.
Koordinat sistemleri, Windows Karma Gerçeklik API'leri tarafından sunulan uzamsal anlayış için temel oluşturur.
Günümüzün oturulan VR veya tek odalı VR cihazları, izlenen alanları için tek bir birincil koordinat sistemi oluşturur. HoloLens gibi Karma Gerçeklik cihazlar büyük tanımsız ortamlar için tasarlanmıştır ve kullanıcı gezindikçe cihazın çevresini bulması ve öğrenmesi sağlanır. Cihaz, kullanıcının odaları hakkındaki bilgileri sürekli geliştirmeye uyum sağlar, ancak uygulamalar ömrü boyunca birbiriyle ilişkilerini değiştiren koordinat sistemleriyle sonuçlanabilir. Windows Karma Gerçeklik, bilgisayarlı çevreleyici kulaklıklardan dünyaya bağlı referans çerçevelerine kadar geniş bir yelpazedeki cihazları 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 bir 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 mantık yürütmede kullanılan çekirdek türü SpatialCoordinateSystem'dır. Bu türdeki bir örnek 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 sağlayan 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 üç ana kaynağı vardır ve bunların her biri Koordinat sistemleri sayfasında açıklanan bir kavramla eşlenir:
- Sabit bir başvuru çerçevesi almak için SpatialStationaryFrameOfReference oluşturun veya geçerli SpatialStageFrameOfReference'dan bir tane alın.
- Uzamsal bir yer işareti almak için bir SpatialAnchor oluşturun.
- Ekli bir başvuru çerçevesi almak için SpatialLocatorAttachedFrameOfReference oluşturun.
Bu nesneler tarafından döndürülen tüm koordinat sistemleri sağ elle kullanılır ve +y yukarı, +x sağda ve +z geriye doğru olur. Pozitif x yönünde sol veya sağ elinizin parmaklarını işaret edip 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
SpatialLocator sınıfını kullanarak HoloLens konumunu temel alan bir SpatialCoordinateSystem'a 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.
Hologramları uzamsal bir aşama kullanarak dünyaya yerleştirme
Opak Windows Karma Gerçeklik çevreleyici mikrofonlu kulaklıklar için koordinat sistemine static SpatialStageFrameOfReference::Current özelliği kullanılarak erişilir. Bu API şunları sağlar:
- Koordinat sistemi
- Oyuncunun oturup oturmadığı veya cep telefonuyla ilgili bilgiler
- Oyuncunun mobil olması durumunda gezinmek için güvenli bir alanın sınırı
- Mikrofonlu kulaklığın yönlü 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 oyuncu 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üş aralığının ve hareket özellikleri aralığının bir görselleştirmesini sağlıyoruz. 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 sırasıyla sağlanır. Windows Karma Gerçeklik kabuğu, kullanıcı yaklaştığında sınıra bir çit çizer, 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 referans ç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ın yakınında kararlı tutulmasına öncelik sağlar. SpatialStationaryFrameOfReference'ın temel kullanımlarından biri, hologramları oluştururken işleme altyapısı içinde temel alınan 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 kayarak kaymalarına izin verilir. Cihaz ortam hakkında daha fazla bilgi edindiği için bu normaldir.
- Tek tek hologramların tam olarak 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 bir sonraki çerçeveden başlayarak düzeltilmiş konumu kullanır.
Uzamsal çapaları kullanarak hologramları dünyaya yerleştirme
Uzamsal tutturucular hologramları gerçek dünyada belirli bir yere yerleştirmenin harika bir yoludur ve sistem bağlantı noktasının zaman içinde yerinde kalmasını sağlar. Bu konuda yer işareti oluşturma ve kullanma ve bağlantı verileriyle çalışma açıklanmaktadır.
SpatialCoordinateSystem içinde istediğiniz konumda ve yönde bir SpatialAnchor oluşturabilirsiniz. Cihazın şu anda bu koordinat sistemini bulabilmesi ve sistemin uzamsal bağlantı 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. Ardından bu SpatialAnchor'u kullanarak kullanıcının çevresinde tam olarak bu konumda düzeltilecek hologramları işleyebilirsiniz.
Tutturucuyu yerinde tutan ayarlamaların etkileri, tutturucudan uzaklık arttıkça büyütülmektedir. İçeriğin, bu bağlantının kaynağından 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.
SpatialAnchorStore sınıfını kullanarak bir SpatialAnchor'u yerel olarak kalıcı hale getirebilirsiniz ve ardından aynı HoloLens cihazında gelecekteki bir uygulama oturumunda geri alabilirsiniz.
Holografik içerik için SpatialAnchors oluşturma
Bu kod örneği için, Basılan hareket algılandığında tutturucular 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 göre 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'u zaman uyumsuz olarak yükleme ve önbellek
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'dan bağlantı 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ır.
Sınıf başlatıldığında SpatialAnchorStore'yu zaman uyumsuz olarak istiyoruz. API bağlantı deposunu yükledikçe sistem G/Ç'sini içerir ve bu API zaman uyumsuz hale getirildiğinden G/Ç engelleyici değildir.
// 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 verilecektir. 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 bir ö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 uygulanması için gerekli olduğunu fark ettiğiniz için yer işaretleri diğer zamanlarda yer işareti deposuna kaydetmeyi de seçebilirsiniz.
Bellek içi tutturucuları SpatialAnchorStore'ya 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'ndaki 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 yer işaretleri geri yüklemek için ilgilendiğiniz her birini kendi bellek içi koleksiyonunuzla 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, yer İşaretlerini depolamak için Windows::Foundation::Collections::IMap kullanmayı seçiyoruz ve bu da SpatialAnchorStore için aynı anahtarı ve veri değerini kullanmayı kolaylaştırıyor.
// 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 tutturucuları alıyoruz. Bu bir gereksinim değildir; uygulamanız uygulamanız için anlamlı olan Dize anahtarı değerlerini kullanarak belirli bir bağlantı 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 tutturucu 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ı seçeriz çü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: Sabit referans çerçevesi koordinat sistemleriyle bağlantı koordinat sistemlerinin ilişkili olması
Bir bağlantınız 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. Bağlantının 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:
- İki başvuru çerçevesinin birbirine göre anlaşılıp anlaşılamadığını bildirir ve;
- Bu durumda, doğrudan bir koordinat sisteminden diğerine geçmek 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ı kalan bir hologramı işlemek isteyebilirsiniz. Örneğin, hata ayıklama bilgilerini 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çeve, kullanıcının çevresine göre, başvuru çerçevesi oluşturulduğunda kullanıcının karşılaştığı yönü gösteren sabit bir başlığa sahiptir. 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 Karma Gerçeklik 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 neleri değiştirdiğimiz anlatılır. Bu "bağlı" hologram sabit veya bağlantılı hologramlarla birlikte çalışır ve cihaz geçici olarak dünyadaki konumunu bulamadıklarında da kullanılabilir.
İlk olarak, şablonu SpatialStationaryFrameOfReference yerine SpatialLocatorAttachedFrameOfReference depolamak için değiştirdik:
HolographicTagAlongSampleMain.h'den:
// A reference frame attached to the holographic camera.
Windows::Perception::Spatial::SpatialLocatorAttachedFrameOfReference^ m_referenceFrame;
HolographicTagAlongSampleMain.cpp:
// In this example, we create a reference frame attached to the device.
m_referenceFrame = m_locator->CreateAttachedFrameOfReferenceAtCurrentHeading();
Güncelleştirme sırasında, şimdi kare tahmini ile 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'yi 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ı konforu 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, hologramı hareketi sönümleyerek stabilize etmemizi 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 değişimini 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 yana konumlandırabilirsiniz. Bunu nasıl yapabileceğinize dair bir örnek aşağıda verilmiştır.
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üzleşmek için döndürme
Hologramı konumlandırmak yeterli değildir, bu durumda dörtlüdür; kullanıcıyla yüzleşmek için nesneyi de döndürmemiz gerekir. Bu dönüş dünya uzayında gerçekleşir, çünkü bu tür bir reklam panosu 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ı panoları o kadar rahat değildir; bu durumda, stereo işlemeyi kesintiye uğratmayan bir görüntüleme alanı pano 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'dan ::Güncelleştirme:
// 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 hepsi bu! Hologram artık kullanıcının bakış yönünün önünde 2 metre olan bir konumu "kovalayacak".
Not
Bu örnekte ek içerik de yüklenir. Bkz. StationaryQuadRenderer.cpp.
İzleme kaybını işleme
Cihaz kendini dünyada bulamıyorsa, uygulama "kayıp izleme" ile karşılaşır. Windows Karma Gerçeklik uygulamaları, konumsal izleme sisteminde bu tür kesintileri işleyebilmelidir. Bu kesintiler gözlemlenebilir ve varsayılan SpatialLocator üzerindeki LocatabilityChanged olayı kullanılarak 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, gerektiğinde davranışı değiştirebilir. Örneğin, PositionalTrackingInhibited durumunda uygulamanız normal işlemi duraklatabilir ve bir uyarı iletisi görüntüleyen etiket boyunca bir 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ği gibi bir yanıt sağlamak için bu işleyiciye kod ekleyebilirsiniz.
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;
}
}
Uzamsal eşleme
Uzamsal eşleme API'leri, yüzey kafesleri için model dönüşümlerini almak için koordinat sistemlerini kullanır.