繪製到螢幕
重要 API
最後,我們將繪製旋轉立方結構的程式碼移植到螢幕上。
在 OpenGL ES 2.0 中,繪圖背景內容定義為 EGLContext 型別,該型別包含視窗和曲面參數以及繪製到渲染目標所需的資源,該渲染目標將用來構成顯示在視窗中的最終影像。 您可以使用此前後關聯來設定圖形資源,以正確顯示著色器流程的結果。 其中一個主要資源是後緩衝器 (或幀緩衝器物件),它包含最終的複合渲染目標,準備呈現給顯示器。
在 Direct3D 中,配置繪圖到顯示器的圖形資源的過程更加說教,並且需要相當多的 API。 (不過,Microsoft Visual Studio Direct3D 範本可大幅簡化此程式!)若要取得內容 (稱為 Direct3D 裝置內容),您必須先取得 ID3D11Device1 物件,然後使用它來建立和設定 ID3D11DeviceContext1 物件。 這兩個物件可搭配使用,以設定繪圖至顯示所需的特定資源。
簡而言之,DXGI API 主要包含用於管理直接與圖形介面卡相關的資源的 API,而 Direct3D 包含允許在 GPU 和在 CPU 上運行的主程式之間進行介面的 API。
為便於在本範例中比較,以下是每個 API 的相關型別:
- ID3D11Device1:提供圖形裝置及其資源的虛擬表示。
- ID3D11DeviceContext1:提供介面以設定緩衝區並發出轉譯命令。
- IDXGI SwapChain1:交換鏈類似 OpenGL ES 2.0 中的後緩衝區。 它是圖形介面卡上的記憶體區域,包含最終的彩現影像以供顯示。 它被稱為交換鏈,因為它有多個緩衝區,可以寫入和交換以將最新渲染顯示到螢幕上。
- ID3D11RenderTargetView:它包含 Direct3D 裝置內容所擷取的 2D 點陣圖緩衝區,並由交換鏈呈現。 與 OpenGL ES 2.0 一樣,您可以擁有多個渲染目標,其中某些目標未繫結到交換鏈,但用於多路徑著色技術。
在範本中,轉譯器物件包含下列欄位:
Direct3D 11:裝置和裝置內容宣告
Platform::Agile<Windows::UI::Core::CoreWindow> m_window;
Microsoft::WRL::ComPtr<ID3D11Device1> m_d3dDevice;
Microsoft::WRL::ComPtr<ID3D11DeviceContext1> m_d3dContext;
Microsoft::WRL::ComPtr<IDXGISwapChain1> m_swapChainCoreWindow;
Microsoft::WRL::ComPtr<ID3D11RenderTargetView> m_d3dRenderTargetViewWin;
下面說明如何將後緩衝器配置為呈現目標並提供給交換鏈。
ComPtr<ID3D11Texture2D> backBuffer;
m_swapChainCoreWindow->GetBuffer(0, IID_PPV_ARGS(backBuffer));
m_d3dDevice->CreateRenderTargetView(
backBuffer.Get(),
nullptr,
&m_d3dRenderTargetViewWin);
Direct3D 執行階段會為 ID3D11Texture2D,隱含建立 IDXGI Surface1,此表示紋理為交換鏈可用於顯示的後緩衝區。
您可以在 Direct3D 範本的自訂 CreateDeviceResources 和 CreateWindowSizeDependentResources 方法中找到 Direct3D 裝置和裝置前後關聯的初始化和設定,以及轉譯目標。
如需有關 Direct3D 裝置前後關聯與 EGL 和 EGLContext 型別的詳細資訊,請閱讀 Port EGL 程式碼至 DXGI 和 Direct3D。
指示
步驟 1:呈現場景並顯示它
更新立方結構資料後 (在此例中,略微繞 y 軸旋轉),Render 方法會將視角設定為工程圖前後關聯 (EGLContext) 的尺寸。 此內容包含使用設定的顯示 (EGLDisplay) 顯示到視窗表面 (EGLSurface) 的色彩緩衝區。 此時,範例會更新頂點資料屬性、重新繫結索引緩衝區、繪製立方結構,以及將著色器流程所繪製的色彩緩衝區交換至顯示曲面。
OpenGL ES 2.0:轉譯顯示畫面
void Render(GraphicsContext *drawContext)
{
Renderer *renderer = drawContext->renderer;
int loc;
// Set the viewport
glViewport ( 0, 0, drawContext->width, drawContext->height );
// Clear the color buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
// Use the program object
glUseProgram (renderer->programObject);
// Load the a_position attribute with the vertex position portion of a vertex buffer element
loc = glGetAttribLocation(renderer->programObject, "a_position");
glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE,
sizeof(Vertex), 0);
glEnableVertexAttribArray(loc);
// Load the a_color attribute with the color position portion of a vertex buffer element
loc = glGetAttribLocation(renderer->programObject, "a_color");
glVertexAttribPointer(loc, 4, GL_FLOAT, GL_FALSE,
sizeof(Vertex), (GLvoid*) (sizeof(float) * 3));
glEnableVertexAttribArray(loc);
// Bind the index buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, renderer->indexBuffer);
// Load the MVP matrix
glUniformMatrix4fv(renderer->mvpLoc, 1, GL_FALSE, (GLfloat*) &renderer->mvpMatrix.m[0][0]);
// Draw the cube
glDrawElements(GL_TRIANGLES, renderer->numIndices, GL_UNSIGNED_INT, 0);
eglSwapBuffers(drawContext->eglDisplay, drawContext->eglSurface);
}
在 Direct3D 11 中,過程非常相似。 (我們假設您使用視角並從 Direct3D 範本轉譯目標組態。
- 使用對 ID3D11DeviceContext1::UpdateSubresource 的呼叫來更新常數緩衝區 (本例中為model-view-projection matrix)。
- 使用 ID3D11DeviceContext1::IASetVertexBuffers 設定頂點緩衝區。
- 使用 ID3D11DeviceContext1::IASetIndexBuffer 設定索引緩衝區。
- 以 ID3D11DeviceContext1::IASetPrimitiveTopology 設定特定的三角形拓撲 (三角形清單)。
- 使用 ID3D11DeviceContext1::IASetInputLayout,設定頂點緩衝區的輸入配置。
- 以 ID3D11DeviceContext1::VSSetShader 繫結頂點著色器。
- 以 ID3D11DeviceContext1::PSSetShader 繫結片段著色器。
- 透過著色器傳送已編制索引的頂點,並將色彩結果輸出至具有 ID3D11DeviceContext1::DrawIndexed 的彩現目標緩衝區。
- 使用 IDXGI SwapChain1::Present1 顯示轉譯目標緩衝區。
Direct3D 11:呈現用於顯示的框架
void RenderObject::Render()
{
// ...
// Only update shader resources that have changed since the last frame.
m_d3dContext->UpdateSubresource(
m_constantBuffer.Get(),
0,
NULL,
&m_constantBufferData,
0,
0);
// Set up the IA stage corresponding to the current draw operation.
UINT stride = sizeof(VertexPositionColor);
UINT offset = 0;
m_d3dContext->IASetVertexBuffers(
0,
1,
m_vertexBuffer.GetAddressOf(),
&stride,
&offset);
m_d3dContext->IASetIndexBuffer(
m_indexBuffer.Get(),
DXGI_FORMAT_R16_UINT,
0);
m_d3dContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_d3dContext->IASetInputLayout(m_inputLayout.Get());
// Set up the vertex shader corresponding to the current draw operation.
m_d3dContext->VSSetShader(
m_vertexShader.Get(),
nullptr,
0);
m_d3dContext->VSSetConstantBuffers(
0,
1,
m_constantBuffer.GetAddressOf());
// Set up the pixel shader corresponding to the current draw operation.
m_d3dContext->PSSetShader(
m_pixelShader.Get(),
nullptr,
0);
m_d3dContext->DrawIndexed(
m_indexCount,
0,
0);
// ...
m_swapChainCoreWindow->Present1(1, 0, ¶meters);
}
呼叫 IDXGI SwapChain1::Present1 後,您的畫面會輸出到設定的顯示器。
上一步
備註
這個範例掩蓋配置裝置資源所花費的複雜程度,特別是針對 Universal Windows Platform (UWP) DirectX 應用程式。 我們建議您檢閱完整的範本程式碼,尤其是執行視窗與裝置資源設定與管理的零件。 UWP 應用程式必須支援旋轉事件以及暫停/恢復事件,範本示範處理介面遺失或顯示參數變更的最佳作法。
相關主題