Condividi tramite


Creazione di risorse texture (Direct3D 10)

Una risorsa di texture è una raccolta strutturata di dati. In genere, i valori di colore vengono archiviati in trame e accessibili durante il rendering dalla pipeline in varie fasi sia per l'input che per l'output. La creazione di trame e la definizione di come verranno usate è una parte importante del rendering di scene interessanti in Direct3D 10.

Anche se le trame in genere contengono informazioni sul colore, la creazione di trame che usano DXGI_FORMAT diverse consente di archiviare tipi diversi di dati. Questi dati possono quindi essere sfruttati dalla pipeline Direct3D 10 in modi non tradizionali.

Tutte le trame hanno limiti sulla quantità di memoria usata e sul numero di texel che contengono. Questi limiti vengono specificati dalle costanti delle risorse .

Creare una trama da un file

Nota

La libreria di utilità D3DX è deprecata per Windows 8 e non è supportata per le app di Windows Store.

 

Quando crei una trama in Direct3D 10, è necessario creare anche una visualizzazione . Una visualizzazione è un oggetto che indica al dispositivo come accedere a una trama durante il rendering. Il modo più comune per accedere a una trama consiste nel leggerlo usando un shader. Una vista delle risorse shader dirà a uno shader come leggere da una texture durante il rendering. Il tipo di visualizzazione che verrà usata da una trama deve essere specificato al momento della creazione.

La creazione di una trama e il caricamento dei dati iniziali possono essere eseguite in due modi diversi: creare una trama e una visualizzazione separatamente oppure creare sia la trama che la visualizzazione contemporaneamente. L'API fornisce entrambe le tecniche in modo da poter scegliere le più adatte alle proprie esigenze.

Creare trama e visualizzazione separatamente

Il modo più semplice per creare una trama consiste nel caricarlo da un file di immagine. Per creare la trama, è sufficiente compilare una struttura e specificare il nome della trama per 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 );

La funzione D3DX D3DX10CreateTextureFromFile esegue tre operazioni: prima crea un oggetto trama Direct3D 10; in secondo luogo, legge il file di immagine di input; terzo, archivia i dati dell'immagine nell'oggetto trama. Nell'esempio precedente viene caricato un file BMP, ma la funzione può caricare un'ampia gamma di tipi di file.

Il flag di bind indica che la texture verrà creata come risorsa per shader che consente a uno stadio dello shader di accedere alla texture durante il rendering.

Nell'esempio precedente non vengono specificati tutti i parametri di caricamento. In effetti, spesso è utile evitare semplicemente i parametri di caricamento, in quanto ciò consente a D3DX di scegliere i valori appropriati in base all'immagine di input. Se si vuole che l'immagine di input determini tutti i parametri con cui viene creata la trama, è sufficiente specificare NULL per il parametro loadInfo simile al seguente:

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

Specificare NULL per le informazioni di caricamento è un collegamento semplice ma potente.

Ora che è stata creata una trama, è necessario creare una visualizzazione shader-resource in modo che la trama possa essere associata come input a uno shader. Poiché D3DX10CreateTextureFromFile restituisce un puntatore a una risorsa e non un puntatore a una trama, è necessario determinare il tipo esatto di risorsa caricato e quindi è possibile creare una visualizzazione shader-resource usando 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 );

Anche se l'esempio precedente crea una visualizzazione risorsa shader 2D, il codice per creare altri tipi di visualizzazione delle risorse shader è molto simile. Qualsiasi fase dello shader può ora usare questa trama come input.

L'uso di D3DX10CreateTextureFromFile e CreateShaderResourceView per creare una trama e la visualizzazione associata è un modo per preparare una trama da associare a una fase dello shader. Un altro modo per eseguire questa operazione consiste nel creare sia la trama che la relativa visualizzazione contemporaneamente, come illustrato nella sezione successiva.

Creare contemporaneamente trama e visualizzazione

Direct3D 10 richiede sia una texture che una vista risorsa shader per la lettura di una texture durante l'esecuzione. Poiché la creazione di una trama e una visualizzazione delle risorse shader è un'attività così comune, D3DX fornisce il D3DX10CreateShaderResourceViewFromFile per farlo automaticamente.

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 );

Con una singola chiamata D3DX, vengono create sia la trama che la visualizzazione delle risorse shader. La funzionalità del parametro loadInfo è invariata; è possibile usarlo per personalizzare la modalità di creazione della trama o derivare i parametri necessari dal file di input specificando NULL per il parametro loadInfo.

L'oggetto ID3D10ShaderResourceView restituito dall'D3DX10CreateShaderResourceViewFromFile funzione può essere usata successivamente per recuperare l'interfaccia originale ID3D10Resource, se necessario. Questo può essere fatto chiamando il metodo GetResource.

D3DX fornisce una funzione singola per creare una texture e una visualizzazione delle risorse dello shader come comodità; spetta a te decidere quale metodo di creazione di una texture e di visualizzazione si adatti meglio alle esigenze della tua applicazione.

Dopo aver appreso come creare una trama e la relativa visualizzazione shader-resource, la sezione successiva illustra come è possibile campionare (leggere) da tale trama usando uno shader.

Creazione di trame vuote

A volte le applicazioni vogliono creare una trama e calcolare i dati da archiviare nella trama oppure usare la grafica pipeline per eseguire il rendering in questa trama e successivamente usare i risultati in altre elaborazioni. Queste trame possono essere aggiornate dalla pipeline grafica o dall'applicazione stessa, a seconda del tipo di utilizzo specificato al momento della creazione della trama.

Rendering su una texture

Il caso più comune della creazione di una trama vuota da riempire con i dati durante il runtime è il caso in cui un'applicazione vuole eseguire il rendering in una trama e quindi usare i risultati dell'operazione di rendering in un passaggio successivo. Le trame create con questo scopo devono specificare l'utilizzo predefinito.

L'esempio di codice seguente crea una trama vuota in cui la pipeline può eseguire il rendering e successivamente usarla come input per un shader.

// 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 );

Per creare la trama è necessario che l'applicazione specifichi alcune informazioni sulle proprietà di cui avrà la trama. La larghezza e l'altezza della trama in texel sono impostate su 256. Per questa destinazione di rendering, è sufficiente un singolo livello mipmap. È necessaria una sola destinazione di rendering in modo che le dimensioni della matrice siano impostate su 1. Ogni texel contiene quattro valori a virgola mobile a 32 bit, che possono essere usati per archiviare informazioni molto precise (vedere DXGI_FORMAT). Un campione per pixel è tutto ciò che sarà necessario. L'utilizzo è impostato sul valore predefinito perché consente il posizionamento più efficiente della destinazione di rendering in memoria. Infine, viene specificato che la trama verrà associata come destinazione di rendering e come risorsa shader in momenti diversi.

Non è possibile associare le trame per il rendering direttamente alla pipeline; usare una visualizzazione di destinazione di rendering come illustrato nell'esempio di codice seguente.

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 );

Il formato della vista di destinazione del rendering è semplicemente impostato sul formato della texture originale. Le informazioni nella risorsa devono essere interpretate come trama 2D e si vuole usare solo il primo livello mipmap della destinazione di rendering.

Analogamente alla modalità di creazione di una visualizzazione di destinazione di rendering in modo che la destinazione di rendering possa essere associata per l'output alla pipeline, è necessario creare una vista shader-resource in modo che la destinazione di rendering possa essere associata alla pipeline come input. L'esempio di codice seguente illustra questa operazione.

// 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 );

I parametri delle descrizioni delle viste risorsa shader sono molto simili a quelli delle viste bersaglio di rendering e sono stati scelti per gli stessi motivi.

Riempimento manuale delle texture

In alcuni casi le applicazioni vogliono calcolare i valori in fase di esecuzione, inserirle manualmente in una trama e quindi disporre della pipeline grafica usare questa trama nelle operazioni di rendering successive. A tale scopo, l'applicazione deve creare una trama vuota in modo da consentire alla CPU di accedere alla memoria sottostante. Questa operazione viene eseguita creando una trama dinamica e ottenendo l'accesso alla memoria sottostante chiamando un metodo specifico. Nell'esempio di codice seguente viene illustrato come eseguire questa operazione.

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 );

Si noti che il formato è impostato su 32 bit per pixel in cui ogni componente è definito da 8 bit. Il parametro di utilizzo è impostato su dinamico mentre i flag di associazione sono impostati per specificare che la trama sarà accessibile da uno shader. Il resto della descrizione della texture è simile alla creazione di un target di rendering.

L'invocazione Map consente all'applicazione di accedere alla memoria sottostante della texture. Il puntatore recuperato viene quindi usato per riempire la trama con i dati. Questo può essere visualizzato nell'esempio di codice seguente.

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) );

Più destinazioni di rendering

Fino a otto viste delle destinazioni di rendering possono essere associate alla pipeline contemporaneamente (con OMSetRenderTargets). Per ogni pixel (o ogni campione se è abilitato il multicampionamento), la fusione viene eseguita in modo indipendente per ogni visualizzazione di destinazione di rendering. Due delle variabili di stato del blend, BlendEnable e RenderTargetWriteMask, sono matrici con otto elementi, dove ogni elemento della matrice corrisponde a una vista del target di rendering. Quando si usano più destinazioni di rendering, ogni destinazione di rendering deve essere uguale tipo di risorsa (buffer, trama 1D, matrice di trame 2D e così via) e deve avere la stessa dimensione (larghezza, altezza, profondità per trame 3D e dimensioni della matrice per le matrici di trame). Se le destinazioni di rendering sono multicampionate, devono avere tutte lo stesso numero di campioni per pixel.

Può essere attivo un solo buffer depth-stencil, indipendentemente dal numero di destinazioni di rendering attive. Quando si usano matrici di trame come destinazioni di rendering, tutte le dimensioni di visualizzazione devono corrispondere. Le destinazioni di rendering non devono avere lo stesso formato di trama.

Risorse (Direct3D 10)