Direct3D11(C++):渲染(基本)问题
我一直在关注一本关于 D3D11 游戏编程基础知识的书。我现在了解了 Direct3D 的绝对基础知识:)
但是...我有一个问题。 在书中,我总是必须一次制作一个演示。现在,我正在尝试用它制作一个 2D 游戏。因为我不想养成坏习惯,所以我需要你的建议。
在书中,我总是必须定义一个(具有 texcoord 和位置成员的 struct VertexPos)或(仅具有 XMFLOAT3 位置成员的 struct VertexPos)。在我正在制作的游戏中,我希望能够绘制没有纹理的实体表面和有纹理的表面。我不知道如何做到这一点,更不用说有效地做到这一点了。
这是我的渲染函数:
void GameSpriteDemo::Render()
{
if (m_pD3DContext == 0)
{return;}
float ClearColor[4] = {0.0f, 0.0f, 0.25f, 1.0f};
m_pD3DContext->ClearRenderTargetView(m_pBackBufferTarget,ClearColor);
UINT stride = sizeof(VertexPos);
UINT offset = 0;
m_pD3DContext->IASetInputLayout(m_pInputLayout);
m_pD3DContext->IASetVertexBuffers(0,1,&m_pVertexBuffer, &stride, &offset);
m_pD3DContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_pD3DContext->VSSetShader(m_pSolidColorVS,0,0);
m_pD3DContext->PSSetShader(m_pSolidColorPS,0,0);
m_pD3DContext->PSSetShaderResources(0,1,&m_pColorMap);
m_pD3DContext->PSSetSamplers(0,1,&m_pColorMapSampler);
for(int i=0; i < 2; ++i)
{
XMMATRIX world = m_Sprites[i].GetWorldMatrix();
XMMATRIX mvp = XMMatrixMultiply( world, m_VpMatrix );
mvp = XMMatrixTranspose(mvp);
m_pD3DContext->UpdateSubresource(m_pMvpCB,0,0,&mvp,0,0);
m_pD3DContext->VSSetConstantBuffers(0,1,&m_pMvpCB);
m_pD3DContext->Draw(6,0);
}
m_pSwapChain->Present(0,0);
}
那么,我应该如何使用多个顶点缓冲区、输入布局、着色器、搅拌器等有效地处理这个问题?
我是否应该创建这些版本的多个版本,然后在 Draw 调用之后设置重置输入程序集、着色器等?或者这不起作用/效率不高?
谢谢 :)
I've been following a book about basics for game programming with D3D11. I now understand the absolute basics of Direct3D :)
but... I have a question.
In the book, I always had to make one demo at a time. Now, I'm trying to make a 2D game with it. Since I don't want to get used to bad habits so I need your advice.
In the book, I always had to define a (struct VertexPos with texcoord and position members) OR (struct VertexPos with only a XMFLOAT3 position member). In the game I'm making, I want to be able to draw both solid surfaces without textures and surfaces with textures. I'm not sure how to do this, let alone do this efficiently.
Here is my rendering function:
void GameSpriteDemo::Render()
{
if (m_pD3DContext == 0)
{return;}
float ClearColor[4] = {0.0f, 0.0f, 0.25f, 1.0f};
m_pD3DContext->ClearRenderTargetView(m_pBackBufferTarget,ClearColor);
UINT stride = sizeof(VertexPos);
UINT offset = 0;
m_pD3DContext->IASetInputLayout(m_pInputLayout);
m_pD3DContext->IASetVertexBuffers(0,1,&m_pVertexBuffer, &stride, &offset);
m_pD3DContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_pD3DContext->VSSetShader(m_pSolidColorVS,0,0);
m_pD3DContext->PSSetShader(m_pSolidColorPS,0,0);
m_pD3DContext->PSSetShaderResources(0,1,&m_pColorMap);
m_pD3DContext->PSSetSamplers(0,1,&m_pColorMapSampler);
for(int i=0; i < 2; ++i)
{
XMMATRIX world = m_Sprites[i].GetWorldMatrix();
XMMATRIX mvp = XMMatrixMultiply( world, m_VpMatrix );
mvp = XMMatrixTranspose(mvp);
m_pD3DContext->UpdateSubresource(m_pMvpCB,0,0,&mvp,0,0);
m_pD3DContext->VSSetConstantBuffers(0,1,&m_pMvpCB);
m_pD3DContext->Draw(6,0);
}
m_pSwapChain->Present(0,0);
}
So, how should I handle this efficiently with multiple vertex buffers, input layouts, Shaders, Blenders, etc?
Should I just create multiple versions of those, and then set reset the input assembly, shaders and such after the Draw call? Or does this not work/ is this not efficient?
Thanks :)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
简单的答案是肯定的,您应该创建多个顶点缓冲区、输入布局、着色器等,并在每个相应的绘制调用之前设置适当的缓冲区。这将会起作用并且相当高效(对于现代硬件上的 2D 游戏来说应该足够高效)。
在完整的 3D 游戏引擎中,事情往往会变得更加复杂。通常,渲染引擎将在原始对象(例如顶点和索引缓冲区、输入布局、着色器等)之上有一些额外的内部抽象层。
一种相当常见的简单的结构化方法是拥有一个 Mesh 类,它知道所有的顶点缓冲区、索引缓冲区、输入布局、着色器、纹理等构成了可以在单个绘制调用中绘制的 3D 模型的一部分,并负责设置它们全部(通常与渲染状态的其他位一起设置)混合模式、剔除模式等)并发出相应的绘制调用。
更改任何设备状态都会产生相关成本,因此渲染引擎通常设计为尝试对特定帧中需要绘制的所有对象进行排序,以便最大限度地减少所需的状态更改数量。例如,在《战争黎明 2》渲染器中,我们对所有网格几何体进行了排序,以便我们可以在绘制具有不同顶点和索引缓冲区、纹理的所有太空海军陆战队员身体之前,以最小的状态更改来绘制所有太空海军陆战队头盔。与过去相比,
现代 3D 硬件和 API 更改状态的开销有所减少,因此进行排序以最大限度地减少状态更改不再像以前那么重要,但对于需要在 PC 上获得最大性能的游戏来说,这仍然是常见做法。
在支持灵活的光照和材质模型以及蒙皮动画、地形、粒子系统、全屏效果、2D UI 等的数据驱动渲染引擎中,适合管理绘制游戏对象所需的所有状态和对它进行排序以便以最大效率进行绘制可能会变得相当复杂,并且有许多不同的方法来构建事物。所有可归类为“渲染器状态管理”的代码通常构成典型渲染引擎中代码的重要部分。
The simple answer is yes, you should create multiple vertex buffers, input layouts, shaders, etc. and set the appropriate ones before each corresponding draw call. This will work and is reasonably efficient (should be efficient enough for a 2D game on modern hardware).
Things tend to get a bit more complicated in a full 3D game engine. Typically the rendering engine will have some additional internal levels of abstraction layered on top of primitive objects like vertex and index buffers, input layouts, shaders etc.
A reasonably common simple way of structuring things is to have a Mesh class which knows about all of the vertex buffers, index buffers, input layouts, shaders, textures, etc. which make up a bit of a 3D model that can be drawn in a single draw call and is responsible for setting them all (often along with other bits of render state like blend modes, culling modes, etc.) and issuing the corresponding draw call.
There is a cost associated with changing any device state and so rendering engines are often designed to try and sort all the objects that need drawing in a particular frame so as to minimize the number of state changes required. In the Dawn of War 2 renderer for example we sorted all of the mesh geometry so that we could draw e.g. all of the space marine helmets with minimal state changes required before drawing all of the space marine bodies with different vertex and index buffers, textures, etc.
Modern 3D hardware and APIs have somewhat less overhead for changing state than in the past so sorting to minimize state changes is a bit less important than it once was but it is still common practice for games that need to get maximum performance on the PC.
In a data driven rendering engine that supports a flexible lighting and material model along with skinned animation, terrain, particle systems, full screen effects, 2D UI, etc. a suitable design for managing all of the state required to draw the game objects and for sorting it so it can be drawn with maximum efficiency can get quite complex and there are many different approaches to structuring things. The code for everything that could be classed as 'renderer state management' often makes up a significant portion of the code in a typical rendering engine.