Aracılığıyla paylaş


İşleme çerçevesi II: Oyun işleme

Uyarı

Bu konu, DirectX öğretici serisi ile basit bir Evrensel Windows Platformu (UWP) oluşturma oyunun bir parçasıdır. Bu bağlantıdaki konu başlığı, serinin bağlamını ayarlar.

İşleme çerçevesibölümünde, sahne bilgilerini nasıl aldığımızı ve ekran ekranına nasıl sunacağımızı ele aldık. Şimdi bir adım geri gidip verileri işlemeye hazırlamayı öğreneceğiz.

Uyarı

Bu örnek için en son oyun kodunu indirmediyseniz Direct3D örnek oyunbölümüne gidin. Bu örnek, büyük bir UWP özellik örnekleri koleksiyonunun bir parçasıdır. Örneği indirme talimatları için, Windows geliştirme için örnek uygulamalar sayfasına bakın.

Amaç

Hedefe ilişkin hızlı özet. Bir UWP DirectX oyununun grafik çıkışını görüntülemek için temel bir işleme çerçevesi ayarlamayı anlamaktır. Bunları bu üç adımda gevşek bir şekilde gruplandırabiliriz.

  1. Grafik arabirimimizle bağlantı kurma
  2. Hazırlık: Grafikleri çizmek için ihtiyacımız olan kaynakları oluşturma
  3. Grafikleri göster: Çerçeveyi oluştur

İşleme çerçevesi I: İşlemeye giriş, 1. ve 3. Adımları kapsayan grafiklerin nasıl işlendiğini açıkladı.

Bu makalede, bu çerçevenin diğer parçalarının nasıl ayarlanacağı ve işleme gerçekleşmeden önce gerekli verilerin nasıl hazırlanacağı açıklanır ve bu da işlemin 2. Adımıdır.

oluşturucuyu tasarlama

oluşturucu, oyun görsellerini oluşturmak için kullanılan tüm D3D11 ve D2D nesnelerini oluşturmak ve korumakla sorumludur. GameRenderer sınıfı, bu örnek oyun için işleyicidir ve oyunun işleme gereksinimlerini karşılamak için tasarlanmıştır.

Bunlar, işleyiciyi oyununuz için tasarlamaya yardımcı olmak için kullanabileceğiniz bazı kavramlardır:

  • Direct3D 11 API'leri COM API'leri olarak tanımlandığından, bu API'ler tarafından tanımlanan nesnelere ComPtr başvuruları sağlamanız gerekir. Bu nesneler, son başvuruları kapsam dışına çıktığında ve uygulama sonlandırıldığında otomatik olarak serbest bırakılır. Daha fazla bilgi için bkz. ComPtr. Bu nesnelere örnek: sabit arabellekler, gölgelendirici nesneleri - köşe gölgelendiricisi, piksel gölgelendiricive gölgelendirici kaynak nesneleri.
  • Bu sınıfta, işleme için gereken çeşitli verileri tutmak için sabit arabellekler tanımlanır.
    • Kare başına GPU'ya gönderilmesi gereken veri miktarını azaltmak için farklı frekanslara sahip birden çok sabit arabellek kullanın. Bu örnek, sabitleri güncelleştirilmeleri gereken sıklığa göre farklı arabelleklere ayırır. Bu, Direct3D programlama için en iyi yöntemdir.
    • Bu örnek oyunda 4 sabit arabellek tanımlanmıştır.
      1. m_constantBufferNeverChanges aydınlatma parametrelerini içerir. FinalizeCreateGameDeviceResources yönteminde bir kez ayarlanır ve bir daha asla değişmez.
      2. m_constantBufferChangeOnResize projeksiyon matrisini içerir. Projeksiyon matrisi, pencerenin boyutuna ve en boy oranına bağlıdır. CreateWindowSizeDependentResources ayarlanır ve FinalizeCreateGameDeviceResources yönteminde kaynaklar yüklendikten sonra güncelleştirilir. 3B olarak işleniyorsa, her karede iki kez değiştirilir.
      3. m_constantBufferChangesEveryFrame görünüm matrisini içerir. Bu matris, kamera konumuna ve görünüm yönüne (projeksiyona normal) bağlıdır ve render yönteminde kare başına bir kez değişir. Bu konu daha önce İşleme çerçevesi I:işlemeye giriş bölümünde, GameRenderer::Render yöntemialtında ele alınmıştı.
      4. m_constantBufferChangesEveryPrim her temel öğeye ait model matrisini ve malzeme özelliklerini içerir. Model matrisi köşeleri yerel koordinatlardan dünya koordinatlarına dönüştürür. Bu sabitler her temel öğeye özeldir ve her çizim çağrısı için güncelleştirilir. Bu konu daha önce İşleme çerçevesi I:işlemeye giriş bölümünde, Temel işlemealtında ele alınmıştı.
  • Temel öğeler için dokuları tutan gölgelendirici kaynak nesneleri de bu sınıfta tanımlanır.
    • Bazı dokular önceden tanımlanmıştır (DDS sıkıştırılmış ve sıkıştırılmamış dokuları depolamak için kullanılabilecek bir dosya biçimidir. DDS dokuları, dünyanın duvarları ve zemini ile cephane küreleri için kullanılır.)
    • Bu örnek oyunda gölgelendirici kaynak nesneleri şunlardır: m_sphereTexture, m_cylinderTexture, m_ceilingTexture, m_floorTexture, m_wallsTexture.
  • Gölgelendirici nesneleri, temel öğelerimizi ve dokularımızı hesaplamak için bu sınıfta tanımlanır.
    • Bu örnek oyunda gölgelendirici nesneleri m_vertexShader, m_vertexShaderFlatve m_pixelShaderm_pixelShaderFlat.
    • Köşe gölgelendiricisi ilkelleri ve temel aydınlatmayı işler ve piksel gölgelendiricisi (bazen parça gölgelendiricisi olarak adlandırılır) dokuları ve piksel başına efektleri işler.
    • Bu gölgelendiricilerin farklı ilkel öğeleri işlemek için iki sürümü vardır (normal ve düz). Farklı sürümlerimiz olmasının nedeni, düz sürümlerin çok daha basit olması ve belirtik vurgulamalar veya piksel başına aydınlatma efektleri yapmamamızdır. Bunlar duvarlar için kullanılır ve daha düşük güçlendirilmiş cihazlarda işlemeyi hızlandırır.

GameRenderer.h

Şimdi örnek oyunun işleyici sınıf nesnesindeki koda göz atalım.

// Class handling the rendering of the game
class GameRenderer : public std::enable_shared_from_this<GameRenderer>
{
public:
    GameRenderer(std::shared_ptr<DX::DeviceResources> const& deviceResources);

    void CreateDeviceDependentResources();
    void CreateWindowSizeDependentResources();
    void ReleaseDeviceDependentResources();
    void Render();
    // --- end of async related methods section

    winrt::Windows::Foundation::IAsyncAction CreateGameDeviceResourcesAsync(_In_ std::shared_ptr<Simple3DGame> game);
    void FinalizeCreateGameDeviceResources();
    winrt::Windows::Foundation::IAsyncAction LoadLevelResourcesAsync();
    void FinalizeLoadLevelResources();

    Simple3DGameDX::IGameUIControl* GameUIControl() { return &m_gameInfoOverlay; };

    DirectX::XMFLOAT2 GameInfoOverlayUpperLeft()
    {
        return DirectX::XMFLOAT2(m_gameInfoOverlayRect.left, m_gameInfoOverlayRect.top);
    };
    DirectX::XMFLOAT2 GameInfoOverlayLowerRight()
    {
        return DirectX::XMFLOAT2(m_gameInfoOverlayRect.right, m_gameInfoOverlayRect.bottom);
    };
    bool GameInfoOverlayVisible() { return m_gameInfoOverlay.Visible(); }
    // --- end of rendering overlay section
...
private:
    // Cached pointer to device resources.
    std::shared_ptr<DX::DeviceResources>        m_deviceResources;

    ...

    // Shader resource objects
    winrt::com_ptr<ID3D11ShaderResourceView>    m_sphereTexture;
    winrt::com_ptr<ID3D11ShaderResourceView>    m_cylinderTexture;
    winrt::com_ptr<ID3D11ShaderResourceView>    m_ceilingTexture;
    winrt::com_ptr<ID3D11ShaderResourceView>    m_floorTexture;
    winrt::com_ptr<ID3D11ShaderResourceView>    m_wallsTexture;

    // Constant buffers
    winrt::com_ptr<ID3D11Buffer>                m_constantBufferNeverChanges;
    winrt::com_ptr<ID3D11Buffer>                m_constantBufferChangeOnResize;
    winrt::com_ptr<ID3D11Buffer>                m_constantBufferChangesEveryFrame;
    winrt::com_ptr<ID3D11Buffer>                m_constantBufferChangesEveryPrim;

    // Texture sampler
    winrt::com_ptr<ID3D11SamplerState>          m_samplerLinear;

    // Shader objects: Vertex shaders and pixel shaders
    winrt::com_ptr<ID3D11VertexShader>          m_vertexShader;
    winrt::com_ptr<ID3D11VertexShader>          m_vertexShaderFlat;
    winrt::com_ptr<ID3D11PixelShader>           m_pixelShader;
    winrt::com_ptr<ID3D11PixelShader>           m_pixelShaderFlat;
    winrt::com_ptr<ID3D11InputLayout>           m_vertexLayout;
};

Yapıcı

Şimdi örnek oyunun GameRenderer oluşturucuyu inceleyelim ve bunu DirectX 11 Uygulama şablonunda sağlanan Sample3DSceneRenderer oluşturucuyla karşılaştıralım.

// Constructor method of the main rendering class object
GameRenderer::GameRenderer(std::shared_ptr<DX::DeviceResources> const& deviceResources) : ...
    m_gameInfoOverlay(deviceResources),
    m_gameHud(deviceResources, L"Windows platform samples", L"DirectX first-person game sample")
{
    // m_gameInfoOverlay is a GameHud object to render text in the top left corner of the screen.
    // m_gameHud is Game info rendered as an overlay on the top-right corner of the screen,
    // for example hits, shots, and time.

    CreateDeviceDependentResources();
    CreateWindowSizeDependentResources();
}

DirectX grafik kaynakları oluşturma ve yükleme

Örnek oyunda (ve Visual Studio'nun DirectX 11 Uygulaması (Evrensel Windows) şablonunda), GameRenderer oluşturucudan çağrılan bu iki yöntem kullanılarak oyun kaynakları oluşturma ve yükleme uygulanır:

  • CihazBağımlıKaynaklarOluştur
  • CreateWindowSizeDependentResources

CreateDeviceDependentResources yöntemi

DirectX 11 Uygulama şablonunda bu yöntem köşe ve piksel gölgelendiricisini zaman uyumsuz olarak yüklemek, gölgelendirici ve sabit arabellek oluşturmak, konum ve renk bilgileri içeren köşeler içeren bir ağ oluşturmak için kullanılır.

Örnek oyunda, sahne nesnelerinin bu işlemleri bunun yerine CreateGameDeviceResourcesAsync ve FinalizeCreateGameDeviceResources yöntemleri arasında bölünür.

Bu örnek oyun için bu yönteme ne eklenir?

  • Kaynakları zaman uyumsuz olarak yüklediğimiz için işlemeye geçmeden önce yüklenip yüklenmediğini gösteren örneklenmiş değişkenler (m_gameResourcesLoaded = false ve m_levelResourcesLoaded = false).
  • HUD ve örtüşme işleme ayrı sınıf nesnelerinde olduğundan, burada GameHud::CreateDeviceDependentResources ve GameInfoOverlay::CreateDeviceDependentResources yöntemlerini çağırın.

İşte GameRenderer::CreateDeviceDependentResourceskodu.

// This method is called in GameRenderer constructor when it's created in GameMain constructor.
void GameRenderer::CreateDeviceDependentResources()
{
    // instantiate variables that indicate whether resources were loaded.
    m_gameResourcesLoaded = false;
    m_levelResourcesLoaded = false;

    // game HUD and overlay are design as separate class objects.
    m_gameHud.CreateDeviceDependentResources();
    m_gameInfoOverlay.CreateDeviceDependentResources();
}

Kaynak oluşturmak ve yüklemek için kullanılan yöntemlerin listesi aşağıdadır.

  • Cihaz Bağımlı Kaynaklar Oluştur
    • CreateGameDeviceResourcesAsync (Eklendi)
    • FinalizeCreateGameDeviceResources (Eklendi)
  • PencereBoyutunaBağlıKaynaklarOluştur

Kaynak oluşturmak ve yüklemek için kullanılan diğer yöntemlere geçmeden önce işleyiciyi oluşturalım ve oyun döngüsüne nasıl uyduğunu görelim.

Oluşturucu oluştur

GameRenderer, GameMainoluşturucusunda oluşturulur. Ayrıca, kaynak oluşturmaya ve yüklemeye yardımcı olmak için eklenen iki diğer yöntem olan CreateGameDeviceResourcesAsync ve FinalizeCreateGameDeviceResources yöntemlerini de çağırır.

GameMain::GameMain(std::shared_ptr<DX::DeviceResources> const& deviceResources) : ...
{
    m_deviceResources->RegisterDeviceNotify(this);

    // Creation of GameRenderer
    m_renderer = std::make_shared<GameRenderer>(m_deviceResources);

    ...

    ConstructInBackground();
}

winrt::fire_and_forget GameMain::ConstructInBackground()
{
    ...

    // Asynchronously initialize the game class and load the renderer device resources.
    // By doing all this asynchronously, the game gets to its main loop more quickly
    // and in parallel all the necessary resources are loaded on other threads.
    m_game->Initialize(m_controller, m_renderer);

    co_await m_renderer->CreateGameDeviceResourcesAsync(m_game);

    // The finalize code needs to run in the same thread context
    // as the m_renderer object was created because the D3D device context
    // can ONLY be accessed on a single thread.
    // co_await of an IAsyncAction resumes in the same thread context.
    m_renderer->FinalizeCreateGameDeviceResources();

    InitializeGameState();

    ...
}

CreateGameDeviceResourcesAsync yöntemi

CreateGameDeviceResourcesAsync, oyun kaynaklarını zaman uyumsuz olarak yüklediğimizden create_task döngüsündeki GameMain oluşturucu yönteminden çağrılır.

CreateDeviceResourcesAsync, oyun kaynaklarını yüklemek için ayrı bir zaman uyumsuz görev kümesi olarak çalışan bir yöntemdir. Ayrı bir iş parçacığında çalışması beklendiğinden, yalnızca ID3D11Deviceüzerinde tanımlanan Direct3D 11 aygıt yöntemlerine erişimi vardır ve ID3D11DeviceContextüzerinde tanımlanan aygıt bağlamı yöntemlerine erişimi yoktur; bu nedenle herhangi bir işleme gerçekleştirmez.

FinalizeCreateGameDeviceResources yöntemi ana iş parçacığında çalışır ve Direct3D 11 cihaz bağlam yöntemlerine erişimi vardır.

Prensip olarak

  • CreateGameDeviceResourcesAsync yalnızca ID3D11Device yöntemlerini kullanın çünkü bunlar serbest iş parçacıklı olduğundan herhangi bir iş parçacığında çalıştırılabildikleri anlamına gelir. Ayrıca, GameRenderer'ın oluşturulduğu iş parçacığında çalışmamaları da beklenir.
  • ID3D11DeviceContext yöntemleri burada kullanmayın çünkü tek bir iş parçacığında ve GameRendererile aynı iş parçacığında çalışması gerekir.
  • Sabit arabellekler oluşturmak için bu yöntemi kullanın.
  • dokuları (.dds dosyaları gibi) ve gölgelendirici bilgilerini (.cso dosyaları gibi)gölgelendiricilere yüklemek için bu yöntemi kullanın.

Bu yöntem aşağıdakiler için kullanılır:

  • 4 sabit arabellekoluşturun: m_constantBufferNeverChanges, m_constantBufferChangeOnResize, m_constantBufferChangesEveryFrame, m_constantBufferChangesEveryPrim
  • Bir doku için örnekleme bilgilerini kapsülleyen bir örnekleme durumu nesnesi oluşturun.
  • Metodun oluşturduğu tüm asenkron görevleri içeren bir görev grubu oluşturun. Tüm bu asenkron görevlerin tamamlanmasını bekler ve ardından FinalizeCreateGameDeviceResourcesçağırır.
  • Temel Yükleyicikullanarak bir yükleyici oluşturun. Yükleyicinin asenkron yükleme işlemlerini daha önce oluşturulan görev grubuna görevler olarak ekleyin.
  • BasicLoader::LoadShaderAsync ve BasicLoader::LoadTextureAsync gibi yöntemler yüklemek için kullanılır:
    • derlenmiş gölgelendirici nesneleri (VertextShader.cso, VertexShaderFlat.cso, PixelShader.cso ve PixelShaderFlat.cso). Daha fazla bilgi için çeşitli gölgelendirici dosya biçimleribakın.
    • oyuna özgü dokular (Assets\seafloor.dds, metal_texture.dds, cellceiling.dds, cellfloor.dds, cellwall.dds).
IAsyncAction GameRenderer::CreateGameDeviceResourcesAsync(_In_ std::shared_ptr<Simple3DGame> game)
{
    auto lifetime = shared_from_this();

    // Create the device dependent game resources.
    // Only the d3dDevice is used in this method. It is expected
    // to not run on the same thread as the GameRenderer was created.
    // Create methods on the d3dDevice are free-threaded and are safe while any methods
    // in the d3dContext should only be used on a single thread and handled
    // in the FinalizeCreateGameDeviceResources method.
    m_game = game;

    auto d3dDevice = m_deviceResources->GetD3DDevice();

    // Define D3D11_BUFFER_DESC. See
    // https://learn.microsoft.com/windows/win32/api/d3d11/ns-d3d11-d3d11_buffer_desc
    D3D11_BUFFER_DESC bd;
    ZeroMemory(&bd, sizeof(bd));

    // Create the constant buffers.
    bd.Usage = D3D11_USAGE_DEFAULT;
    ...

    // Create the constant buffers: m_constantBufferNeverChanges, m_constantBufferChangeOnResize,
    // m_constantBufferChangesEveryFrame, m_constantBufferChangesEveryPrim
    // CreateBuffer is used to create one of these buffers: vertex buffer, index buffer, or 
    // shader-constant buffer. For CreateBuffer API ref info, see
    // https://learn.microsoft.com/windows/win32/api/d3d11/nf-d3d11-id3d11device-createbuffer.
    winrt::check_hresult(
        d3dDevice->CreateBuffer(&bd, nullptr, m_constantBufferNeverChanges.put())
        );

    ...

    // Define D3D11_SAMPLER_DESC. For API ref, see
    // https://learn.microsoft.com/windows/win32/api/d3d11/ns-d3d11-d3d11_sampler_desc.
    D3D11_SAMPLER_DESC sampDesc;

    // ZeroMemory fills a block of memory with zeros. For API ref, see
    // https://learn.microsoft.com/previous-versions/windows/desktop/legacy/aa366920(v=vs.85).
    ZeroMemory(&sampDesc, sizeof(sampDesc));

    sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
    sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
    sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
    ...

    // Create a sampler-state object that encapsulates sampling information for a texture.
    // The sampler-state interface holds a description for sampler state that you can bind to any 
    // shader stage of the pipeline for reference by texture sample operations.
    winrt::check_hresult(
        d3dDevice->CreateSamplerState(&sampDesc, m_samplerLinear.put())
        );

    // Start the async tasks to load the shaders and textures.

    // Load compiled shader objects (VertextShader.cso, VertexShaderFlat.cso, PixelShader.cso, and PixelShaderFlat.cso).
    // The BasicLoader class is used to convert and load common graphics resources, such as meshes, textures, 
    // and various shader objects into the constant buffers. For more info, see
    // https://learn.microsoft.com/windows/uwp/gaming/complete-code-for-basicloader.
    BasicLoader loader{ d3dDevice };

    std::vector<IAsyncAction> tasks;

    uint32_t numElements = ARRAYSIZE(PNTVertexLayout);

    // Load shaders asynchronously with the shader and pixel data using the
    // BasicLoader::LoadShaderAsync method. Push these method calls into a list of tasks.
    tasks.push_back(loader.LoadShaderAsync(L"VertexShader.cso", PNTVertexLayout, numElements, m_vertexShader.put(), m_vertexLayout.put()));
    tasks.push_back(loader.LoadShaderAsync(L"VertexShaderFlat.cso", nullptr, numElements, m_vertexShaderFlat.put(), nullptr));
    tasks.push_back(loader.LoadShaderAsync(L"PixelShader.cso", m_pixelShader.put()));
    tasks.push_back(loader.LoadShaderAsync(L"PixelShaderFlat.cso", m_pixelShaderFlat.put()));

    // Make sure the previous versions if any of the textures are released.
    m_sphereTexture = nullptr;
    ...

    // Load Game specific textures (Assets\\seafloor.dds, metal_texture.dds, cellceiling.dds,
    // cellfloor.dds, cellwall.dds).
    // Push these method calls also into a list of tasks.
    tasks.push_back(loader.LoadTextureAsync(L"Assets\\seafloor.dds", nullptr, m_sphereTexture.put()));
    ...

    // Simulate loading additional resources by introducing a delay.
    tasks.push_back([]() -> IAsyncAction { co_await winrt::resume_after(GameConstants::InitialLoadingDelay); }());

    // Returns when all the async tasks for loading the shader and texture assets have completed.
    for (auto&& task : tasks)
    {
        co_await task;
    }
}

FinalizeCreateGameDeviceResources yöntemi

FinalizeCreateGameDeviceResources yöntemi, CreateGameDeviceResourcesAsync yöntemindeki tüm yük kaynakları görevleri tamamlandıktan sonra çağrılır.

  • ConstantBufferNeverChanges'i ışık konumları ve rengi ile başlatın. CIhaz bağlamı yöntemi ID3D11DeviceContext::UpdateSubresourceçağrısı ile ilk verileri sabit arabelleklere yükler.
  • Zaman uyumsuz olarak yüklenen kaynakların yüklenmesi tamamlandığından, bunları uygun oyun nesneleriyle ilişkilendirmenin zamanı geldi.
  • Her oyun nesnesi için, yüklenen dokuları kullanarak mesh'i ve malzemeyi oluşturun. Ardından ağı ve malzemeyi oyun nesnesiyle ilişkilendirin.
  • Hedef oyununun nesnesi için, üstünde sayısal bir değer bulunan eşmerkezli renkli halkalardan oluşan doku, bir doku dosyasından yüklenmemektedir. Bunun yerine, TargetTexture.cppiçindeki kod kullanılarak yordamsal olarak oluşturulur. TargetTexture sınıfı, başlatma sırasında dokuyu ekran dışı bir kaynağa çizmek için gerekli kaynakları oluşturur. Sonuçta elde edilen doku daha sonra uygun hedef oyun nesneleriyle ilişkilendirilir.

FinalizeCreateGameDeviceResources ve CreateWindowSizeDependentResources bunlar için kodun benzer bölümlerini paylaşır:

  • Kameranın doğru projeksiyon matrisine sahip olduğundan emin olmak için SetProjParams kullanın. Daha fazla bilgi için Kamera ve koordinat alanıadresine gidin.
  • 3B döndürme matrisini kameranın projeksiyon matrisine çarparak ekran döndürmeyi işleyebilir. Ardından ConstantBufferChangeOnResize sabit arabelleği sonuçta elde edilen projeksiyon matrisiyle güncelleştirin.
  • m_gameResourcesLoadedBoole genel değişkenini, kaynakların artık arabelleklere yüklendiğini ve sonraki adıma hazır olduğunu belirtmek için ayarlayın. Bu değişkeni ilk olarak GameRenderer::CreateDeviceDependentResources yöntemi aracılığıyla GameRendereroluşturucu yönteminde FALSE olarak başlatmış olduğumuzu hatırlayın.
  • Bu m_gameResourcesLoaded değeri TRUEolduğunda, sahne nesnelerinin işlenmesi gerçekleşebilir. Bu, İşleme çerçevesi I: İşlemeye giriş makalesinde, GameRenderer::Render metodualtında ele alınmıştır.
// This method is called from the GameMain constructor.
// Make sure that 2D rendering is occurring on the same thread as the main rendering.
void GameRenderer::FinalizeCreateGameDeviceResources()
{
    // All asynchronously loaded resources have completed loading.
    // Now associate all the resources with the appropriate game objects.
    // This method is expected to run in the same thread as the GameRenderer
    // was created. All work will happen behind the "Loading ..." screen after the
    // main loop has been entered.

    // Initialize the Constant buffer with the light positions
    // These are handled here to ensure that the d3dContext is only
    // used in one thread.

    auto d3dDevice = m_deviceResources->GetD3DDevice();

    ConstantBufferNeverChanges constantBufferNeverChanges;
    constantBufferNeverChanges.lightPosition[0] = XMFLOAT4(3.5f, 2.5f, 5.5f, 1.0f);
    ...
    constantBufferNeverChanges.lightColor = XMFLOAT4(0.25f, 0.25f, 0.25f, 1.0f);

    // CPU copies data from memory (constantBufferNeverChanges) to a subresource 
    // created in non-mappable memory (m_constantBufferNeverChanges) which was created in the earlier 
    // CreateGameDeviceResourcesAsync method. For UpdateSubresource API ref info, 
    // go to: https://msdn.microsoft.com/library/windows/desktop/ff476486.aspx
    // To learn more about what a subresource is, go to:
    // https://msdn.microsoft.com/library/windows/desktop/ff476901.aspx

    m_deviceResources->GetD3DDeviceContext()->UpdateSubresource(
        m_constantBufferNeverChanges.get(),
        0,
        nullptr,
        &constantBufferNeverChanges,
        0,
        0
        );

    // For the objects that function as targets, they have two unique generated textures.
    // One version is used to show that they have never been hit and the other is 
    // used to show that they have been hit.
    // TargetTexture is a helper class to procedurally generate textures for game
    // targets. The class creates the necessary resources to draw the texture into 
    // an off screen resource at initialization time.

    TargetTexture textureGenerator(
        d3dDevice,
        m_deviceResources->GetD2DFactory(),
        m_deviceResources->GetDWriteFactory(),
        m_deviceResources->GetD2DDeviceContext()
        );

    // CylinderMesh is a class derived from MeshObject and creates a ID3D11Buffer of
    // vertices and indices to represent a canonical cylinder (capped at
    // both ends) that is positioned at the origin with a radius of 1.0,
    // a height of 1.0 and with its axis in the +Z direction.
    // In the game sample, there are various types of mesh types:
    // CylinderMesh (vertical rods), SphereMesh (balls that the player shoots), 
    // FaceMesh (target objects), and WorldMesh (Floors and ceilings that define the enclosed area)

    auto cylinderMesh = std::make_shared<CylinderMesh>(d3dDevice, (uint16_t)26);
    ...

    // The Material class maintains the properties that represent how an object will
    // look when it is rendered.  This includes the color of the object, the
    // texture used to render the object, and the vertex and pixel shader that
    // should be used for rendering.

    auto cylinderMaterial = std::make_shared<Material>(
        XMFLOAT4(0.8f, 0.8f, 0.8f, .5f),
        XMFLOAT4(0.8f, 0.8f, 0.8f, .5f),
        XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f),
        15.0f,
        m_cylinderTexture.get(),
        m_vertexShader.get(),
        m_pixelShader.get()
        );

    ...

    // Attach the textures to the appropriate game objects.
    // We'll loop through all the objects that need to be rendered.
    for (auto&& object : m_game->RenderObjects())
    {
        if (object->TargetId() == GameConstants::WorldFloorId)
        {
            // Assign a normal material for the floor object.
            // This normal material uses the floor texture (cellfloor.dds) that was loaded asynchronously from
            // the Assets folder using BasicLoader::LoadTextureAsync method in the earlier 
            // CreateGameDeviceResourcesAsync loop

            object->NormalMaterial(
                std::make_shared<Material>(
                    XMFLOAT4(0.5f, 0.5f, 0.5f, 1.0f),
                    XMFLOAT4(0.8f, 0.8f, 0.8f, 1.0f),
                    XMFLOAT4(0.3f, 0.3f, 0.3f, 1.0f),
                    150.0f,
                    m_floorTexture.get(),
                    m_vertexShaderFlat.get(),
                    m_pixelShaderFlat.get()
                    )
                );
            // Creates a mesh object called WorldFloorMesh and assign it to the floor object.
            object->Mesh(std::make_shared<WorldFloorMesh>(d3dDevice));
        }
        ...
        else if (auto cylinder = dynamic_cast<Cylinder*>(object.get()))
        {
            cylinder->Mesh(cylinderMesh);
            cylinder->NormalMaterial(cylinderMaterial);
        }
        else if (auto target = dynamic_cast<Face*>(object.get()))
        {
            const int bufferLength = 16;
            wchar_t str[bufferLength];
            int len = swprintf_s(str, bufferLength, L"%d", target->TargetId());
            auto string{ winrt::hstring(str, len) };

            winrt::com_ptr<ID3D11ShaderResourceView> texture;
            textureGenerator.CreateTextureResourceView(string, texture.put());
            target->NormalMaterial(
                std::make_shared<Material>(
                    XMFLOAT4(0.8f, 0.8f, 0.8f, 0.5f),
                    XMFLOAT4(0.8f, 0.8f, 0.8f, 0.5f),
                    XMFLOAT4(0.3f, 0.3f, 0.3f, 1.0f),
                    5.0f,
                    texture.get(),
                    m_vertexShader.get(),
                    m_pixelShader.get()
                    )
                );

            texture = nullptr;
            textureGenerator.CreateHitTextureResourceView(string, texture.put());
            target->HitMaterial(
                std::make_shared<Material>(
                    XMFLOAT4(0.8f, 0.8f, 0.8f, 0.5f),
                    XMFLOAT4(0.8f, 0.8f, 0.8f, 0.5f),
                    XMFLOAT4(0.3f, 0.3f, 0.3f, 1.0f),
                    5.0f,
                    texture.get(),
                    m_vertexShader.get(),
                    m_pixelShader.get()
                    )
                );

            target->Mesh(targetMesh);
        }
        ...
    }

    // The SetProjParams method calculates the projection matrix based on input params and
    // ensures that the camera has been initialized with the right projection
    // matrix.  
    // The camera is not created at the time the first window resize event occurs.

    auto renderTargetSize = m_deviceResources->GetRenderTargetSize();
    m_game->GameCamera().SetProjParams(
        XM_PI / 2,
        renderTargetSize.Width / renderTargetSize.Height,
        0.01f,
        100.0f
        );

    // Make sure that the correct projection matrix is set in the ConstantBufferChangeOnResize buffer.

    // Get the 3D rotation transform matrix. We are handling screen rotations directly to eliminate an unaligned 
    // fullscreen copy. So it is necessary to post multiply the 3D rotation matrix to the camera's projection matrix
    // to get the projection matrix that we need.

    auto orientation = m_deviceResources->GetOrientationTransform3D();

    ConstantBufferChangeOnResize changesOnResize;

    // The matrices are transposed due to the shader code expecting the matrices in the opposite
    // row/column order from the DirectX math library.

    // XMStoreFloat4x4 takes a matrix and writes the components out to sixteen single-precision floating-point values at the given address. 
    // The most significant component of the first row vector is written to the first four bytes of the address, 
    // followed by the second most significant component of the first row, and so on. The second row is then written out in a 
    // like manner to memory beginning at byte 16, followed by the third row to memory beginning at byte 32, and finally 
    // the fourth row to memory beginning at byte 48. For more API ref info, go to: 
    // https://msdn.microsoft.com/library/windows/desktop/microsoft.directx_sdk.storing.xmstorefloat4x4.aspx

    XMStoreFloat4x4(
        &changesOnResize.projection,
        XMMatrixMultiply(
            XMMatrixTranspose(m_game->GameCamera().Projection()),
            XMMatrixTranspose(XMLoadFloat4x4(&orientation))
            )
        );

    // UpdateSubresource method instructs CPU to copy data from memory (changesOnResize) to a subresource 
    // created in non-mappable memory (m_constantBufferChangeOnResize ) which was created in the earlier 
    // CreateGameDeviceResourcesAsync method.

    m_deviceResources->GetD3DDeviceContext()->UpdateSubresource(
        m_constantBufferChangeOnResize.get(),
        0,
        nullptr,
        &changesOnResize,
        0,
        0
        );

    // Finally we set the m_gameResourcesLoaded as TRUE, so we can start rendering.
    m_gameResourcesLoaded = true;
}

CreateWindowSizeDependentResource yöntemi

CreateWindowSizeDependentResources yöntemleri, pencere boyutu, yönlendirme, stereo özellikli işleme veya çözünürlük her değiştiğinde çağrılır. Örnek oyunda, ConstantBufferChangeOnResizeiçindeki projeksiyon matrisini güncelleştirir.

Pencere boyutu kaynakları şu şekilde güncelleştirilir:

  • Uygulama çerçevesi, pencere durumunda bir değişikliği gösteren birkaç olası olaydan birini alır.
  • Ardından ana oyun döngünüz olay hakkında bilgilendirilir ve ana sınıf (GameMain) örneğindeki CreateWindowSizeDependentResources fonksiyonunu çağırır; bu da, oyun işleyicisindeki (GameRenderer) sınıfındaki CreateWindowSizeDependentResources uygulamasını çağırır.
  • Bu yöntemin birincil işi, pencere özelliklerindeki bir değişiklik nedeniyle görsellerin karıştırılmadığından veya geçersiz olmadığından emin olmaktır.

Bu örnek oyun için bir dizi yöntem çağrısı, FinalizeCreateGameDeviceResources yöntemiyle aynıdır. Kod kılavuzu için önceki bölüme gidin.

Oyun HUD ve yer paylaşımlı pencere boyutu işleme ayarlamaları, kullanıcı arabirimi eklemealtında kapsanmaktadır.

// Initializes view parameters when the window size changes.
void GameRenderer::CreateWindowSizeDependentResources()
{
    // Game HUD and overlay window size rendering adjustments are done here
    // but they'll be covered in the UI section instead.

    m_gameHud.CreateWindowSizeDependentResources();

    ...

    auto d3dContext = m_deviceResources->GetD3DDeviceContext();
    // In Sample3DSceneRenderer::CreateWindowSizeDependentResources, we had:
    // Size outputSize = m_deviceResources->GetOutputSize();

    auto renderTargetSize = m_deviceResources->GetRenderTargetSize();

    ...

    m_gameInfoOverlay.CreateWindowSizeDependentResources(m_gameInfoOverlaySize);

    if (m_game != nullptr)
    {
        // Similar operations as the last section of FinalizeCreateGameDeviceResources method
        m_game->GameCamera().SetProjParams(
            XM_PI / 2, renderTargetSize.Width / renderTargetSize.Height,
            0.01f,
            100.0f
            );

        XMFLOAT4X4 orientation = m_deviceResources->GetOrientationTransform3D();

        ConstantBufferChangeOnResize changesOnResize;
        XMStoreFloat4x4(
            &changesOnResize.projection,
            XMMatrixMultiply(
                XMMatrixTranspose(m_game->GameCamera().Projection()),
                XMMatrixTranspose(XMLoadFloat4x4(&orientation))
                )
            );

        d3dContext->UpdateSubresource(
            m_constantBufferChangeOnResize.get(),
            0,
            nullptr,
            &changesOnResize,
            0,
            0
            );
    }
}

Sonraki Adımlar

Bu, bir oyunun grafik işleme çerçevesini uygulamaya yönelik temel süreçtir. Oyununuz ne kadar büyük olursa, nesne türlerinin ve animasyon davranışlarının hiyerarşilerini işlemek için o kadar fazla soyutlama yapmak zorunda olursunuz. Kafesler ve dokular gibi varlıkları yüklemek ve yönetmek için daha karmaşık yöntemler uygulamanız gerekir. Sonraki adımda bir kullanıcı arayüzüeklemeyi öğrenelim.