Partilhar via


Criando recursos de textura (Direct3D 10)

Um recurso de textura é uma coleção estruturada de dados. Normalmente, os valores de cor são armazenados em texturas e acessados durante a renderização pelo pipeline em vários estágios para entrada e saída. Criar texturas e definir como elas serão usadas é uma parte importante da renderização de cenas interessantes no Direct3D 10.

Embora as texturas normalmente contenham informações de cor, a criação de texturas usando DXGI_FORMAT diferentes permite que elas armazenem diferentes tipos de dados. Esses dados podem ser aproveitados pelo pipeline do Direct3D 10 de maneiras não tradicionais.

Todas as texturas têm limites para a quantidade de memória que consomem e quantos texels contêm. Esses limites são especificados por constantes de recurso.

Criar uma textura a partir de um arquivo

Observação

A biblioteca de utilitários D3DX foi preterida para o Windows 8 e não é suportada para aplicativos da Windows Store.

 

Ao criar uma textura no Direct3D 10, você também precisa criar uma exibição . Uma exibição é um objeto que informa ao dispositivo como uma textura deve ser acessada durante a renderização. A maneira mais comum de acessar uma textura é ler a partir dela usando um sombreador . Uma exibição de recurso de sombreador informará a um sombreador como ler de uma textura durante a renderização. O tipo de exibição que uma textura usará deve ser especificado ao criá-la.

Criar uma textura e carregar seus dados iniciais pode ser feito de duas maneiras diferentes: criar uma textura e exibir separadamente ou criar a textura e a exibição ao mesmo tempo. A API fornece ambas as técnicas para que você possa escolher a que melhor se adapta às suas necessidades.

Criar textura e visualizar separadamente

A maneira mais fácil de criar uma textura é carregá-la a partir de um arquivo de imagem. Para criar a textura, basta preencher uma estrutura e fornecer o nome da textura para 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 );

A função D3DX D3DX10CreateTextureFromFile faz três coisas: primeiro, cria um objeto de textura Direct3D 10; segundo, ele lê o arquivo de imagem de entrada; Em terceiro lugar, ele armazena os dados da imagem no objeto Texture. No exemplo acima, um arquivo BMP é carregado, mas a função pode carregar uma variedade de tipos de arquivo.

O sinalizador de ligação indica que a textura será criada como um recurso de sombreador que permite que um estágio de sombreador leia a textura durante a renderização.

O exemplo acima não especifica todos os parâmetros de carregamento. Na verdade, muitas vezes é benéfico simplesmente zerar os parâmetros de carregamento, pois isso permite que o D3DX escolha valores apropriados com base na imagem de entrada. Se você quiser que a imagem de entrada determine todos os parâmetros com os quais a textura é criada, basta especificar NULL para o parâmetro loadInfo da seguinte forma:

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

Especificar NULL para as informações de carregamento é um atalho simples, mas poderoso.

Agora que uma textura foi criada, você precisa criar uma exibição de recurso de sombreador para que a textura possa ser vinculada como uma entrada a um sombreador. Como D3DX10CreateTextureFromFile retorna um ponteiro para um recurso e não um ponteiro para uma textura, você precisa determinar o tipo exato de recurso que foi carregado e, em seguida, pode criar uma exibição de recurso de sombreador 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 );

Embora o exemplo acima crie uma exibição de recurso de sombreador 2D, o código para criar outros tipos de exibição de recurso de sombreador é muito semelhante. Em qualquer estágio de sombreador, esta textura pode agora ser utilizada como entrada.

Usar D3DX10CreateTextureFromFile e CreateShaderResourceView para criar uma textura e a sua exibição associada é uma forma de preparar uma textura para ser vinculada a um estágio de sombreador. Outra maneira de fazer isso é criar a textura e sua exibição ao mesmo tempo, o que é discutido na próxima seção.

Criar textura e visualizar simultaneamente

O Direct3D 10 requer tanto uma textura quanto uma visualização de recurso de sombreador para ler de uma textura em tempo de execução. Como a criação de uma textura e uma vista de recurso de shader é uma tarefa tão comum, o D3DX fornece o D3DX10CreateShaderResourceViewFromFile para o fazer por si.

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

Com uma única chamada D3DX, são criadas tanto a textura quanto a visualização do recurso de sombreador. A funcionalidade do parâmetro loadInfo permanece inalterada; você pode usá-lo para personalizar como a textura é criada ou derivar os parâmetros necessários do arquivo de entrada especificando NULL para o parâmetro loadInfo.

O objeto ID3D10ShaderResourceView retornado pela função D3DX10CreateShaderResourceViewFromFile pode ser usado posteriormente para recuperar a interface ID3D10Resource original, se necessário. Isso pode ser feito chamando o GetResource método.

O D3DX fornece uma única função para criar uma textura e uma visualização de recurso de sombreador como conveniência; é da sua responsabilidade decidir qual método de criação de textura e visualização melhor adequa-se às necessidades do seu aplicativo.

Agora que você sabe como criar uma textura e sua exibição de recurso de sombreador, a próxima seção mostrará como você pode obter amostras (ler) dessa textura usando um sombreador.

Criação de texturas vazias

Às vezes, os aplicativos vão querer criar uma textura e calcular os dados a serem armazenados na textura, ou usar os gráficos pipeline para renderizar essa textura e, posteriormente, usar os resultados em outro processamento. Essas texturas podem ser atualizadas pelo pipeline gráfico ou pela própria aplicação, dependendo do tipo de de uso especificado para a textura quando ela foi criada.

Renderização para uma textura

O caso mais comum de criação de uma textura vazia para ser preenchida com dados durante o tempo de execução é o caso em que um aplicativo deseja renderizar para uma textura e, em seguida, usar os resultados da operação de renderização em uma passagem subsequente. As texturas criadas com essa finalidade devem especificar o uso de padrão.

O exemplo de código a seguir cria uma textura vazia que o pipeline pode renderizar e, posteriormente, usar como uma entrada para um sombreador de .

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

A criação da textura requer que o aplicativo especifique algumas informações sobre as propriedades que a textura terá. A largura e altura da textura em texels é definida para 256. Para este alvo de renderização, um único nível de mipmap é tudo o que precisamos. Apenas um destino de renderização é necessário para que o tamanho da matriz seja definido como 1. Cada texel contém quatro valores de ponto flutuante de 32 bits, que podem ser usados para armazenar informações muito precisas (ver DXGI_FORMAT). Uma amostra por pixel é tudo o que será necessário. O uso é definido como padrão porque isso permite o posicionamento mais eficiente do destino de renderização na memória. Finalmente, o facto de a textura ser associada como alvo de renderização e recurso de sombreamento em diferentes momentos no tempo é especificado.

As texturas não podem ser vinculadas para renderização diretamente ao pipeline; Use uma exibição de destino de renderização, conforme mostrado no exemplo de código a seguir.

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

O formato da visualização de destino de renderização é simplesmente definido para o formato da textura original. As informações no recurso devem ser interpretadas como uma textura 2D, e queremos usar apenas o primeiro nível mipmap do destino de renderização.

Da mesma forma que uma exibição de destino de renderização deve ser criada para que o destino de renderização possa ser vinculado para saída ao pipeline, uma exibição de recurso de sombreador deve ser criada para que o destino de renderização possa ser vinculado ao pipeline como uma entrada. O exemplo de código a seguir demonstra isso.

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

Os parâmetros das descrições das vistas de recursos de sombreador são muito semelhantes aos das descrições das vistas de alvo de renderização e foram escolhidos pelos mesmos motivos.

Preenchimento manual de texturas

Às vezes, os aplicativos gostariam de calcular valores em tempo de execução, colocá-los em uma textura manualmente e, em seguida, ter os gráficos pipeline usar essa textura em operações de renderização posteriores. Para fazer isso, o aplicativo deve criar uma textura vazia de tal forma a permitir que a CPU acesse a memória subjacente. Isso é feito criando uma textura dinâmica e obtendo acesso à memória subjacente chamando um método específico. O exemplo de código a seguir demonstra como fazer isso.

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

Observe que o formato é definido como 32 bits por pixel, onde cada componente é definido por 8 bits. O parâmetro usage é definido como dinâmico, enquanto os sinalizadores de ligação são definidos para especificar que a textura será acessada por um sombreador. O restante da descrição da textura é semelhante à criação de um destino de renderização.

Chamar Map permite que o aplicativo acesse a memória subjacente da textura. O ponteiro recuperado é então usado para preencher a textura com dados. Isso pode ser visto no exemplo de código a seguir.

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

Vários destinos de renderização

Até oito exibições de destino de renderização podem ser vinculadas ao pipeline de cada vez (com OMSetRenderTargets). Para cada pixel (ou cada amostra se a amostragem múltipla estiver habilitada), a mistura é feita independentemente para cada visualização de destino de renderização. Duas das variáveis de estado de mesclagem - BlendEnable e RenderTargetWriteMask - são matrizes de oito, cada membro da matriz corresponde a uma exibição de destino de renderização. Ao usar vários destinos de renderização, cada destino de renderização deve ser o mesmo tipo de recurso (buffer, textura 1D, matriz de textura 2D, etc.) e deve ter a mesma dimensão (largura, altura, profundidade para texturas 3D e tamanho de matriz para matrizes de textura). Se os destinos de renderização forem com várias amostras, todos eles deverão ter o mesmo número de amostras por pixel.

Só pode haver um buffer de estêncil de profundidade ativo, independentemente de quantos destinos de renderização estão ativos. Ao usar matrizes de textura como destinos de renderização, todas as dimensões de exibição devem corresponder. Os destinos de renderização não precisam ter o mesmo formato de textura.

Recursos (Direct3D 10)