重要的应用程序接口(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:提供用于配置缓冲区和发出呈现命令的接口。
- IDXGISwapChain1:交换链类似于 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创建 IDXGISurface1,该表面将纹理作为交换链可用于显示的“后台缓冲区”呈现。
Direct3D 设备和设备上下文的初始化和配置以及呈现目标可以在 Direct3D 模板中的自定义 CreateDeviceResources 和 CreateWindowSizeDependentResources 方法中找到。
有关 Direct3D 设备上下文与 EGL 和 EGLContext 类型的关系的详细信息,请阅读 将 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更新常量缓冲区(在本例中为模型视图投影矩阵)。
- 使用 ID3D11DeviceContext1::IASetVertexBuffers设置顶点缓冲区。
- 使用 ID3D11DeviceContext1::IASetIndexBuffer设置索引缓冲区。
- 使用 ID3D11DeviceContext1::IASetPrimitiveTopology设置特定的三角形拓扑(三角形列表)。
- 使用 ID3D11DeviceContext1::IASetInputLayout来设置顶点缓冲区的输入布局。
- 将顶点着色器与 ID3D11DeviceContext1::VSSetShader绑定。
- 将片段着色器与 ID3D11DeviceContext1::P SSetShader绑定。
- 将索引顶点通过着色器发送,并将颜色结果输出到渲染目标缓冲区,ID3D11DeviceContext1::DrawIndexed。
- 使用 IDXGISwapChain1::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);
}
调用 IDXGISwapChain1::Present1 后,帧将输出到配置的显示器。
上一步
注解
该示例忽略了配置设备资源过程中的许多复杂性,特别是在针对通用 Windows 平台 (UWP) 的 DirectX 应用程序时。 建议查看完整的模板代码,尤其是执行窗口和设备资源设置和管理的部分。 UWP 应用必须支持轮换事件以及暂停/恢复事件,模板演示了处理接口丢失或更改显示参数的最佳做法。
相关主题