共用方式為


移植頂點緩衝區和資料

重要 API

在此步驟中,您將定義包含網格的頂點緩衝區,以及允許著色器以指定順序周遊頂點的索引緩衝區。

此時,讓我們檢查我們所使用的立方體網格硬式編碼模型。 這兩個表示法都有組織為三角形清單的頂點 (相對於帶狀結構或其他更有效率的三角形配置)。 這兩個表示法中的所有頂點也都有相關聯的索引和色彩值。 本主題中的大部分 Direct3D 程式碼都是指 Direct3D 專案中定義的變數和物件。

以下是 OpenGL ES 2.0 處理的立方體。 在範例實作中,每個頂點都是 7 個浮點值:3 個位置座標,後面接著 4 個 RGBA 色彩值。

#define CUBE_INDICES 36
#define CUBE_VERTICES 8

GLfloat cubeVertsAndColors[] = 
{
  -0.5f, -0.5f,  0.5f, 0.0f, 0.0f, 1.0f, 1.0f,
  -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f,
  -0.5f,  0.5f,  0.5f, 0.0f, 1.0f, 1.0f, 1.0f,
  -0.5f,  0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f,
  0.5f, -0.5f,  0.5f, 1.0f, 0.0f, 1.0f, 1.0f,
  0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f,  
  0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 1.0f,
  0.5f,  0.5f, -0.5f, 1.0f, 1.0f, 0.0f, 1.0f
};

GLuint cubeIndices[] = 
{
  0, 1, 2, // -x
  1, 3, 2,

  4, 6, 5, // +x
  6, 7, 5,

  0, 5, 1, // -y
  5, 6, 1,

  2, 6, 3, // +y
  6, 7, 3,

  0, 4, 2, // +z
  4, 6, 2,

  1, 7, 3, // -z
  5, 7, 1
};

以下是 Direct3D 11 處理的相同立方體。

VertexPositionColor cubeVerticesAndColors[] = 
// struct format is position, color
{
  {XMFLOAT3(-0.5f, -0.5f, -0.5f), XMFLOAT3(0.0f, 0.0f, 0.0f)},
  {XMFLOAT3(-0.5f, -0.5f,  0.5f), XMFLOAT3(0.0f, 0.0f, 1.0f)},
  {XMFLOAT3(-0.5f,  0.5f, -0.5f), XMFLOAT3(0.0f, 1.0f, 0.0f)},
  {XMFLOAT3(-0.5f,  0.5f,  0.5f), XMFLOAT3(0.0f, 1.0f, 1.0f)},
  {XMFLOAT3( 0.5f, -0.5f, -0.5f), XMFLOAT3(1.0f, 0.0f, 0.0f)},
  {XMFLOAT3( 0.5f, -0.5f,  0.5f), XMFLOAT3(1.0f, 0.0f, 1.0f)},
  {XMFLOAT3( 0.5f,  0.5f, -0.5f), XMFLOAT3(1.0f, 1.0f, 0.0f)},
  {XMFLOAT3( 0.5f,  0.5f,  0.5f), XMFLOAT3(1.0f, 1.0f, 1.0f)},
};
        
unsigned short cubeIndices[] = 
{
  0, 2, 1, // -x
  1, 2, 3,

  4, 5, 6, // +x
  5, 7, 6,

  0, 1, 5, // -y
  0, 5, 4,

  2, 6, 7, // +y
  2, 7, 3,

  0, 4, 6, // -z
  0, 6, 2,

  1, 3, 7, // +z
  1, 7, 5
};

檢閱此程式碼時,您會注意到 OpenGL ES 2.0 程式碼中的立方體會以右側座標系統表示,而 Direct3D 特定程式碼中的立方體則以左側座標系統表示。 匯入您自己的網格資料時,您必須反轉模型的 z 軸座標,並據此變更每個網格的索引,根據座標系統中的變更來周遊三角形。

假設我們已成功將立方體網格從右側 OpenGL ES 2.0 座標系統移至左側 Direct3D 座標系統,讓我們看看如何載入立方體資料以在這兩個模型中進行處理。

指示

步驟 1:建立輸入配置

在OpenGL ES 2.0中,您的頂點資料做為屬性提供,這些屬性將提供給著色器物件並由著色器物件讀取。 通常,您會向著色器程式物件提供一個包含著色器 GLSL 中使用的屬性名稱的字串,並取得可提供給著色器的記憶體位置。 在此範例中,頂點緩衝區物件包含自訂頂點結構的清單,其定義和格式如下:

OpenGL ES 2.0:設定包含每個頂點資訊的屬性。

typedef struct 
{
  GLfloat pos[3];        
  GLfloat rgba[4];
} Vertex;

在 OpenGL ES 2.0 中,輸入配置是隱含的;您採用通用 GL_ELEMENT_ARRAY_BUFFER 並提供步距和位移,以便頂點著色器可以在上傳資料後解釋資料。 在轉譯之前,您可以使用 glVertexAttribPointer 通知著色器哪些屬性會對應到每個頂點資料塊的哪些部分。

在 Direct3D 中,您必須提供輸入配置,以描述在建立緩衝區時頂點緩衝區中的頂點資料結構,而不是在繪製幾何之前。 若要這樣做,您可以使用輸入配置,對應至記憶體中個別頂點的資料配置。 對此進行正確指定非常重要!

您在此將輸入描述建立為 D3D11_INPUT_ELEMENT_DESC 結構的陣列。

Direct3D:定義輸入配置描述。

struct VertexPositionColor
{
  DirectX::XMFLOAT3 pos;
  DirectX::XMFLOAT3 color;
};

// ...

const D3D11_INPUT_ELEMENT_DESC vertexDesc[] = 
{
  { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0,  D3D11_INPUT_PER_VERTEX_DATA, 0 },
  { "COLOR",    0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};

此輸入描述會將頂點定義為一對 2 個 3 座標向量:一個 3D 向量,以將頂點的位置儲存在模型座標中,另一個 3D 向量用來儲存與頂點相關聯的 RGB 色彩值。 在本案例中,您使用 3x32 位元浮點格式,我們在程式碼中將其元素表示為 XMFLOAT3(X.Xf, X.Xf, X.Xf)。 每當處理著色器將使用的資料時,都應該使用 DirectXMath 程式庫中的類型,因為它可以確保該資料的正確封裝和對齊。 (例如,對向量資料使用 XMFLOAT3XMFLOAT4,對矩陣使用 XMFLOAT4X4。)

如需所有可能格式類型的清單,請參閱 DXGI_FORMAT

定義每個頂點輸入配置後,您即可建立配置物件。 在下列程式碼中,將其寫入 m_inputLayout,即 ComPtr 類型的變數 (指向 ID3D11InputLayout 類型的物件)。 fileData 包含上一步驟移植著色器中編譯的頂點著色器物件。

Direct3D:建立頂點緩衝區所使用的輸入配置。

Microsoft::WRL::ComPtr<ID3D11InputLayout>      m_inputLayout;

// ...

m_d3dDevice->CreateInputLayout(
  vertexDesc,
  ARRAYSIZE(vertexDesc),
  fileData->Data,
  fileShaderData->Length,
  &m_inputLayout
);

我們已定義輸入配置。 現在,讓我們建立使用此版面配置的緩衝區,並將它載入立方體網格資料。

步驟 2:建立和載入頂點緩衝區

在OpenGL ES 2.0中,您會建立一組緩衝區,一個用於位置資料,另一個用於色彩資料。 (您也可以建立同時包含和單一緩衝區的結構。) 您可以將每個緩衝區繫結,並將位置和色彩資料寫入其中。 稍後,在轉譯函式期間,再次繫結緩衝區,並提供著色器與緩衝區中的資料格式,以便正確解譯它。

OpenGL ES 2.0:繫結頂點緩衝區

// upload the data for the vertex position buffer
glGenBuffers(1, &renderer->vertexBuffer);    
glBindBuffer(GL_ARRAY_BUFFER, renderer->vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(VERTEX) * CUBE_VERTICES, renderer->vertices, GL_STATIC_DRAW);   

在 Direct3D 中,著色器可存取的緩衝區會以 D3D11_SUBRESOURCE_DATA 結構表示。 若要將這個緩衝區的位置繫節到著色器物件,需要使用 ID3DDevice::CreateBuffer 為每個緩衝區建立一個CD3D11_BUFFER_DESC 結構,然後透過呼叫特定於緩衝區類型的設定方法來設定 Direct3D 裝置內容的緩衝區,例如 ID3DDeviceContext::IASetVertexBuffers

當您設定緩衝區時,必須從緩衝區開頭設定步距 (個別頂點的資料元素大小) 以及位移 (頂點資料陣列實際開始的位置)。

請注意,我們將指向 vertexIndices 陣列的指標指派給 D3D11_SUBRESOURCE_DATA 結構的 pSysMem 欄位。 如果不正確,您的網格將會損毀或空白!

Direct3D:建立和設定頂點緩衝區

D3D11_SUBRESOURCE_DATA vertexBufferData = {0};
vertexBufferData.pSysMem = cubeVertices;
vertexBufferData.SysMemPitch = 0;
vertexBufferData.SysMemSlicePitch = 0;
CD3D11_BUFFER_DESC vertexBufferDesc(sizeof(cubeVertices), D3D11_BIND_VERTEX_BUFFER);
        
m_d3dDevice->CreateBuffer(
  &vertexBufferDesc,
  &vertexBufferData,
  &m_vertexBuffer);
        
// ...

UINT stride = sizeof(VertexPositionColor);
UINT offset = 0;
m_d3dContext->IASetVertexBuffers(
  0,
  1,
  m_vertexBuffer.GetAddressOf(),
  &stride,
  &offset);

步驟 3:建立和載入索引緩衝區

索引緩衝區是讓頂點著色器查閱個別頂點的有效方式。 雖然它們並非必要,但我們在此範例轉譯器中使用它們。 如同 OpenGL ES 2.0 中的頂點緩衝區,索引緩衝區會建立並繫結為一般用途緩衝區,而您稍早建立的頂點索引會複製到其中。

當您準備好繪製時,請再次繫結頂點和索引緩衝區,並呼叫 glDrawElements

OpenGL ES 2.0:將索引順序傳送至繪製呼叫。

GLuint indexBuffer;

// ...

glGenBuffers(1, &renderer->indexBuffer);    
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, renderer->indexBuffer);   
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 
  sizeof(GLuint) * CUBE_INDICES, 
  renderer->vertexIndices, 
  GL_STATIC_DRAW);

// ...
// Drawing function

// Bind the index buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, renderer->indexBuffer);
glDrawElements (GL_TRIANGLES, renderer->numIndices, GL_UNSIGNED_INT, 0);

對於 Direct3D,它的程序有點非常相似,儘管更具說教性。 將索引緩衝區做為 Direct3D 子資源提供給您在設定 Direct3D 時建立的 ID3D11DeviceContext。 您可以透過使用為索引陣列配置的子資源呼叫 ID3D11DeviceContext::IASetIndexBuffer 來完成此操作,如下所示。 (再次注意,您將指向 cubeIndices 陣列的指標指派給了D3D11_SUBRESOURCE_DATA 結構的 pSysMem 欄位。)

Direct3D:建立索引緩衝區。

m_indexCount = ARRAYSIZE(cubeIndices);

D3D11_SUBRESOURCE_DATA indexBufferData = {0};
indexBufferData.pSysMem = cubeIndices;
indexBufferData.SysMemPitch = 0;
indexBufferData.SysMemSlicePitch = 0;
CD3D11_BUFFER_DESC indexBufferDesc(sizeof(cubeIndices), D3D11_BIND_INDEX_BUFFER);

m_d3dDevice->CreateBuffer(
  &indexBufferDesc,
  &indexBufferData,
  &m_indexBuffer);

// ...

m_d3dContext->IASetIndexBuffer(
  m_indexBuffer.Get(),
  DXGI_FORMAT_R16_UINT,
  0);

稍後,您將透過呼叫 ID3D11DeviceContext::DrawIndexed (或 ID3D11DeviceContext::Draw 對於未索引的頂點) 來繪製三角形,如下所示。 (如需詳細資訊,請跳到繪製到畫面。)

Direct3D:繪製索引頂點。

m_d3dContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_d3dContext->IASetInputLayout(m_inputLayout.Get());

// ...

m_d3dContext->DrawIndexed(
  m_indexCount,
  0,
  0);

上一步

移植著色器物件

後續步驟

移植 GLSL

備註

建構 Direct3D 時,請將呼叫 ID3D11Device 上的方法的程式碼分離到需要重新建立裝置資源時呼叫的方法。 (在 Direct3D 專案範本中,此程式碼位於轉譯器物件的 CreateDeviceResource 方法中。 另一方面,更新裝置內容 (ID3D11DeviceContext) 的程式碼則放置在 Render 方法中,因為這是您實際建立著色器階段並繫結資料的地方。