绘制到屏幕Draw to the screen

重要的 APIImportant APIs

最终,我们会移植可将旋转立方体绘制到屏幕的代码。Finally, we port the code that draws the spinning cube to the screen.

在 OpenGL ES 2.0 中,你的绘制上下文被定义为 EGLContext 类型,该类型包含窗口和图面参数以及绘制到呈现目标所需的资源,将使用呈现目标来编写显示到窗口的最终图像。In OpenGL ES 2.0, your drawing context is defined as an EGLContext type, which contains the window and surface parameters as well the resources necessary for drawing to the render targets that will be used to compose the final image displayed to the window. 你将使用此上下文来配置图形资源,以便在显示器上正确显示着色器管道的结果。You use this context to configure the graphics resources to correctly display the results of your shader pipeline on the display. 其中一个主要资源是“后台缓冲区”(或“帧缓冲区对象”),它包含可显示到显示器的最终复合呈现目标。One of the primary resources is the "back buffer" (or "frame buffer object") that contains the final, composited render targets, ready for presentation to the display.

对于 Direct3D,配置图形资源以便绘制到显示器的过程说教性较强,并且需要相当多的 API。With Direct3D, the process of configuring the graphics resources for drawing to the display is more didactic, and requires quite a few more APIs. (但是 Microsoft Visual Studio Direct3D 模板可以大大简化这个过程!)若要获取上下文(称为 Direct3D 设备上下文),必须首先获取 ID3D11Device1 对象,然后使用该对象来创建和配置 ID3D11DeviceContext1 对象。(A Microsoft Visual Studio Direct3D template can significantly simplify this process, though!) To obtain a context (called a Direct3D device context), you must first obtain an ID3D11Device1 object, and use it to create and configure an ID3D11DeviceContext1 object. 结合使用这两个对象来配置绘制到显示器所需的特定资源。These two objects are used in conjunction to configure the specific resources you need for drawing to the display.

简而言之,DXGI API 包含的 API 主要用于管理与图形适配器直接相关的资源,而 Direct3D 包含的 API 可用作 GPU 与在 CPU 上运行的主要程序之间的接口。In short, the DXGI APIs contain primarily APIs for managing resources that directly pertain to the graphics adapter, and Direct3D contains the APIs that allow you to interface between the GPU and your main program running on the CPU.

为了在该示例中进行比较,我们在下面给出了每个 API 的相关类型:For the purposes of comparison in this sample, here are the relevant types from each API:

  • ID3D11Device1:提供图形设备及其资源的视觉表示。ID3D11Device1: provides a virtual representation of the graphics device and its resources.
  • ID3D11DeviceContext1:提供用于配置缓冲区以及发出呈现命令的接口。ID3D11DeviceContext1: provides the interface to configure buffers and issue rendering commands.
  • IDXGISwapChain1:交换链类似于 OpenGL ES 2.0 中的后台缓冲区。IDXGISwapChain1: the swap chain is analogous to the back buffer in OpenGL ES 2.0. 它是图形适配器上的内存区域,其中包含用于显示的最终呈现的图像。It is the region of memory on the graphics adapter that contains the final rendered image(s) for display. 它称为“交换链”,因为它包含多个可以写入以及“已进行交换”可向屏幕提供最新呈现的缓冲区。It is called the "swap chain" because it has several buffers that can be written to and "swapped" to present the latest render to the screen.
  • ID3D11RenderTargetView:它包含 Direct3D 设备上下文在其中进行绘制且由交换链提供的 2D 位图缓冲区。ID3D11RenderTargetView: this contains the 2D bitmap buffer that the Direct3D device context draws into, and which is presented by the swap chain. 和 OpenGL ES 2.0 一样,你可以拥有多个呈现目标,其中一些目标未绑定到交换链,但用于多通道着色技术。As with OpenGL ES 2.0, you can have multiple render targets, some of which are not bound to the swap chain but are used for multi-pass shading techniques.

在该模板中,呈现器对象包含以下字段:In the template, the renderer object contains the following fields:

Direct3D 11:设备和设备上下文声明Direct3D 11: Device and device context declarations

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;

下面介绍了如何将后台缓冲区配置为呈现目标以及如何将其提供给交换链。Here's how the back buffer is configured as a render target and provided to the swap chain.

ComPtr<ID3D11Texture2D> backBuffer;
m_swapChainCoreWindow->GetBuffer(0, IID_PPV_ARGS(backBuffer));
m_d3dDevice->CreateRenderTargetView(
  backBuffer.Get(),
  nullptr,
  &m_d3dRenderTargetViewWin);

Direct3D 运行时为 ID3D11Texture2D 隐式创建一个 IDXGISurface1,它将纹理表示为交换链可以用于显示器的“后台缓冲区”。The Direct3D runtime implicitly creates an IDXGISurface1 for the ID3D11Texture2D, which represents the texture as a "back buffer" that the swap chain can use for display.

Direct3D 设备和设备上下文以及呈现目标的初始化和配置可以在 Direct3D 模板的自定义 CreateDeviceResourcesCreateWindowSizeDependentResources 方法中找到。The initialization and configuration of the Direct3D device and device context, as well as the render targets, can be found in the custom CreateDeviceResources and CreateWindowSizeDependentResources methods in the Direct3D template.

当 Direct3D 设备上下文与 EGL 和 EGLContext 类型相关时有关该上下文的详细信息,请参阅将 EGL 代码移植到 DXGI 和 Direct3DFor more info on Direct3D device context as it relates to EGL and the EGLContext type, read Port EGL code to DXGI and Direct3D.

InstructionsInstructions

步骤 1:呈现场景并进行显示Step 1: Rendering the scene and displaying it

更新立方体数据(在本例中,将其围绕 y 轴稍稍旋转)后,Render 方法将视口设置为绘制上下文 (EGLSurface) 的尺寸。After updating the cube data (in this case, by rotating it slightly around the y axis), the Render method sets the viewport to the dimensions of he drawing context (an EGLContext). 该上下文包含将使用配置的显示器 (EGLDisplay) 显示到窗口图面 (EGLSurface) 的颜色缓冲区。This context contains the color buffer that will be displayed to the window surface (an EGLSurface), using the configured display (EGLDisplay). 此时,该示例更新顶点数据属性、重新绑定索引缓冲区、绘制立方体,并在着色管道绘制的颜色缓冲区中交换到显示器图面。At this time, the example updates the vertex data attributes, re-binds the index buffer, draws the cube, and swaps in color buffer drawn by the shading pipeline to the display surface.

OpenGL ES 2.0:呈现用于显示的帧OpenGL ES 2.0: Rendering a frame for display

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 中,该过程非常相似。In Direct3D 11, the process is very similar. (我们假定你使用 Direct3D 模板中的视区和呈现目标配置。)(We're assuming that you're using the viewport and render target configuration from the Direct3D template.

Direct3D 11:呈现用于显示的帧Direct3D 11: Rendering a frame for display

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, &parameters);
}

调用 IDXGISwapChain1::Present1 之后,你的帧会输出到配置的显示器。Once IDXGISwapChain1::Present1 is called, your frame is output to the configured display.

上一步Previous step

移植 GLSLPort the GLSL

备注Remarks

该示例掩盖了很多与配置设备资源相关的复杂事项,对于通用 Windows 平台 (UWP) DirectX 应用来说更是如此。This example glosses over much of the complexity that goes into configuring device resources, especially for Universal Windows Platform (UWP) DirectX apps. 我们建议你查看全部模板代码,尤其是执行窗口和设备资源设置和管理的部分。We suggest you review the full template code, especially the parts that perform the window and device resource setup and management. UWP 应用必须支持旋转事件以及暂停/恢复事件,并且该模板演示了处理显示参数中缺少接口或更改的最佳做法。UWP apps have to support rotation events as well as suspend/resume events, and the template demonstrates best practices for handling the loss of an interface or a change in the display parameters.