Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Evrensel Windows Platformu (UWP) uygulamanız, DisplayInformation::OrientationChanged olayını işlerken birden çok ekran yönünü destekleyebilir. Burada, Windows 10 cihazının grafik donanımının verimli ve etkili bir şekilde kullanılması için UWP DirectX uygulamanızda ekran döndürmeyi işlemeye yönelik en iyi yöntemleri ele alacağız.
Başlamadan önce, grafik donanımının cihazın yönlendirmesine bakılmaksızın piksel verilerini her zaman aynı şekilde çıkış olarak dışarı aktardığını unutmayın. Windows 10 cihazları mevcut ekran yönelimlerini belirleyebilir (bir tür algılayıcıyla veya yazılım üzerinden bir düğmeyle) ve kullanıcıların ekran ayarlarını değiştirmesine izin verebilir. Bu nedenle Windows 10, görüntülerin döndürme işlemini cihazın yönlendirmesine göre "dik" olduklarından emin olmak için işler. Varsayılan olarak, uygulamanız bir yönün değiştiğine ilişkin bildirimi (örneğin, bir pencere boyutu) alır. Bu durumda, Windows 10 görüntüyü son ekran için hemen döndürür. Dört belirli ekran yönlendirmesinin üçü için (daha sonra ele alınmalıdır), Windows 10 son görüntüyü görüntülemek için ek grafik kaynakları ve hesaplama kullanır.
UWP DirectX uygulamaları için DisplayInformation nesnesi, uygulamanızın sorgulayabileceğiniz temel görüntüleme yönlendirme verilerini sağlar. Varsayılan yön, ekranın piksel genişliğinin yükseklikten daha büyük olduğu yatay
Windows 10 dört özel görüntü yönlendirme modu tanımlar:
- Yatay— Windows 10'un varsayılan görüntüleme yönüdür ve döndürme için temel veya referans açısı (0 derece) olarak kabul edilir.
- Portre: Ekran saat yönünde 90 derece (veya saat yönünün tersine 270 derece) döndürülmüştür.
- Manzara, ters çevrilmiş—ekran 180 derece döndürüldü (baş aşağı çevrildi).
- Portre modu, çevrilmiş—ekran saat yönünde 270 derece (veya saat yönünün tersine 90 derece) döndürülmüştür.
Ekran bir yönlendirmeden diğerine döndüğünde Windows 10, çizilen görüntüyü yeni yönlendirmeyle hizalamak için dahili olarak bir döndürme işlemi gerçekleştirir ve kullanıcı ekranda dik bir görüntü görür.
Ayrıca Windows 10, bir yönlendirmeden diğerine geçerken sorunsuz bir kullanıcı deneyimi oluşturmak için otomatik geçiş animasyonları görüntüler. Görüntü yönü değiştikçe, kullanıcı bu kaydırmaları görüntülenen ekran görüntüsünün sabit bir yakınlaştırma ve döndürme animasyonu olarak görür. Windows 10, yeni yöne geçişte düzen için uygulamaya zaman ayırır.
Genel olarak, bu, ekran yönlendirmesindeki değişiklikleri işlemeye yönelik genel işlemdir:
- Değiştirme zincirini cihazın yerel görüntüleme yönüyle uyumlu tutmak için pencere sınırları değerlerinin ve görüntüleme yönlendirme verilerinin bir bileşimini kullanın.
- IDXGISwapChain1::SetRotationkullanarak Değiştirme zincirinin yönünü Windows 10'a bildirin.
- İşleme kodunu değiştirerek cihazın kullanıcı yönlendirmesiyle hizalanmış görüntüler oluşturun.
Değişim zincirini yeniden boyutlandırma ve içeriğini önceden yönlendirme
UWP DirectX uygulamanızda temel bir ekran yeniden boyutlandırma ve içeriğini önceden döndürme gerçekleştirmek için şu adımları uygulayın:
- DisplayInformation::OrientationChanged olayını işleyin.
- Pencerenin yeni boyutlarına göre takas zincirini yeniden boyutlandırın.
- Değiştirme zincirinin yönünü ayarlamak için IDXGISwapChain1::SetRotation
çağrısı yapın. - İşleme hedefleriniz ve diğer piksel veri arabellekleri gibi pencere boyutuna bağlı kaynakları yeniden oluşturun.
Şimdi bu adımlara biraz daha ayrıntılı bir şekilde bakalım.
İlk adımınız, DisplayInformation::OrientationChanged olayı için bir işleyici kaydetmektir. Bu olay, ekran yönü her değiştiğinde (örneğin, ekran döndürülürken) uygulamanızda oluşturulur.
DisplayInformation::OrientationChanged olayını işlemek için, görünüm sağlayıcınızın uygulaması gereken IFrameworkView arabiriminin yöntemlerinden biri olan gerekli SetWindow yönteminde DisplayInformation::OrientationChanged işleyicinizi bağlarsınız.
Bu kod örneğinde, DisplayInformation::OrientationChanged için olay işleyicisi olan OnOrientationChangedadlı bir yöntemdir. DisplayInformation::OrientationChanged başlatıldığında, SetCurrentOrientation adlı bir yöntemi çağırır ve ardından CreateWindowSizeDependentResourcesçağırır.
void App::SetWindow(CoreWindow^ window)
{
// ... Other UI event handlers assigned here ...
currentDisplayInformation->OrientationChanged +=
ref new TypedEventHandler<DisplayInformation^, Object^>(this, &App::OnOrientationChanged);
// ...
}
}
void App::OnOrientationChanged(DisplayInformation^ sender, Object^ args)
{
m_deviceResources->SetCurrentOrientation(sender->CurrentOrientation);
m_main->CreateWindowSizeDependentResources();
}
// This method is called in the event handler for the OrientationChanged event.
void DX::DeviceResources::SetCurrentOrientation(DisplayOrientations currentOrientation)
{
if (m_currentOrientation != currentOrientation)
{
m_currentOrientation = currentOrientation;
CreateWindowSizeDependentResources();
}
}
Ardından, yeni ekran yönlendirmesi için değiştirme zincirini yeniden boyutlandırıp işleme gerçekleştirilirken grafik işlem hattının içeriğini döndürmek için hazırlarsınız. Bu örnekte DirectXBase::CreateWindowSizeDependentResources, IDXGISwapChain::ResizeBuffers çağrısını, 3B ve 2B döndürme matrisini ayarlamayı, SetRotation'ı çağırmayı ve kaynaklarınızı yeniden oluşturmayı işleyen bir yöntemdir.
void DX::DeviceResources::CreateWindowSizeDependentResources()
{
// Clear the previous window size specific context.
ID3D11RenderTargetView* nullViews[] = {nullptr};
m_d3dContext->OMSetRenderTargets(ARRAYSIZE(nullViews), nullViews, nullptr);
m_d3dRenderTargetView = nullptr;
m_d2dContext->SetTarget(nullptr);
m_d2dTargetBitmap = nullptr;
m_d3dDepthStencilView = nullptr;
m_d3dContext->Flush();
// Calculate the necessary render target size in pixels.
m_outputSize.Width = DX::ConvertDipsToPixels(m_logicalSize.Width, m_dpi);
m_outputSize.Height = DX::ConvertDipsToPixels(m_logicalSize.Height, m_dpi);
// Prevent zero size DirectX content from being created.
m_outputSize.Width = max(m_outputSize.Width, 1);
m_outputSize.Height = max(m_outputSize.Height, 1);
// The width and height of the swap chain must be based on the window's
// natively-oriented width and height. If the window is not in the native
// orientation, the dimensions must be reversed.
DXGI_MODE_ROTATION displayRotation = ComputeDisplayRotation();
bool swapDimensions = displayRotation == DXGI_MODE_ROTATION_ROTATE90 || displayRotation == DXGI_MODE_ROTATION_ROTATE270;
m_d3dRenderTargetSize.Width = swapDimensions ? m_outputSize.Height : m_outputSize.Width;
m_d3dRenderTargetSize.Height = swapDimensions ? m_outputSize.Width : m_outputSize.Height;
if (m_swapChain != nullptr)
{
// If the swap chain already exists, resize it.
HRESULT hr = m_swapChain->ResizeBuffers(
2, // Double-buffered swap chain.
lround(m_d3dRenderTargetSize.Width),
lround(m_d3dRenderTargetSize.Height),
DXGI_FORMAT_B8G8R8A8_UNORM,
0
);
if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
{
// If the device was removed for any reason, a new device and swap chain will need to be created.
HandleDeviceLost();
// Everything is set up now. Do not continue execution of this method. HandleDeviceLost will reenter this method
// and correctly set up the new device.
return;
}
else
{
DX::ThrowIfFailed(hr);
}
}
else
{
// Otherwise, create a new one using the same adapter as the existing Direct3D device.
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0};
swapChainDesc.Width = lround(m_d3dRenderTargetSize.Width); // Match the size of the window.
swapChainDesc.Height = lround(m_d3dRenderTargetSize.Height);
swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // This is the most common swap chain format.
swapChainDesc.Stereo = false;
swapChainDesc.SampleDesc.Count = 1; // Don't use multi-sampling.
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = 2; // Use double-buffering to minimize latency.
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // All UWP apps must use this SwapEffect.
swapChainDesc.Flags = 0;
swapChainDesc.Scaling = DXGI_SCALING_NONE;
swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
// This sequence obtains the DXGI factory that was used to create the Direct3D device above.
ComPtr<IDXGIDevice3> dxgiDevice;
DX::ThrowIfFailed(
m_d3dDevice.As(&dxgiDevice)
);
ComPtr<IDXGIAdapter> dxgiAdapter;
DX::ThrowIfFailed(
dxgiDevice->GetAdapter(&dxgiAdapter)
);
ComPtr<IDXGIFactory2> dxgiFactory;
DX::ThrowIfFailed(
dxgiAdapter->GetParent(IID_PPV_ARGS(&dxgiFactory))
);
DX::ThrowIfFailed(
dxgiFactory->CreateSwapChainForCoreWindow(
m_d3dDevice.Get(),
reinterpret_cast<IUnknown*>(m_window.Get()),
&swapChainDesc,
nullptr,
&m_swapChain
)
);
// Ensure that DXGI does not queue more than one frame at a time. This both reduces latency and
// ensures that the application will only render after each VSync, minimizing power consumption.
DX::ThrowIfFailed(
dxgiDevice->SetMaximumFrameLatency(1)
);
}
// Set the proper orientation for the swap chain, and generate 2D and
// 3D matrix transformations for rendering to the rotated swap chain.
// Note the rotation angle for the 2D and 3D transforms are different.
// This is due to the difference in coordinate spaces. Additionally,
// the 3D matrix is specified explicitly to avoid rounding errors.
switch (displayRotation)
{
case DXGI_MODE_ROTATION_IDENTITY:
m_orientationTransform2D = Matrix3x2F::Identity();
m_orientationTransform3D = ScreenRotation::Rotation0;
break;
case DXGI_MODE_ROTATION_ROTATE90:
m_orientationTransform2D =
Matrix3x2F::Rotation(90.0f) *
Matrix3x2F::Translation(m_logicalSize.Height, 0.0f);
m_orientationTransform3D = ScreenRotation::Rotation270;
break;
case DXGI_MODE_ROTATION_ROTATE180:
m_orientationTransform2D =
Matrix3x2F::Rotation(180.0f) *
Matrix3x2F::Translation(m_logicalSize.Width, m_logicalSize.Height);
m_orientationTransform3D = ScreenRotation::Rotation180;
break;
case DXGI_MODE_ROTATION_ROTATE270:
m_orientationTransform2D =
Matrix3x2F::Rotation(270.0f) *
Matrix3x2F::Translation(0.0f, m_logicalSize.Width);
m_orientationTransform3D = ScreenRotation::Rotation90;
break;
default:
throw ref new FailureException();
}
//SDM: only instance of SetRotation
DX::ThrowIfFailed(
m_swapChain->SetRotation(displayRotation)
);
// Create a render target view of the swap chain back buffer.
ComPtr<ID3D11Texture2D> backBuffer;
DX::ThrowIfFailed(
m_swapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer))
);
DX::ThrowIfFailed(
m_d3dDevice->CreateRenderTargetView(
backBuffer.Get(),
nullptr,
&m_d3dRenderTargetView
)
);
// Create a depth stencil view for use with 3D rendering if needed.
CD3D11_TEXTURE2D_DESC depthStencilDesc(
DXGI_FORMAT_D24_UNORM_S8_UINT,
lround(m_d3dRenderTargetSize.Width),
lround(m_d3dRenderTargetSize.Height),
1, // This depth stencil view has only one texture.
1, // Use a single mipmap level.
D3D11_BIND_DEPTH_STENCIL
);
ComPtr<ID3D11Texture2D> depthStencil;
DX::ThrowIfFailed(
m_d3dDevice->CreateTexture2D(
&depthStencilDesc,
nullptr,
&depthStencil
)
);
CD3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc(D3D11_DSV_DIMENSION_TEXTURE2D);
DX::ThrowIfFailed(
m_d3dDevice->CreateDepthStencilView(
depthStencil.Get(),
&depthStencilViewDesc,
&m_d3dDepthStencilView
)
);
// Set the 3D rendering viewport to target the entire window.
m_screenViewport = CD3D11_VIEWPORT(
0.0f,
0.0f,
m_d3dRenderTargetSize.Width,
m_d3dRenderTargetSize.Height
);
m_d3dContext->RSSetViewports(1, &m_screenViewport);
// Create a Direct2D target bitmap associated with the
// swap chain back buffer and set it as the current target.
D2D1_BITMAP_PROPERTIES1 bitmapProperties =
D2D1::BitmapProperties1(
D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,
D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED),
m_dpi,
m_dpi
);
ComPtr<IDXGISurface2> dxgiBackBuffer;
DX::ThrowIfFailed(
m_swapChain->GetBuffer(0, IID_PPV_ARGS(&dxgiBackBuffer))
);
DX::ThrowIfFailed(
m_d2dContext->CreateBitmapFromDxgiSurface(
dxgiBackBuffer.Get(),
&bitmapProperties,
&m_d2dTargetBitmap
)
);
m_d2dContext->SetTarget(m_d2dTargetBitmap.Get());
// Grayscale text anti-aliasing is recommended for all UWP apps.
m_d2dContext->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE);
}
Bu yöntem bir sonraki çağrılışında pencerenin geçerli yükseklik ve genişlik değerlerini kaydettikten sonra, görüntü sınırları için cihazdan bağımsız piksel (DIP) değerlerini piksele dönüştürün. Örnekte, bu kodu çalıştıran basit bir işlev olan ConvertDipsToPixelsçağırırsınız:
floor((dips * dpi / 96.0f) + 0.5f);
En yakın tamsayı değerine yuvarlama sağlamak için 0,5f değerini eklersiniz.
Bu arada, CoreWindow koordinatları her zaman CIP'lerde tanımlanır. Windows 10 ve önceki Windows sürümlerinde DIP, inçin 1/96'sı olarak tanımlanır ve işletim sistemininkadar
İşlem açısından, yalnızca değiştirme zincirini yeniden boyutlandırmak yerine biraz daha fazla iş yapıyorsunuz: Görüntüyü sunuma hazırlamadan önce Direct2D ve Direct3D bileşenlerini döndürüyor ve değiştirme zincirine, sonuçları yeni bir yönde işlediğinizi bildiriyorsunuz. Bu işlemle ilgili daha ayrıntılı bilgi, DX::DeviceResources::CreateWindowSizeDependentResourceskod örneğinde gösterildiği gibi, aşağıda verilmiştir:
Ekranın yeni yönünü belirleyin. Ekran yataydan dikeye veya tersine çevrilmişse, görüntü sınırları için yükseklik ve genişlik değerlerini (DIP değerlerinden elbette piksellere) değiştirin.
Ardından takas zincirinin oluşturulup oluşturulmadığını denetleyin. Oluşturulmadıysa, IDXGIFactory2::CreateSwapChainForCoreWindowçağırarak oluşturun. Aksi takdirde, IDXGISwapchain:ResizeBuffersçağırarak mevcut takas zincirinin arabelleklerini yeni görüntü boyutlarına yeniden boyutlandırın. Döndürme olayı için değiştirme zincirini yeniden boyutlandırmanız gerekmese de, sonuçta işleme işlem hattınız tarafından zaten döndürülmüş olan içeriğin çıkışını oluşturuyorsunuz; yeniden boyutlandırma gerektiren uydurma ve doldurma olayları gibi başka boyut değişikliği olayları da vardır.
Bundan sonra, uygun 2-B veya 3-B matris dönüşümünü, grafik işlem hattındaki piksellere veya sırasıyla köşelere uygulamak üzere, işleme sırasında değişim zincirine ayarlayın. 4 olası döndürme matrisimiz var:
- yatay (DXGI_MODE_ROTATION_IDENTITY)
- dikey dönüş (DXGI_MODE_ROTATION_ROTATE270)
- yatay döndürülmüş, (DXGI_MODE_ROTATION_ROTATE180)
- portre, döndürülmüş (DXGI_MODE_ROTATION_ROTATE90)
Görüntü yönlendirmesini belirlemek için Windows 10 tarafından sağlanan verilere (DisplayInformation::OrientationChangedgibi) göre doğru matris seçilir ve sahnedeki her pikselin (Direct2D) veya köşenin (Direct3D) koordinatlarıyla çarpılır ve bunları ekranın yönüne hizalanacak şekilde etkili bir şekilde döndürür. (Direct2D'de ekran kaynağının sol üst köşe olarak tanımlandığını, Direct3D'de ise kaynağın pencerenin mantıksal merkezi olarak tanımlandığını unutmayın.)
Not Döndürme için kullanılan 2-B dönüştürmeleri ve bunların nasıl tanımlanacağı hakkında daha fazla bilgi için bkz. Ekran döndürme için matrisleri tanımlama (2-B). Döndürme için kullanılan 3B dönüştürmeler hakkında daha fazla bilgi için bkz. ekran döndürme (3B) için matrisleri tanımlama.
İşte önemli kısım:
m_swapChain->SetRotation(rotation);
Ayrıca, işleme yönteminizin yeni projeksiyonu hesaplarken bunu alabildiği seçili döndürme matrisini de depolarsınız. Bu matrisi son 3-B projeksiyonunuzu oluştururken veya son 2-B düzeninizi birleştirdiğinizde kullanırsınız. (Sizin için otomatik olarak uygulanmaz.)
Bundan sonra, döndürülmüş 3B görünüm için yeni bir işleme hedefi ve görünüm için yeni bir derinlik kalıbı arabelleği oluşturun. ID3D11DeviceContext:RSSetViewportsçağırarak döndürülen sahne için 3-B işleme görünüm penceresi ayarlayın.
Son olarak, döndürmek veya düzenlemek için 2-B görüntüleriniz varsa, ID2D1DeviceContext::CreateBitmapFromDxgiSurface kullanarak yeniden boyutlandırılan takas zinciri için yazılabilir bir bit eşlem olarak 2-B işleme hedefi oluşturun ve güncelleştirilmiş yönlendirme için yeni düzeninizi birleştirin. İşleme hedefinde, kod örneğinde görüldüğü gibi kenar yumuşatma modu gibi ihtiyaç duyduğunuz özellikleri ayarlayın.
Şimdi takas zincirini sun.
CoreWindowResizeManager kullanarak döndürme gecikmesini azaltma
Varsayılan olarak Windows 10, uygulama modeli veya dili ne olursa olsun tüm uygulamaların görüntünün döndürmesini tamamlaması için kısa ama fark edilebilir bir zaman penceresi sağlar. Ancak, muhtemelen uygulamanız burada açıklanan tekniklerden birini kullanarak döndürme hesaplamasını gerçekleştirdiğinde, bu süre penceresi kapanmadan önce tamamlanmış olur. O zamanı geri almak ve döndürme animasyonunu tamamlamak istiyorsunuz, değil mi? İşte CoreWindowResizeManager
CoreWindowResizeManagernasıl kullanılır: Bir DisplayInformation::OrientationChanged olayı oluştuğunda, CoreWindowResizeManager örneğini almak için olay işleyicisi içinde CoreWindowResizeManager::GetForCurrentView çağrısını yapın. Yeni yönlendirme düzeni tamamlandığında ve sunulduğunda, Windows'un döndürme animasyonunu tamamlayıp uygulama ekranını görüntüleyebilmesi için NotifyLayoutCompleted çağrısını yapın.
DisplayInformation::OrientationChanged için olay işleyicinizdeki kod şöyle görünebilir:
CoreWindowResizeManager^ resizeManager = Windows::UI::Core::CoreWindowResizeManager::GetForCurrentView();
// ... build the layout for the new display orientation ...
resizeManager->NotifyLayoutCompleted();
Kullanıcı ekranın yönünü döndürüyorsa Windows 10, kullanıcıya geri bildirim olarak uygulamanızdan bağımsız bir animasyon gösterir. Bu animasyonda aşağıdaki sırada gerçekleşen üç bölüm vardır:
- Windows 10, özgün görüntüyü küçültür.
- Windows 10, görüntüyü yeni düzeni yeniden oluşturma süresi boyunca tutar. Bu, azaltmak istediğiniz zaman aralığıdır, çünkü uygulamanızın büyük olasılıkla tümüne ihtiyacı yoktur.
- Düzen penceresinin süresi dolduğunda veya düzen tamamlama bildirimi alındığında Windows görüntüyü döndürür ve ardından yeni yönlendirmeye çapraz yakınlaştırma yapar.
Üçüncü madde işaretinde de önerildiği gibi, bir uygulama NotifyLayoutCompletedçağırdığında, Windows 10 zaman aşımı penceresini durdurur, döndürme animasyonunu tamamlar ve kontrolü uygulamanıza geri verir; bu durumda uygulamanız artık yeni ekran yönlendirmesinde çizim yapmaktadır. Bunun genel etkisi, uygulamanızın artık biraz daha akıcı ve duyarlı hissetmesi ve biraz daha verimli çalışmasıdır!
Ek A: Ekran döndürme için matrislerin uygulanması (2-B)
Değişim zincirini yeniden boyutlandırma ve içeriğini önceden döndürme (ve DXGI değişim zinciri döndürme örneği) içindeki örnek kodda, Direct2D çıkışı ve Direct3D çıkışı için ayrı döndürme matrislerimiz olduğunu fark etmiş olabilirsiniz. Önce 2-B matrislere bakalım.
Direct2D ve Direct3D içeriğine aynı döndürme matrislerini uygulayamamanın iki nedeni vardır:
Birincisi, farklı Kartezyen koordinat modelleri kullanıyorlar. Direct2D sağ el kuralını kullanır; burada y-koordinatı, başlangıç noktasından yukarı doğru hareket ederken pozitif olarak artar. Ancak, Direct3D sol elle kullanılan kuralı kullanır ve burada y koordinatı, çıkıştan sağa doğru pozitif değerde artar. Sonuç, ekran koordinatlarının kaynağı Direct2D için sol üst köşede, ekranın kaynağı ise (projeksiyon düzlemi) Direct3D için sol altta yer alır. (Daha fazla bilgi için bkz. 3B koordinat sistemleri.)
İki, yuvarlama hatalarını önlemek için 3-B döndürme matrisleri açıkça belirtilmelidir.
Takas zinciri, kaynağın sol altta yer aldığını varsayar, bu nedenle sağ elli Direct2D koordinat sistemini takas zinciri tarafından kullanılan sol elli sistemle hizalamak için bir döndürme gerçekleştirmeniz gerekir. Özellikle, döndürme matrisini döndürülmüş koordinat sistemi kaynağı için bir çeviri matrisi ile çarparak görüntüyü yeni sol el yönlendirmesinin altına yeniden konumlandırır ve görüntüyü CoreWindow
Olası dört döndürmeden doğru matrisi seçme kodunuz şöyle görünebilir (yeni koordinat sistemi kaynağına çeviriyi unutmayın):
// Set the proper orientation for the swap chain, and generate 2D and
// 3D matrix transformations for rendering to the rotated swap chain.
// Note the rotation angle for the 2D and 3D transforms are different.
// This is due to the difference in coordinate spaces. Additionally,
// the 3D matrix is specified explicitly to avoid rounding errors.
switch (displayRotation)
{
case DXGI_MODE_ROTATION_IDENTITY:
m_orientationTransform2D = Matrix3x2F::Identity();
m_orientationTransform3D = ScreenRotation::Rotation0;
break;
case DXGI_MODE_ROTATION_ROTATE90:
m_orientationTransform2D =
Matrix3x2F::Rotation(90.0f) *
Matrix3x2F::Translation(m_logicalSize.Height, 0.0f);
m_orientationTransform3D = ScreenRotation::Rotation270;
break;
case DXGI_MODE_ROTATION_ROTATE180:
m_orientationTransform2D =
Matrix3x2F::Rotation(180.0f) *
Matrix3x2F::Translation(m_logicalSize.Width, m_logicalSize.Height);
m_orientationTransform3D = ScreenRotation::Rotation180;
break;
case DXGI_MODE_ROTATION_ROTATE270:
m_orientationTransform2D =
Matrix3x2F::Rotation(270.0f) *
Matrix3x2F::Translation(0.0f, m_logicalSize.Width);
m_orientationTransform3D = ScreenRotation::Rotation90;
break;
default:
throw ref new FailureException();
}
2-D görüntü için doğru döndürme matrisi ve çıkış noktası elde ettikten sonra, ID2D1DeviceContext::SetTransform çağrısını, ID2D1DeviceContext::BeginDraw ve ID2D1DeviceContext::EndDrawçağrıları arasında yapın.
Uyarı Direct2D'nin dönüştürme yığını yoktur. Uygulamanız aynı zamanda ID2D1DeviceContext::SetTransform çizim kodunun bir parçası olarak kullanıyorsa, bu matrisin uyguladığınız diğer tüm dönüşümlerle çarpılması gerekir.
ID2D1DeviceContext* context = m_deviceResources->GetD2DDeviceContext();
Windows::Foundation::Size logicalSize = m_deviceResources->GetLogicalSize();
context->SaveDrawingState(m_stateBlock.Get());
context->BeginDraw();
// Position on the bottom right corner.
D2D1::Matrix3x2F screenTranslation = D2D1::Matrix3x2F::Translation(
logicalSize.Width - m_textMetrics.layoutWidth,
logicalSize.Height - m_textMetrics.height
);
context->SetTransform(screenTranslation * m_deviceResources->GetOrientationTransform2D());
DX::ThrowIfFailed(
m_textFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_TRAILING)
);
context->DrawTextLayout(
D2D1::Point2F(0.f, 0.f),
m_textLayout.Get(),
m_whiteBrush.Get()
);
// Ignore D2DERR_RECREATE_TARGET here. This error indicates that the device
// is lost. It will be handled during the next call to Present.
HRESULT hr = context->EndDraw();
Bir sonraki değiştirme zinciri sunumunda, 2B görüntünüz yeni görüntü yönüyle eşleşecek şekilde döndürülür.
Ek B: Ekranı döndürme için matrislerin uygulanması (3 boyutlu)
Takas zincirini yeniden boyutlandırma ve içeriğinin önceden döndürülmesi (ve DXGI takas zinciri döndürme örneği) içindeki örnek kodda, olası her ekran yönü için belirli bir dönüştürme matrisi tanımladık. Şimdi 3B sahneleri döndürme matrislerine bakalım. Daha önce olduğu gibi, 4 olası yönlendirmenin her biri için bir matris kümesi oluşturursunuz. Yuvarlama hatalarını ve dolayısıyla küçük görsel yapıtları önlemek için matrisleri kodunuzda açıkça bildirin.
Bu 3-B döndürme matrislerini aşağıdaki gibi ayarlarsınız. Aşağıdaki kod örneğinde gösterilen matrisler, kameranın 3B sahne alanında noktaları tanımlayan köşelerin 0, 90, 180 ve 270 derece döndürmeleri için standart döndürme matrisleridir. Sahnenin 2-B projeksiyonu hesaplandığında her köşenin [x, y, z] koordinat değeri bu döndürme matrisi ile çarpılır.
// 0-degree Z-rotation
static const XMFLOAT4X4 Rotation0(
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
);
// 90-degree Z-rotation
static const XMFLOAT4X4 Rotation90(
0.0f, 1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
);
// 180-degree Z-rotation
static const XMFLOAT4X4 Rotation180(
-1.0f, 0.0f, 0.0f, 0.0f,
0.0f, -1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
);
// 270-degree Z-rotation
static const XMFLOAT4X4 Rotation270(
0.0f, -1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
);
}
Değiştirme zincirinde döndürme türünü IDXGISwapChain1::SetRotationçağrısını kullanarak ayarlamak için yapmanız gereken:
m_swapChain->SetRotation(rotation);
Şimdi işleme yönteminizde şuna benzer bir kod uygulayın:
struct ConstantBuffer // This struct is provided for illustration.
{
// Other constant buffer matrices and data are defined here.
float4x4 projection; // Current matrix for projection
} ;
ConstantBuffer m_constantBufferData; // Constant buffer resource data
// ...
// Rotate the projection matrix as it will be used to render to the rotated swap chain.
m_constantBufferData.projection = mul(m_constantBufferData.projection, m_rotationTransform3D);
Şimdi işleme yönteminizi çağırdığınızda geçerli döndürme matrisini (m_orientationTransform3Dsınıf değişkeni tarafından belirtildiği gibi) geçerli projeksiyon matrisiyle çarpar ve bu işlemin sonuçlarını işleyiciniz için yeni projeksiyon matrisi olarak atar. Görünümü güncelleştirilmiş görüntü yönlendirmesinde görmek için değiştirme zincirini sunun.