Programmation d’un ou plusieurs flux (Direct3D 9)

Cette section décrit les nuanceurs qui peuvent être utilisés pour le modèle de flux programmable.

Utilisation de flux

DirectX 8 a introduit la notion de flux pour lier des données à des registres d’entrée à des fins d’utilisation par les nuanceurs. Un flux est un tableau uniforme de données de composant, où chaque composant se compose d’un ou plusieurs éléments qui représentent une seule entité telle que la position, la normale, la couleur, etc. Les flux permettent aux puces graphiques d’effectuer un accès direct à la mémoire à partir de plusieurs mémoires tampons de vertex en parallèle et fournissent également un mappage plus naturel à partir des données d’application. Ils permettent également le multitexture trivial et le multipass. Pensez-y comme ceci :

  • Un sommet est composé de n flux.
  • Un flux est composé d’éléments m.
  • Un élément est [position, couleur, normale, coordonnée de texture].

La méthode IDirect3DDevice9::SetStreamSource lie une mémoire tampon de vertex à un flux de données d’appareil, créant une association entre les données de vertex et l’un des ports de flux de données qui alimentent les fonctions de traitement primitives. Les références réelles aux données de flux ne se produisent pas tant qu’une méthode de dessin, telle que IDirect3DDevice9::D rawPrimitive, n’est pas appelée.

Le mappage des éléments de vertex d’entrée aux registres d’entrée de vertex pour les nuanceurs de vertex programmables est défini dans la déclaration du nuanceur, mais les éléments de vertex d’entrée n’ont pas de sémantique spécifique sur leur utilisation. L’interprétation des éléments de vertex d’entrée est programmée à l’aide des instructions du nuanceur. La fonction de nuanceur de vertex est définie par un tableau d’instructions qui sont appliquées à chaque sommet. Les registres de sortie de vertex sont explicitement écrits dans, à l’aide d’instructions dans la fonction de nuanceur.

Dans le cadre de cette discussion, cependant, vous devez moins vous préoccuper du mappage sémantique des éléments aux registres que de la raison de l’utilisation des flux et du problème qui est résolu par l’utilisation de flux. L’avantage main des flux est qu’ils suppriment les coûts de données de vertex précédemment associés à la multitexturation. Avant les flux, un utilisateur devait dupliquer les jeux de données de vertex pour gérer le cas unique et multitexture sans éléments de données inutilisés, ou transporter des éléments de données qui seraient inutilisés sauf dans le cas de la multitexture.

Voici un exemple d’utilisation de deux jeux de données de vertex, l’un pour une texture unique et l’autre pour la multitexturation.

struct CUSTOMVERTEX_TEX1
{
    FLOAT x, y, z;      // The untransformed position for the vertex
    DWORD diffColor;    // The vertex diffuse color    
    DWORD specColor;    // The vertex specular color
    float tu_1, tv_1;   // Texture coordinates for a single texture
};
 
struct CUSTOMVERTEX_TEX2
{
    FLOAT x, y, z;      // The untransformed position for the vertex
    DWORD diffColor;    // The vertex diffuse color    
    DWORD specColor;    // The vertex specular color
    float tu_2, tv_2;   // Texture coordinates for multitexturing
};

L’alternative était d’avoir un seul élément de vertex qui contenait les deux jeux de coordonnées de texture.

struct CUSTOMVERTEX_TEX2
{
    FLOAT x, y, z;      // The untransformed position for the vertex
    DWORD diffColor;    // The vertex diffuse color    
    DWORD specColor;    // The vertex specular color
    float tu_1, tv_1;   // Texture coordinates for a single texture
    float tu_2, tv_2;   // Texture coordinates for multitexturing
};

Avec ces données de vertex, une seule copie des données de position et de couleur est conservée en mémoire, au détriment du transport des deux ensembles de coordonnées de texture pour le rendu, même dans le cas de texture unique.

Maintenant que le compromis est clair, les flux fournissent une solution élégante à ce dilemme. Voici un ensemble de définitions de vertex pour prendre en charge trois flux : l’un avec la position et la couleur, l’autre avec le premier ensemble de coordonnées de texture et l’autre avec le deuxième ensemble de coordonnées de texture.

// Multistream vertex
// Stream 0, pos, diffuse, specular
struct POSCOLORVERTEX
{
    FLOAT x, y, z;
    DWORD diffColor, specColor;
};
#define D3DFVF_POSCOLORVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_SPECULAR)
// Stream 1, tex coord 0
struct TEXC0VERTEX
{
    FLOAT tu1, tv1;
};
#define D3DFVF_TEXC0VERTEX (D3DFVF_TEX1)

// Stream 2, tex coord 1
struct TEXC1VERTEX
{
    FLOAT tu2, tv2;
};
#define D3DFVF_TEXC1VERTEX (D3DFVF_TEX0)

La déclaration de vertex se présente comme suit :

// Multitexture - multistream

D3DVERTEXELEMENT9 dwDecl3[] = 
{
    {0, 0,  D3DDECLTYPE_FLOAT3,   D3DDECLMETHOD_DEFAULT, 
                                      D3DDECLUSAGE_POSITION, 0},
    {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, 
                                      D3DDECLUSAGE_COLOR, 0},
    {0, 16, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, 
                                      D3DDECLUSAGE_COLOR, 1},
    {1,  0, D3DDECLTYPE_FLOAT2,   D3DDECLMETHOD_DEFAULT, 
                                      D3DDECLUSAGE_TEXCOORD, 0},
    {2,  0, D3DDECLTYPE_FLOAT2,   D3DDECLMETHOD_DEFAULT, 
                                      D3DDECLUSAGE_TEXCOORD, 1},
    D3DDECL_END()
};

Créez maintenant l’objet de déclaration de vertex et définissez-le comme indiqué :

LPDIRECT3DVERTEXDECLARATION9 m_pVertexDeclaration;
g_d3dDevice->CreateVertexDeclaration(dwDecl3, &m_pVertexDeclaration);

m_pd3dDevice->SetVertexDeclaration(m_pVertexDeclaration);

Exemples de combinaisons

Couleur diffuse d’un flux

Les paramètres de déclaration de vertex et de flux pour le rendu des couleurs diffuses ressemblent à ceci :

D3DVERTEXELEMENT9 dwDecl3[] = 
{
    {0,  0,  D3DDECLTYPE_FLOAT3,   D3DDECLMETHOD_DEFAULT, 
                                      D3DDECLUSAGE_POSITION, 0},
    {0, 12,  D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, 
                                      D3DDECLUSAGE_COLOR, 0 ,
    {0, 16,  D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, 
                                      D3DDECLUSAGE_COLOR, 1},
    D3DDECL_END()
};
   m_pd3dDevice->SetStreamSource(0, m_pVBVertexShader0, 0,
                                      sizeof(CUSTOMVERTEX));
   m_pd3dDevice->SetStreamSource(1, NULL, 0, 0);
   m_pd3dDevice->SetStreamSource(2, NULL, 0, 0);

Deux flux avec couleur et texture

Les paramètres de déclaration de vertex et de flux pour le rendu d’une texture unique ressemblent à ceci :

D3DVERTEXELEMENT9 dwDecl3[] = 
{
    {0, 0,  D3DDECLTYPE_FLOAT3,   D3DDECLMETHOD_DEFAULT, 
                                      D3DDECLUSAGE_POSITION, 0},
    {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, 
                                      D3DDECLUSAGE_COLOR, 0},
    {0, 16, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, 
                                      D3DDECLUSAGE_COLOR, 1},

    {1,  0, D3DDECLTYPE_FLOAT2,   D3DDECLMETHOD_DEFAULT, 
                                      D3DDECLUSAGE_TEXCOORD, 0},

    D3DDECL_END()
};
   m_pd3dDevice->SetStreamSource(0, m_pVBPosColor, 0,
                                           sizeof(POSCOLORVERTEX));
   m_pd3dDevice->SetStreamSource(1, m_pVBTexC0, 0,
                                           sizeof(TEXC0VERTEX));
   m_pd3dDevice->SetStreamSource(2, NULL, 0, 0);

Deux flux avec couleur et deux textures

Les paramètres de déclaration de vertex et de flux pour le rendu multi texture à deux textures ressemblent à ceci :

D3DVERTEXELEMENT9 dwDecl3[] = 
{
    {0, 0,  D3DDECLTYPE_FLOAT3,   D3DDECLMETHOD_DEFAULT, 
                                      D3DDECLUSAGE_POSITION, 0},
    {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, 
                                      D3DDECLUSAGE_COLOR, 0},
    {0, 16, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, 
                                      D3DDECLUSAGE_COLOR, 1},

    {1,  0, D3DDECLTYPE_FLOAT2,   D3DDECLMETHOD_DEFAULT, 
                                      D3DDECLUSAGE_TEXCOORD, 0},

    {2,  0, D3DDECLTYPE_FLOAT2,   D3DDECLMETHOD_DEFAULT, 
                                      D3DDECLUSAGE_TEXCOORD, 1},
    
    D3DDECL_END()
};
 
m_pd3dDevice->SetStreamSource(0, m_pVBPosColor, 0, 
                                          sizeof(POSCOLORVERTEX));
m_pd3dDevice->SetStreamSource(1, m_pVBTexC0, 0, 
                                          sizeof(TEXC0VERTEX));
m_pd3dDevice->SetStreamSource(2, m_pVBTexC1, 0, 
                                          sizeof(TEXC1VERTEX));

Dans tous les cas, l’appel suivant IDirect3DDevice9::D rawPrimitive suffit.

       m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, NUM_TRIS);

Cela montre la flexibilité des flux dans la résolution du problème de la duplication des données/la transmission redondante de données dans le bus (autrement dit, de la quantité de bande passante gaspillante).

Déclaration de vertex