Partager via


Création de ressources de texture (Direct3D 10)

Une ressource de texture est une collection structurée de données. En règle générale, les valeurs de couleur sont stockées dans des textures et accessibles pendant le rendu par le pipeline à différentes étapes pour l’entrée et la sortie. La création de textures et la définition de leur utilisation sont une partie importante du rendu de scènes intéressantes dans Direct3D 10.

Même si les textures contiennent généralement des informations de couleur, la création de textures à l’aide de différentes DXGI_FORMAT leur permet de stocker différents types de données. Ces données peuvent ensuite être exploitées par le pipeline Direct3D 10 de manière non traditionnelle.

Toutes les textures ont des limites quant à la quantité de mémoire qu’elles consomment et au nombre de texels qu’elles contiennent. Ces limites sont spécifiées par des constantes de ressource.

Créer une texture à partir d’un fichier

Notes

La bibliothèque d’utilitaires D3DX est déconseillée pour Windows 8 et n’est pas prise en charge pour les applications du Windows Store.

 

Lorsque vous créez une texture dans Direct3D 10, vous devez également créer une vue. Une vue est un objet qui indique à l’appareil comment accéder à une texture pendant le rendu. La façon la plus courante d’accéder à une texture consiste à lire à partir de celle-ci à l’aide d’un nuanceur. Une vue nuanceur-ressource indique à un nuanceur comment lire à partir d’une texture pendant le rendu. Le type de vue qu’une texture utilisera doit être spécifié lorsque vous la créez.

La création d’une texture et le chargement de ses données initiales peuvent être effectuées de deux manières différentes : créer une texture et une vue séparément, ou créer à la fois la texture et la vue en même temps. L’API fournit les deux techniques afin que vous puissiez choisir celle qui correspond le mieux à vos besoins.

Créer une texture et une vue séparément

Le moyen le plus simple de créer une texture consiste à la charger à partir d’un fichier image. Pour créer la texture, il suffit de remplir une structure et de fournir le nom de la texture à 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 fonction D3DX D3DX10CreateTextureFromFile effectue trois opérations : premièrement, elle crée un objet de texture Direct3D 10 ; deuxièmement, il lit le fichier image d’entrée ; troisièmement, il stocke les données d’image dans l’objet de texture. Dans l’exemple ci-dessus, un fichier BMP est chargé, mais la fonction peut charger différents types de fichiers.

L’indicateur de liaison indique que la texture sera créée en tant que ressource de nuanceur, ce qui permet à une étape de nuanceur de lire à partir de la texture pendant le rendu.

L’exemple ci-dessus ne spécifie pas tous les paramètres de chargement. En fait, il est souvent avantageux de simplement annuler les paramètres de chargement, car cela permet à D3DX de choisir les valeurs appropriées en fonction de l’image d’entrée. Si vous souhaitez que l’image d’entrée détermine tous les paramètres avec lesquels la texture est créée, spécifiez simplement NULL pour le paramètre loadInfo comme suit :

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

La spécification de null pour les informations de chargement est un raccourci simple mais puissant.

Maintenant qu’une texture a été créée, vous devez créer une vue nuanceur-ressource afin que la texture puisse être liée en tant qu’entrée à un nuanceur. Étant donné que D3DX10CreateTextureFromFile retourne un pointeur vers une ressource et non un pointeur vers une texture, vous devez déterminer le type exact de ressource qui a été chargé, puis vous pouvez créer une vue nuanceur-ressource à l’aide de 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 );

Bien que l’exemple ci-dessus crée une vue nuanceur-ressource 2D, le code permettant de créer d’autres types d’affichage nuanceur-ressource est très similaire. N’importe quelle étape de nuanceur peut désormais utiliser cette texture comme entrée.

L’utilisation de D3DX10CreateTextureFromFile et CreateShaderResourceView pour créer une texture et sa vue associée est un moyen de préparer une texture à lier à une étape de nuanceur. Une autre façon de procéder consiste à créer la texture et sa vue en même temps, ce qui est décrit dans la section suivante.

Créer simultanément une texture et une vue

Direct3D 10 nécessite à la fois une texture et une vue nuanceur-ressource pour lire à partir d’une texture pendant l’exécution. Étant donné que la création d’une texture et d’une vue nuanceur-ressource est une tâche courante, D3DX fournit le D3DX10CreateShaderResourceViewFromFile pour le faire pour vous.

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

Avec un seul appel D3DX, la vue texture et nuanceur-ressource sont créées. La fonctionnalité du paramètre loadInfo est inchangée ; vous pouvez l’utiliser pour personnaliser la façon dont la texture est créée ou dériver les paramètres nécessaires du fichier d’entrée en spécifiant NULL pour le paramètre loadInfo .

L’objet ID3D10ShaderResourceView retourné par la fonction D3DX10CreateShaderResourceViewFromFile peut être utilisé ultérieurement pour récupérer l’interface ID3D10Resource d’origine si nécessaire. Pour ce faire, appelez la méthode GetResource .

D3DX fournit une fonction unique pour créer une vue texture et nuanceur-ressource en tant que configuration ; c’est à vous de choisir la méthode de création d’une texture et d’une vue qui correspond le mieux aux besoins de votre application.

Maintenant que vous savez comment créer une texture et sa vue nuanceur-ressource, la section suivante vous montre comment échantillonner (lire) à partir de cette texture à l’aide d’un nuanceur.

Création de textures vides

Parfois, les applications veulent créer une texture et calculer les données à stocker dans la texture, ou utiliser le pipeline graphique pour afficher cette texture et utiliser ultérieurement les résultats dans d’autres traitements. Ces textures peuvent être mises à jour par le pipeline graphique ou par l’application elle-même, en fonction du type d’utilisation spécifié pour la texture lors de sa création.

Rendu à une texture

Le cas le plus courant de création d’une texture vide à remplir avec des données pendant l’exécution est le cas où une application souhaite effectuer un rendu sur une texture, puis utiliser les résultats de l’opération de rendu dans une passe suivante. Les textures créées à cet effet doivent spécifier l’utilisation par défaut.

L’exemple de code suivant crée une texture vide que le pipeline peut afficher et utiliser ensuite comme entrée dans un nuanceur.

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

La création de la texture nécessite que l’application spécifie des informations sur les propriétés de la texture. La largeur et la hauteur de la texture en texels sont définies sur 256. Pour cette cible de rendu, un seul niveau mipmap est tout ce dont nous avons besoin. Une seule cible de rendu est requise pour que la taille du tableau soit définie sur 1. Chaque texel contient quatre valeurs à virgule flottante 32 bits, qui peuvent être utilisées pour stocker des informations très précises (voir DXGI_FORMAT). Un exemple par pixel est tout ce qui sera nécessaire. L’utilisation est définie sur la valeur par défaut, car cela permet le placement le plus efficace de la cible de rendu en mémoire. Enfin, le fait que la texture soit liée en tant que cible de rendu et qu’une ressource de nuanceur à différents moments dans le temps est spécifié.

Les textures ne peuvent pas être liées directement au pipeline ; utilisez une vue cible de rendu, comme indiqué dans l’exemple de code suivant.

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

Le format de la vue cible de rendu est simplement défini sur le format de la texture d’origine. Les informations de la ressource doivent être interprétées comme une texture 2D, et nous voulons uniquement utiliser le premier niveau mipmap de la cible de rendu.

De la même façon qu’une vue cible de rendu doit être créée afin que la cible de rendu puisse être liée à la sortie vers le pipeline, une vue nuanceur-ressource doit être créée afin que la cible de rendu puisse être liée au pipeline en tant qu’entrée. L’exemple de code suivant le montre.

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

Les paramètres des descriptions d’affichage des ressources de nuanceur sont très similaires à ceux des descriptions de vue de cible de rendu et ont été choisis pour les mêmes raisons.

Remplissage manuel des textures

Parfois, les applications souhaitent calculer des valeurs au moment de l’exécution, les placer manuellement dans une texture, puis faire en sorte que le pipeline graphique utilise cette texture dans les opérations de rendu ultérieures. Pour ce faire, l’application doit créer une texture vide afin de permettre au processeur d’accéder à la mémoire sous-jacente. Pour ce faire, créez une texture dynamique et accédez à la mémoire sous-jacente en appelant une méthode particulière. L'exemple de code suivant montre comment procéder.

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

Notez que le format est défini sur 32 bits par pixel, chaque composant étant défini par 8 bits. Le paramètre d’utilisation est défini sur dynamique, tandis que les indicateurs de liaison sont définis pour spécifier que la texture sera accessible par un nuanceur. Le reste de la description de texture est similaire à la création d’une cible de rendu.

L’appel de mappage permet à l’application d’accéder à la mémoire sous-jacente de la texture. Le pointeur récupéré est ensuite utilisé pour remplir la texture avec des données. Vous pouvez le voir dans l’exemple de code suivant.

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

Plusieurs rendertargets

Jusqu’à huit vues cibles de rendu peuvent être liées au pipeline à la fois (avec OMSetRenderTargets). Pour chaque pixel (ou chaque exemple si le multi-échantillonnage est activé), le mélange est effectué indépendamment pour chaque affichage cible de rendu. Deux des variables d’état de fusion ( BlendEnable et RenderTargetWriteMask) sont des tableaux de huit, chaque membre du tableau correspond à une vue cible de rendu. Lorsque vous utilisez plusieurs cibles de rendu, chaque cible de rendu doit avoir le même type de ressource (mémoire tampon, texture 1D, tableau de textures 2D, etc.) et avoir la même dimension (largeur, hauteur, profondeur pour les textures 3D et taille du tableau pour les tableaux de textures). Si les cibles de rendu sont multi-échantillonnée, elles doivent toutes avoir le même nombre d’échantillons par pixel.

Il ne peut y avoir qu’une seule mémoire tampon de gabarit de profondeur active, quel que soit le nombre de cibles de rendu actives. Lorsque vous utilisez des tableaux de textures comme cibles de rendu, toutes les dimensions d’affichage doivent correspondre. Les cibles de rendu n’ont pas besoin d’avoir le même format de texture.

Ressources (Direct3D 10)