Direct3D 11 Tutorial 2: Rendering a Triangle_Direct3D 11 教程2:渲染一個三角形

來源:互聯網
上載者:User

標籤:otc   int   oat   自動   資料類型   語義   wrap   有一個   執行   

概要

在之前的教程中,我們建立了一個最小的Direct3D 11的應用程式,它用來在視窗上輸出一個單一顏色。在本次教程中,我們將擴充這個應用程式,在螢幕上渲染出一個單一顏色的三角形。我們將通過設定資料機構的過程關聯到三角形。

這個教程的輸出結果是在視窗中央渲染出一個三角形。

 

資來源目錄

(SDK root)\Samples\C++\Direct3D11\Tutorials\Tutorial02

Github-LearnDirectX-DX3D11 tutorial02 (源碼已上傳至Github)

 

三角形的元素

三角形由其三個點定義,也稱為頂點。 具有唯一位置的一組三個頂點定義了唯一的三角形。 為了讓GPU渲染三角形,我們必須告訴它三角形的三個頂點的位置。舉一個2D的例子,假設我們希望渲染一個三角形,例1中的三角形。我們將三個頂點與位置(0,0)(0,1)和(1,0)一起傳遞給GPU,然後 GPU有足夠的資訊來渲染我們想要的三角形。

圖1.由三個頂點定義的2D三角形

所以現在我們知道我們必須將三個位置傳遞給GPU才能渲染三角形。 我們如何將這些資訊傳遞給GPU? 在Direct3D 11中,諸如位置的頂點資訊儲存在緩衝區資源中。 用於儲存頂點資訊的緩衝區被稱為頂點緩衝區,這並不奇怪。 我們必須為三個頂點建立一個足夠大的頂點緩衝區,並用頂點位置填充它。 在Direct3D 11中,應用程式必須在建立緩衝區資源時指定緩衝區大小(以位元組為單位)。 我們知道緩衝區必須足夠大才能容納三個頂點,但每個頂點需要多少位元組? 要回答這個問題,需要瞭解頂點布局。

 

輸入布局

頂點有一個位置。 通常,它還具有其他屬性,例如法線,一種或多種顏色,紋理座標(用於紋理映射)等。 頂點布局定義了這些屬性在記憶體中的位置:每個屬性使用的資料類型,每個屬性的大小以及記憶體中屬性的順序。 因為屬性通常具有不同的類型,類似於C結構中的欄位,所以頂點通常由結構表示。 頂點的大小可以方便地從結構的大小中獲得。

在本教程中,我們只處理頂點的位置。 因此,我們使用XMFLOAT3類型的單個欄位定義頂點結構。 此類型是三個浮點組件的向量,通常是用於3D位置的資料類型。

struct SimpleVertex{    XMFLOAT3 Pos;  // Position};

  

我們現在有一個表示我們的頂點的結構。 它負責在我們的應用程式中將頂點資訊儲存在系統記憶體中。 然而,當我們向GPU提供包含頂點的頂點緩衝區時,我們只是給它一塊記憶體。 GPU還必須知道頂點布局,以便從緩衝區中提取正確的屬性。 要實現此目的,需要使用輸入布局。

在Direct3D 11中,輸入布局是Direct3D對象,它以GPU可以理解的方式描述頂點的結構。 可以使用D3D11_INPUT_ELEMENT_DESC結構描述每個頂點屬性。 應用程式定義一個或多個D3D11_INPUT_ELEMENT_DESC的數組,然後使用該數組建立輸入布局對象,該對象將頂點描述為一個整體。 現在我們將詳細介紹D3D11_INPUT_ELEMENT_DESC的欄位。

SemanticName

SemanticName是一個字串,其中包含描述此元素的性質或目的(或語義)的單詞。 這個詞可以是C標識符可以的任何形式,也可以是我們選擇的任何形式。 例如,頂點位置的良好語義名稱是POSITION。 語義名稱不區分大小寫。

SemanticIndex

SemanticIndex補充了語義名稱。 頂點可以具有相同性質的多個屬性。 例如,它可以具有2組紋理座標或2組顏色。 不是使用附加了數位語義名稱,例如“COLOR0”和“COLOR1”,這兩個元素可以共用單個語義名稱“COLOR”,具有不同的語義索引0和1。

Format

格式定義要用於此元素的資料類型。 例如,DXGI_FORMAT_R32G32B32_FLOAT的格式有三個32位浮點數,使元素長12個位元組。 DXGI_FORMAT_R16G16B16A16_UINT的格式有四個16位不帶正負號的整數,使元素長8個位元組。

InputSlot

如前所述,Direct3D 11應用程式通過使用頂點緩衝區將頂點資料傳遞給GPU。 在Direct3D 11中,可以同時向GPU提供多個頂點緩衝區,準確地說是16。 每個頂點緩衝區都綁定到0到15之間的輸入槽號.InputSlot欄位告訴GPU它應該為該元素擷取哪個頂點緩衝區。

AlignedByteOffset

頂點儲存在頂點緩衝區中,頂層緩衝區只是一塊記憶體。 AlignedByteOffset欄位告訴GPU開始擷取此元素資料的記憶體位置。

InputSlotClass

該欄位的值通常為D3D11_INPUT_PER_VERTEX_DATA。 當應用程式使用執行個體化時,它可以將輸入布局的InputSlotClass設定為D3D11_INPUT_PER_INSTANCE_DATA以使用包含執行個體資料的頂點緩衝區。 Instancing是一個進階的Direct3D主題,這裡不再討論。 對於我們的教程,我們將專門使用D3D11_INPUT_PER_VERTEX_DATA。

InstanceDataStepRate

該欄位用於執行個體化。 由於我們不使用執行個體化,因此不使用此欄位,必須將其設定為0。

現在我們可以定義D3D11_INPUT_ELEMENT_DESC數組並建立輸入布局:

// Define the input layoutD3D11_INPUT_ELEMENT_DESC layout[] ={    { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },  };UINT numElements = ARRAYSIZE(layout);

  

頂點布局

在下一個教程中,我們將解釋技術對象和關聯的著色器。 目前,我們將專註於為該技術建立Direct3D 11頂點布局對象。 但是,我們將瞭解頂點著色器與此頂點布局緊密耦合。 原因是建立頂點布局對象需要頂點著色器的輸入簽名。 我們使用從D3DX11CompileFromFile返回的ID3DBlob對象來檢索表示頂點著色器的輸入簽名的位元據。 獲得此資料後,我們可以調用ID3D11Device :: CreateInputLayout()來建立頂點布局對象,並使用ID3D11DeviceContext :: IASetInputLayout()將其設定為活動頂點布局。 完成所有這些操作的代碼如下所示:

// Create the input layoutif( FAILED( g_pd3dDevice->CreateInputLayout( layout, numElements, pVSBlob->GetBufferPointer(),         pVSBlob->GetBufferSize(), &g_pVertexLayout ) ) )    return FALSE;// Set the input layoutg_pImmediateContext->IASetInputLayout( g_pVertexLayout );

  

建立頂點緩衝區

在初始化期間我們還需要做的一件事是建立儲存頂點資料的頂點緩衝區。 要在Direct3D 11中建立頂點緩衝區,我們填寫兩個結構D3D11_BUFFER_DESC和D3D11_SUBRESOURCE_DATA,然後調用ID3D11Device :: CreateBuffer()。

D3D11_BUFFER_DESC描述了要建立的頂點緩衝區對象,D3D11_SUBRESOURCE_DATA描述了在建立過程中將複製到頂點緩衝區的實際資料。 頂點緩衝區的建立和初始化是一次完成的,因此我們以後不需要初始化緩衝區。 將複製到頂點緩衝區的資料是頂點,即三個簡單結構的數組。 選擇頂點數組中的座標,以便在使用著色器渲染時在應用程式視窗的中間看到一個三角形。 建立頂點緩衝區後,我們可以調用ID3D11DeviceContext :: IASetVertexBuffers()將其綁定到裝置。 完整的代碼如下所示:

// Create vertex bufferSimpleVertex vertices[] ={    XMFLOAT3( 0.0f, 0.5f, 0.5f ),    XMFLOAT3( 0.5f, -0.5f, 0.5f ),    XMFLOAT3( -0.5f, -0.5f, 0.5f ),};D3D11_BUFFER_DESC bd;ZeroMemory( &bd, sizeof(bd) );bd.Usage = D3D11_USAGE_DEFAULT;bd.ByteWidth = sizeof( SimpleVertex ) * 3;bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;bd.CPUAccessFlags = 0;bd.MiscFlags = 0;D3D11_SUBRESOURCE_DATA InitData; ZeroMemory( &InitData, sizeof(InitData) );InitData.pSysMem = vertices;if( FAILED( g_pd3dDevice->CreateBuffer( &bd, &InitData, &g_pVertexBuffer ) ) )    return FALSE;// Set vertex bufferUINT stride = sizeof( SimpleVertex );UINT offset = 0;g_pImmediateContext->IASetVertexBuffers( 0, 1, &g_pVertexBuffer, &stride, &offset );

  

原始拓撲

原始拓撲是指GPU如何獲得渲染三角形所需的三個頂點。 我們在上面討論過,為了渲染單個三角形,應用程式需要向GPU發送三個頂點。 因此,頂點緩衝區中有三個頂點。 如果我們想渲染兩個三角形怎麼辦? 一種方法是將6個頂點發送到GPU。 前三個頂點定義第一個三角形,後三個頂點定義第二個三角形。 此拓撲稱為三角形列表。 三角形列表具有易於理解的優點,但在某些情況下它們效率非常低。 當連續渲染的三角形共用頂點時會出現這種情況。 例如,圖3a左側顯示了由兩個三角形組成的正方形:ABC和CB D.(按照慣例,三角形通常通過按順時針順序列出它們的頂點來定義。)如果我們使用三角形列表將這兩個三角形發送到GPU ,我們的頂點緩衝區會這樣:

A B C C B D

請注意,B和C在頂點緩衝區中出現兩次,因為它們由兩個三角形共用。

圖3a包含一個由兩個三角形組成的正方形; 圖3b包含由三個三角形組成的五邊形。

如果我們可以告訴GPU在渲染第二個三角形時,我們可以使頂點緩衝區更小,而不是從頂點緩衝區擷取所有三個頂點,使用前一個三角形中的2個頂點,並從頂點緩衝區中僅擷取1個頂點。 事實證明,這是由Direct3D支援的,拓撲結構稱為三角形條帶。 渲染三角形條帶時,第一個三角形由頂點緩衝區中的前三個頂點定義。 下一個三角形由前一個三角形的最後兩個頂點加上頂點緩衝區中的下一個頂點定義。 以圖3a中的方塊為例,使用三角形條帶,頂點緩衝區看起來像:

A B C D

前三個頂點A B C定義第一個三角形。 第二個三角形由B和C定義,即第一個三角形的最後兩個頂點加上D.因此,通過使用三角形條帶拓撲,頂點緩衝區大小從6個頂點變為4個頂點。 類似地,對於三個三角形,例3b中的三角形,使用三角形列表將需要頂點緩衝區,例如:

A B C C B D C D E

使用三角形條帶,頂點緩衝區的大小顯著減少:

A B C D E
你可能已經注意到,在三角形條帶樣本中,第二個三角形定義為B C D.這三個頂點不形成順時針順序。 這是使用三角形條帶的自然現象。 為了克服這個問題,GPU會自動交換來自前一個三角形的兩個頂點的順序。 它只對第二個三角形,第四個三角形,第六個三角形,第八個三角形等執行此操作。 這確保每個三角形由頂點以正確的纏繞順序(在這種情況下為順時針方向)定義。 除了三角形列表和三角形條帶外,Direct3D 11還支援許多其他類型的原始拓撲。 我們不會在本教程中討論它們。

在我們的代碼中,我們有一個三角形,所以我們指定的並不重要。 但是,我們必須指定一些內容,因此我們選擇了三角形列表。

// Set primitive topologyg_pImmediateContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );

  

渲染三角形

缺少的最後一項是執行三角形實際渲染的代碼。我們建立了兩個用於渲染的著色器,頂點著色器和像素著色器。頂點著色器負責將三角形的各個頂點轉換為正確的位置。像素著色器負責計算三角形的每個像素的最終輸出顏色。這將在下一個教程中詳細介紹。要使用這些著色器,我們必須分別調用ID3D11DeviceContext :: VSSetShader()和ID3D11DeviceContext :: PSSetShader()。我們做的最後一件事是調用ID3D11DeviceContext :: Draw(),它命令GPU使用當前頂點緩衝區,頂點布局和原始拓撲進行渲染。 Draw()的第一個參數是要發送到GPU的頂點數,第二個參數是要開始發送的第一個頂點的索引。因為我們渲染一個三角形並且我們從頂點緩衝區的開頭渲染,所以我們分別使用3和0作為兩個參數。整個三角形渲染代碼如下所示:

// Render a triangle g_pImmediateContext->VSSetShader( g_pVertexShader, NULL, 0 );g_pImmediateContext->PSSetShader( g_pPixelShader, NULL, 0 );g_pImmediateContext->Draw( 3, 0 );

  

 

Direct3D 11 Tutorial 2: Rendering a Triangle_Direct3D 11 教程2:渲染一個三角形

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.