Share via


(Direct3D 10) 建立紋理資源

紋理資源是結構化的資料集合。 一般而言,色彩值會儲存在紋理中,並由 管線 在輸入和輸出的各種階段進行轉譯期間存取。 在 Direct3D 10 中,建立紋理並定義其使用方式,是轉譯有趣外觀場景的重要部分。

即使紋理通常包含色彩資訊,但使用不同的 DXGI_FORMAT 建立紋理可讓他們儲存不同類型的資料。 然後,Direct3D 10 管線可以使用非傳統方式來利用這項資料。

所有紋理都有其耗用多少記憶體,以及其包含多少紋素的限制。 這些限制是由 資源常數所指定。

從檔案建立紋理

注意

D3DX 公用程式程式庫已被取代為 Windows 8,且不支援 Windows 市集應用程式。

 

當您在 Direct3D 10 中建立紋理時,也需要建立 檢視。 檢視是物件,告知裝置在轉譯期間應如何存取紋理。 存取紋理最常見的方式是使用 著色器從紋理中讀取。 著色器資源檢視會告訴著色器如何在轉譯期間從紋理讀取。 當您建立紋理時,必須使用的檢視類型。

建立紋理並載入其初始資料的方式有兩種不同的方式:分別建立紋理和檢視,或同時建立紋理和檢視。 API 提供這兩種技術,讓您可以選擇更符合您的需求。

個別建立紋理和檢視

建立紋理最簡單的方式是從影像檔載入它。 若要建立紋理,只要填入一個結構,並將紋理的名稱提供給 D3DX10CreateTextureFromFile

ID3D10Device *pDevice = NULL;
// Initialize D3D10 device...

D3DX10_IMAGE_LOAD_INFO loadInfo;
ZeroMemory( &loadInfo, sizeof(D3DX10_IMAGE_LOAD_INFO) );
loadInfo.BindFlags = D3D10_BIND_SHADER_RESOURCE;

ID3D10Resource *pTexture = NULL;
D3DX10CreateTextureFromFile( pDevice, L"sample.bmp", &loadInfo, NULL, &pTexture, NULL );

D3DX 函式 D3DX10CreateTextureFromFile會執行三件事:首先,它會建立 Direct3D 10 紋理物件;第二,它會讀取輸入影像檔;第三,它會將影像資料儲存在紋理物件中。 在上述範例中,會載入 BMP 檔案,但函式可以載入各種檔案類型。

系結旗標表示紋理會建立為著色器資源,讓著色器階段能夠在轉譯期間從紋理讀取。

上述範例未指定所有載入參數。 事實上,只要將載入參數零出,通常很有説明,因為這可讓 D3DX 根據輸入影像選擇適當的值。 如果您想要讓輸入影像判斷紋理所建立的所有參數,只要為loadInfo參數指定Null,如下所示:

D3DX10CreateTextureFromFile( pDevice, L"sample.bmp", NULL, NULL, &pTexture, NULL );

為載入資訊指定 Null 是簡單但功能強大的快捷方式。

現在已建立紋理,您必須建立著色器資源檢視,讓紋理可以系結為著色器的輸入。 由於 D3DX10CreateTextureFromFile 會傳回資源的指標,而不是紋理的指標,因此您必須判斷載入的確切資源類型,然後使用 CreateShaderResourceView建立著色器資源檢視。

D3D10_SHADER_RESOURCE_VIEW_DESC srvDesc;
D3D10_RESOURCE_DIMENSION type;
pTexture->GetType( &type );
switch( type )
{
    case D3D10_RESOURCE_DIMENSION_BUFFER:
    //...
    break;
    case D3D10_RESOURCE_DIMENSION_TEXTURE1D:
    //...
    break;
    case D3D10_RESOURCE_DIMENSION_TEXTURE2D:
    {
        D3D10_TEXTURE2D_DESC desc;
        ID3D10Texture2D *pTexture2D = (ID3D10Texture2D*)pTexture;
        pTexture2D->GetDesc( &desc );
        
        srvDesc.Format = desc.Format;
        srvDesc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
        srvDesc.Texture2D.MipLevels = desc.MipLevels;
        srvDesc.Texture2D.MostDetailedMip = desc.MipLevels -1;

    }
    break;
    case D3D10_RESOURCE_DIMENSION_TEXTURE3D:
    //...
    break;
    default:
    //...
    break;
}

ID3D10ShaderResourceView *pSRView = NULL;
pDevice->CreateShaderResourceView( pTexture, &srvDesc, &pSRView );

雖然上述範例會建立 2D 著色器資源檢視,但建立其他著色器資源檢視類型的程式碼非常類似。 任何著色器階段現在都可以使用此紋理做為輸入。

使用 D3DX10CreateTextureFromFileCreateShaderResourceView 來建立紋理及其相關聯的檢視,是準備要系結至著色器階段之紋理的其中一種方式。 另一個做法是同時建立紋理及其檢視,在下一節中討論。

同時建立紋理和檢視

Direct3D 10 需要紋理和著色器資源檢視,才能在執行時間從紋理讀取。 由於建立紋理和著色器資源檢視是這類常見的工作, D3DX 會提供 D3DX10CreateShaderResourceViewFromFile 來為您執行此動作。

D3DX10_IMAGE_LOAD_INFO loadInfo;
ZeroMemory( &loadInfo, sizeof(D3DX10_IMAGE_LOAD_INFO) );
loadInfo.BindFlags = D3D10_BIND_SHADER_RESOURCE;
loadInfo.Format = DXGI_FORMAT_BC1_UNORM;

ID3D10ShaderResourceView *pSRView = NULL;
D3DX10CreateShaderResourceViewFromFile( pDevice, L"sample.bmp", &loadInfo, NULL, &pSRView, NULL );

使用單一 D3DX 呼叫時,會建立紋理和著色器資源檢視。 loadInfo參數的功能保持不變;您可以使用它來自訂紋理的建立方式,或藉由指定loadInfo參數的Null,從輸入檔衍生必要的參數。

D3DX10CreateShaderResourceViewFromFile函式傳回的ID3D10ShaderResourceView物件稍後可用來擷取原始ID3D10Resource介面。 這可以藉由呼叫 GetResource 方法來完成。

D3DX 提供單一函式,以建立紋理和著色器資源檢視作為 convienience;您可以決定建立紋理並檢視哪一種方法最符合應用程式的需求。

既然您已瞭解如何建立紋理及其著色器資源檢視,下一節將說明如何使用著色器從該紋理讀取) (範例。

建立空白紋理

有時候,應用程式會想要建立紋理,並計算要儲存在紋理中的資料,或使用圖形 管線 來轉譯至此紋理,稍後再使用其他處理的結果。 圖形管線或應用程式本身可以更新這些紋理,視建立紋理時所指定的 使用量 類型而定。

轉譯為紋理

在執行時間期間建立要填入資料的空紋理最常見的案例,就是應用程式想要轉譯為紋理,然後在後續階段中使用轉譯作業的結果。 使用此用途建立的紋理應該指定預設 使用方式

下列程式碼範例會建立空紋理,讓管線可以轉譯為著色器的輸入,並後續用來做為 著色器的輸入。

// Create the render target texture
D3D10_TEXTURE2D_DESC desc;
ZeroMemory( &desc, sizeof(desc) );
desc.Width = 256;
desc.Height = 256;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
desc.SampleDesc.Count = 1;
desc.Usage = D3D10_USAGE_DEFAULT;
desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;

ID3D10Texture2D *pRenderTarget = NULL;
pDevice->CreateTexture2D( &desc, NULL, &pRenderTarget );

建立紋理需要應用程式指定紋理將擁有之屬性的一些資訊。 材質中紋理的寬度和高度會設定為 256。 針對此轉譯目標,我們只需要單一 Mipmap 層級。 只需要一個轉譯目標,陣列大小才會設定為 1。 每個材質都包含四個 32 位浮點值,可用來儲存非常精確的資訊, (請參閱 DXGI_FORMAT) 。 每個圖元有一個範例,就是需要的所有範例。 使用量會設定為預設值,因為這允許在記憶體中放置最有效率的轉譯目標。 最後,會指定紋理系結為轉譯目標,並指定不同時間點的著色器資源。

無法系結紋理以直接轉譯至管線;使用轉譯目標檢視,如下列程式碼範例所示。

D3D10_RENDER_TARGET_VIEW_DESC rtDesc;
rtDesc.Format = desc.Format;
rtDesc.ViewDimension = D3D10_RTV_DIMENSION_TEXTURE2D;
rtDesc.Texture2D.MipSlice = 0;

ID3D10RenderTargetView *pRenderTargetView = NULL;
pDevice->CreateRenderTargetView( pRenderTarget, &rtDesc, &pRenderTargetView );

轉譯目標檢視的格式只會設定為原始紋理的格式。 資源中的資訊應該解譯為 2D 紋理,而我們只想要使用轉譯目標的第一個 Mipmap 層級。

類似于必須建立轉譯目標檢視的方式,讓轉譯目標可以系結至管線輸出,因此必須建立著色器資源檢視,才能將轉譯目標系結至管線做為輸入。 下列程式碼範例示範這一點。

// Create the shader-resource view
D3D10_SHADER_RESOURCE_VIEW_DESC srDesc;
srDesc.Format = desc.Format;
srDesc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
srDesc.Texture2D.MostDetailedMip = 0;
srDesc.Texture2D.MipLevels = 1;

ID3D10ShaderResourceView *pShaderResView = NULL;
pDevice->CreateShaderResourceView( pRenderTarget, &srDesc, &pShaderResView );

著色器資源檢視描述的參數與轉譯目標檢視描述的參數非常類似,而且基於相同原因而選擇。

手動填滿紋理

有時候應用程式想要在執行時間計算值、手動將它們放入紋理中,然後讓圖形 管線 在稍後的轉譯作業中使用此紋理。 若要這樣做,應用程式必須以這樣的方式建立空紋理,以允許 CPU 存取基礎記憶體。 做法是建立動態紋理,並藉由呼叫特定方法來存取基礎記憶體。 下列程式碼範例示範如何執行這項操作。

D3D10_TEXTURE2D_DESC desc;
desc.Width = 256;
desc.Height = 256;
desc.MipLevels = desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.Usage = D3D10_USAGE_DYNAMIC;
desc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
ID3D10Texture2D *pTexture = NULL;
pd3dDevice->CreateTexture2D( &desc, NULL, &pTexture );

請注意,格式會設定為每個圖元 32 位,其中每個元件都是由 8 位定義。 使用方式參數設定為動態,而系結旗標設定為指定著色器會存取紋理。 紋理描述的其餘部分類似于建立轉譯目標。

呼叫 Map 可讓應用程式存取紋理的基礎記憶體。 然後,擷取的指標會用來填滿紋理資料。 這可以在下列程式碼範例中看到。

D3D10_MAPPED_TEXTURE2D mappedTex;
pTexture->Map( D3D10CalcSubresource(0, 0, 1), D3D10_MAP_WRITE_DISCARD, 0, &mappedTex );

UCHAR* pTexels = (UCHAR*)mappedTex.pData;
for( UINT row = 0; row < desc.Height; row++ )
{
    UINT rowStart = row * mappedTex.RowPitch;
    for( UINT col = 0; col < desc.Width; col++ )
    {
        UINT colStart = col * 4;
        pTexels[rowStart + colStart + 0] = 255; // Red
        pTexels[rowStart + colStart + 1] = 128; // Green
        pTexels[rowStart + colStart + 2] = 64;  // Blue
        pTexels[rowStart + colStart + 3] = 32;  // Alpha
    }
}

pTexture->Unmap( D3D10CalcSubresource(0, 0, 1) );

多個轉譯目標

最多八個轉譯目標檢視可以一次系結至管線, (OMSetRenderTargets) 。 如果啟用多重取樣) ,則針對每個圖元 (或每個樣本,會針對每個轉譯目標檢視獨立完成混合。 BlendEnable 和 RenderTargetWriteMask 的兩個混合狀態變數是八個數組,每個陣列成員都會對應至轉譯目標檢視。 使用多個轉譯目標時,每個轉譯目標都必須是相同的 資源類型 (緩衝區、1D 紋理、2D 紋理陣列等) ,而且必須有相同的維度 (寬度、高度、3D 紋理的深度,以及紋理陣列的陣列大小) 。 如果轉譯目標是多重取樣,則每個圖元的樣本數目必須相同。

不論作用中的轉譯目標數目為何,都只能有一個深度樣板緩衝區作用中。 使用紋理陣列作為轉譯目標時,所有檢視維度都必須相符。 轉譯目標不需要具有相同的紋理格式。

(Direct3D 10)