Desenhar na tela

APIs importantes

Por fim, compatibilizamos o código que desenha o cubo giratório na tela.

No OpenGL ES 2.0, o contexto de desenho é definido como um tipo EGLContext, que contém os parâmetros de janela e superfície, além dos recursos necessários para desenhar em destinos de renderização que serão usados para compor a imagem final exibida na janela. Use esse contexto para configurar os recursos gráficos e apresentar corretamente os resultados do pipeline do sombreador na exibição. Um dos recursos principais é o "buffer de fundo" (ou "objeto de buffer de quadros"), que contém os destinos de renderização finais (compostos), prontos para apresentação na exibição.

Com o Direct3D, o processo de configuração dos recursos gráficos para desenhar na tela é mais didático e requer bem menos APIs. (Porém, um modelo Direct3D do Microsoft Visual Studio pode simplificar bastante esse processo!) Para obter um contexto (chamado de um contexto de dispositivo Direct3D), primeiro você deve obter um objeto ID3D11Device1 e usá-lo para criar e configurar um objeto ID3D11DeviceContext1. Esses dois objetos são usados em conjunto para configurar recursos específicos de desenho na exibição.

Resumindo: as APIs da DXGI contêm principalmente recursos de gerenciamento relacionados diretamente ao adaptador gráfico, e o Direct3D contém APIs que permitem a interação entre a GPU e o programa principal executado na CPU.

Para fins de comparação nesta amostra, consulte os tipos relevantes de APIs:

  • ID3D11Device1: oferece uma representação visual do dispositivo de elementos gráficos e de seus recursos.
  • ID3D11DeviceContext1: oferece a interface de configuração de buffers e emissão de comandos de renderização.
  • IDXGISwapChain1: a cadeia de troca é análoga ao buffer de fundo no OpenGL ES 2.0. No adaptador gráfico, corresponde à região da memória que contém as imagens finais renderizadas para exibição. Ela é chamada de "cadeia de troca" porque tem diversos buffers que podem ser gravados e "trocados" para apresentar o renderizador mais recente na tela.
  • ID3D11RenderTargetView: contém o buffer de bitmap 2D no qual o contexto de dispositivo Direct3D desenha e que é apresentado pela cadeia de troca. Assim como no OpenGL ES 2.0, você pode ter vários destinos de renderização, alguns não vinculados à cadeia de troca, mas usados para técnicas de sombreamento com passagem múltipla.

No modelo, o objeto de renderizador contém os seguintes campos:

Direct3D 11: declarações de dispositivo e contexto de dispositivo

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;

Veja a seguir como o buffer de fundo é configurado como destino de renderização e fornecido à cadeia de troca.

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

O tempo de execução do Direct3D cria implicitamente uma IDXGISurface1 para a ID3D11Texture2D, que representa a textura como um "buffer de fundo" que a cadeia de troca pode usar para exibição.

A inicialização e a configuração do dispositivo Direct3D e de seu respectivo contexto, bem como dos destinos de renderização, podem ser encontradas nos métodos personalizados CreateDeviceResources e CreateWindowSizeDependentResources no modelo do Direct3D.

Para saber mais sobre o contexto de dispositivo Direct3D relacionado a EGL e ao tipo EGLContext, leia o tópico sobre portabilidade do código EGL para DXGI e Direct3D.

Instruções

Etapa 1: renderizando a cena e exibindo-a

Depois de atualizar os dados do cubo (neste caso, girando-o um pouco em torno do eixo y), o método Render define o visor de acordo com as dimensões do contexto de desenho (EGLContext). Esse contexto contém o buffer de cor que será exibido na superfície da janela (uma EGLSurface), usando a exibição configurada (EGLDisplay). Neste momento, o exemplo atualiza os atributos de dados de vértice, vincula o buffer de índice novamente, desenha o cubo e alterna para o buffer de cor desenhado pelo pipeline de sombreamento na superfície de exibição.

OpenGL ES 2.0: renderizando um quadro para exibição

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);
}

No Direct3D 11, o processo é muito parecido (supomos que você esteja usando a configuração de destino de renderização e visor do modelo Direct3D).

Direct3D 11: renderizando um quadro para exibição

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);
}

Depois que você chama IDXGISwapChain1::Present1, seu quadro é gerado na exibição configurada.

Etapa anterior

Fazer a portabilidade do GLSL

Comentários

Este exemplo fala muito da complexidade de configurar recursos de dispositivo, principalmente para aplicativos UWP (Plataforma Universal do Windows) em DirectX. Sugerimos que você revise o código completo do modelo, especialmente as partes que executam a configuração e o gerenciamento de recursos de janela e dispositivo. Os aplicativos UWP devem oferecer suporte a eventos de rotação e suspensão/retomada. Além disso, o modelo demonstra as práticas recomendadas para lidar com a perda e uma interface ou alterações nos parâmetros de exibição.