如何在 DirectX 11 中绘制/渲染不同的形状

How to draw/render different shapes in DirectX 11

本文关键字:DirectX 绘制      更新时间:2023-10-16

我一直在尝试使用 MSDN tutorial05 示例代码学习 DirectX 11 编程的基础知识,但我遇到了一个问题,我在互联网上找不到解决方案(无论如何我都可以看到(。基本上,我正在尝试绘制和渲染玩家立方体对象,完成用户输入,以及玩家必须收集的金字塔状对象。

我的问题是,当我渲染场景时,只读取立方体顶点(和索引(数据,因此所有对象都是立方体,而它们不应该是立方体。

这是创建顶点数据的函数:

PyramidVertex Pyramid[] =
{
// Square base of the pyramid
{ XMFLOAT3( -0.5f, -0.5f, 0.5f), XMFLOAT4(0.0f, 1.0f, 0.0f, 1.0f) },
{ XMFLOAT3( 0.5f, -0.5f, 0.5f), XMFLOAT4(0.0f, 0.0f, 1.0f, 1.0f) },
{ XMFLOAT3(-0.5f, -0.5f, -0.5f), XMFLOAT4(1.0f, 0.0f, 0.0f, 1.0f) },
{ XMFLOAT3(0.5f, -0.5f, -0.5f), XMFLOAT4(0.0f, 1.0f, 1.0f, 1.0f) },
// The tip of the pyramid
{ XMFLOAT3(0.0f, 0.5f, 0.0f), XMFLOAT4(0.0f, 1.0f, 0.0f, 1.0f) },
};
D3D11_BUFFER_DESC bdP;
ZeroMemory(&bdP, sizeof(bdP));
bdP.Usage = D3D11_USAGE_DEFAULT;
bdP.ByteWidth = sizeof(PyramidVertex) * 5;
bdP.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bdP.CPUAccessFlags = 0;
D3D11_SUBRESOURCE_DATA InitPData;
ZeroMemory(&InitPData, sizeof(InitPData));
InitPData.pSysMem = Pyramid;
hr = g_pd3dDevice->CreateBuffer(&bdP, &InitPData, &g_pVertexBufferP);
if (FAILED(hr))
return hr;  
// Set vertex buffer
UINT pStride = sizeof(PyramidVertex);
UINT pOffset = 1;
g_pImmediateContext->IASetVertexBuffers(0, 1, &g_pVertexBufferP, &pStride, &pOffset);
// create the index buffer 
DWORD pIndex[] =
{
0, 2, 1,    
1, 2, 3,
0, 1, 4,    
1, 3, 4,
3, 2, 4,
2, 0, 4,
};
// create the index buffer
bdP.Usage = D3D11_USAGE_DYNAMIC;
bdP.ByteWidth = sizeof(DWORD) * 18;
bdP.BindFlags = D3D11_BIND_INDEX_BUFFER;
bdP.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
bdP.MiscFlags = 0;
InitPData.pSysMem = pIndex;
hr = g_pd3dDevice->CreateBuffer(&bdP, &InitPData, &g_pIndexBufferP);
if (FAILED(hr))
return hr;
// Set index buffer
g_pImmediateContext->IASetIndexBuffer(g_pIndexBufferP, DXGI_FORMAT_R16_UINT, 0);
// Set primitive topology
g_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

// Create vertex buffer
SimpleVertex vertices[] =
{
{ XMFLOAT3( -1.0f, 1.0f, -1.0f ), XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f ) },
{ XMFLOAT3( 1.0f, 1.0f, -1.0f ), XMFLOAT4(  1.0f, 1.0f, 1.0f, 1.0f ) },
{ XMFLOAT3( 1.0f, 1.0f, 1.0f ), XMFLOAT4( 0.0f, 1.0f, 1.0f, 1.0f ) },
{ XMFLOAT3( -1.0f, 1.0f, 1.0f ), XMFLOAT4(  .0f, 1.0f, 1.0f, 1.0f ) },
{ XMFLOAT3( -1.0f, -1.0f, -1.0f ), XMFLOAT4 (1.0f, 1.0f, 1.0f, 1.0f ) },
{ XMFLOAT3( 1.0f, -1.0f, -1.0f ), XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f ) },
{ XMFLOAT3( 1.0f, -1.0f, 1.0f ), XMFLOAT4(  0.0f, 1.0f, 1.0f, 1.0f ) },
{ XMFLOAT3( -1.0f, -1.0f, 1.0f ), XMFLOAT4( .0f, 1.0f, 1.0f, 1.0f ) },
};
D3D11_BUFFER_DESC bd;
ZeroMemory( &bd, sizeof(bd) );
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof( SimpleVertex ) * 8;
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = 0;
D3D11_SUBRESOURCE_DATA InitData;
ZeroMemory( &InitData, sizeof(InitData) );
InitData.pSysMem = vertices;
hr = g_pd3dDevice->CreateBuffer( &bd, &InitData, &g_pVertexBuffer );
if( FAILED( hr ) )
return hr;
// Set vertex buffer
UINT stride = sizeof( SimpleVertex );
UINT offset = 0;
g_pImmediateContext->IASetVertexBuffers( 0, 1, &g_pVertexBuffer, &stride, &offset );
// Create index buffer
WORD indices[] =
{
3,1,0,
2,1,3,
0,5,4,
1,5,0,
3,4,7,
0,4,3,
1,6,5,
2,6,1,
2,7,6,
3,7,2,
6,4,5,
7,4,6,
};
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof( WORD ) * 36;        // 36 vertices needed for 12 triangles in a triangle list
bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
bd.CPUAccessFlags = 0;
InitData.pSysMem = indices;
hr = g_pd3dDevice->CreateBuffer( &bd, &InitData, &g_pIndexBuffer );
if( FAILED( hr ) )
return hr;
// Set index buffer
g_pImmediateContext->IASetIndexBuffer( g_pIndexBuffer, DXGI_FORMAT_R16_UINT, 0 );
// Set primitive topology
g_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

// Create the constant buffer
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof(ConstantBuffer);
bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
bd.CPUAccessFlags = 0;
hr = g_pd3dDevice->CreateBuffer( &bd, nullptr, &g_pConstantBuffer );
if( FAILED( hr ) )
return hr;
// Create the constant buffer
bdP.Usage = D3D11_USAGE_DEFAULT;
bdP.ByteWidth = sizeof(ConstantBuffer);
bdP.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
bdP.CPUAccessFlags = 0;
hr = g_pd3dDevice->CreateBuffer(&bdP, nullptr, &g_pConstantBufferP);
if (FAILED(hr))
return hr;
// Initialize the world matrix
g_Player = XMMatrixIdentity();
for (int i = 0; i < 10; ++i)
{
g_Shapes[i] = XMMatrixIdentity();
}
// Initialize the view matrix
XMVECTOR Eye = XMVectorSet( 0.0f, 1.0f, -5.0f, 0.0f );
XMVECTOR At = XMVectorSet( 0.0f, 1.0f, 0.0f, 0.0f );
XMVECTOR Up = XMVectorSet( 0.0f, 4.0f, 0.0f, 0.0f );
g_View = XMMatrixLookAtLH( Eye, At, Up );
// Initialize the projection matrix
g_Projection = XMMatrixPerspectiveFovLH( XM_PIDIV2, width / (FLOAT)height, 0.01f, 100.0f );

我相信问题就在这里,我的理论是金字塔g_pImmediateContext在绘制立方体时被覆盖。如果是这种情况,那么我不知道如何解决或研究这个问题。我花了一个小时才弄清楚将我的代码正确放在此页面上,但得到了奇怪的结果,因此如果有人想深入了解(无论出于何种原因(代码,我将留下一个包含此代码的 Google 云端硬盘链接。

这是渲染函数:

//
// Clear the back buffer
//
g_pImmediateContext->ClearRenderTargetView(g_pRenderTargetView, Colors::Black);
//
// Clear the depth buffer to 1.0 (max depth)
//
g_pImmediateContext->ClearDepthStencilView(g_pDepthStencilView, D3D11_CLEAR_DEPTH, 1.0f, 0);
XMMATRIX mRotate = XMMatrixRotationZ(DXGame->playerUser->getRotation());
XMMATRIX mTranslate = XMMatrixTranslation(DXGame->playerUser->getXpos(), DXGame->playerUser->getYpos(), DXGame->playerUser->getZpos());
XMMATRIX mScale = XMMatrixScaling(0.7f, 0.7f, 0.7f);
g_Player = mScale * mRotate * mTranslate;
ConstantBuffer cb1;
cb1.mWorld = XMMatrixTranspose(g_Player);
cb1.mView = XMMatrixTranspose(g_View);
cb1.mProjection = XMMatrixTranspose(g_Projection);
g_pImmediateContext->UpdateSubresource(g_pConstantBuffer, 0, nullptr, &cb1, 0, 0);
g_pImmediateContext->VSSetShader(g_pVertexShader, nullptr, 0);
g_pImmediateContext->VSSetConstantBuffers(0, 1, &g_pConstantBuffer);
g_pImmediateContext->PSSetShader(g_pPixelShader, nullptr, 0);
g_pImmediateContext->DrawIndexed(36, 0, 0);

for (int i = 0; i < 10; i++)
{   
XMMATRIX sRotate = XMMatrixRotationY((DXGame->pickUps[i].rotation += 0.001f));
XMMATRIX sTranslate = XMMatrixTranslation(DXGame->pickUps[i].xPos, DXGame->pickUps[i].yPos, DXGame->pickUps[i].zPos);
XMMATRIX sScale = XMMatrixScaling(0.2f, 0.2f, 0.2f);
g_Shapes[i] = sScale * sRotate * sTranslate;        
ConstantBuffer constB;
constB.mWorld = XMMatrixTranspose(g_Shapes[i]);
constB.mView = XMMatrixTranspose(g_View);
constB.mProjection = XMMatrixTranspose(g_Projection);
g_pImmediateContext->UpdateSubresource(g_pConstantBufferP, 0, nullptr, &constB, 0, 0);
g_pImmediateContext->VSSetShader(g_pVertexShader, nullptr, 0);
g_pImmediateContext->VSSetConstantBuffers(0, 1, &g_pConstantBufferP);
g_pImmediateContext->PSSetShader(g_pPixelShader, nullptr, 0);
g_pImmediateContext->DrawIndexed(18, 0, 0);
}
g_pSwapChain->Present(0, 0);

我还在研究常量缓冲区和 HLSL,看看这是否也是一个问题。

请有人至少指出我正确的方向,因为这个问题已经困扰了我将近 2 个月(我离开了这么久,因为我想自己弄清楚,但现在我迫切需要解决方案(。

感谢您抽出宝贵时间阅读这篇文章,抱歉它太长了,但我需要尽可能多地获取信息,希望它更容易阅读。

您对IASetIndexBuffer和IASetVertexBuffers的调用在您的创建例程中,它们需要位于渲染函数中(在调用相关的Draw函数之前,因为它们在绘制之前将这些缓冲区附加到运行时(

它们根本不需要在创建部分(如在 DirectX11 上下文中,例如构建命令和设备,例如:创建资源是分离的(。

在渲染循环中,您应该有:

// Set vertex buffer and index buffer for your cube
UINT stride = sizeof( SimpleVertex );
UINT offset = 0;
g_pImmediateContext->IASetVertexBuffers( 0, 1, &g_pVertexBuffer, &stride, 
&offset );
// Set index buffer
g_pImmediateContext->IASetIndexBuffer( g_pIndexBuffer, DXGI_FORMAT_R16_UINT, 
0 );
g_pImmediateContext->VSSetShader(g_pVertexShader, nullptr, 0);
g_pImmediateContext->VSSetConstantBuffers(0, 1, &g_pConstantBuffer);
g_pImmediateContext->PSSetShader(g_pPixelShader, nullptr, 0);
g_pImmediateContext->DrawIndexed(36, 0, 0);

就在绘制所有金字塔之前:

// Set vertex buffer and index buffer for pyramids as you will draw it 10 times, you can do it once just before the loop as geometry will not change
UINT stride = sizeof( SimpleVertex );
UINT offset = 0;
g_pImmediateContext->IASetVertexBuffers( 0, 1, &g_pVertexBuffer, &stride, 
&offset );
// Set index buffer
g_pImmediateContext->IASetIndexBuffer(g_pIndexBufferP, DXGI_FORMAT_R16_UINT, 0);

for (int i = 0; i < 10; i++)
{ 
//Same draw code as before 
}