Programación de una o varias secuencias (Direct3D 9)

En esta sección se describen los sombreadores que se pueden usar para el modelo de secuencia programable.

Uso de secuencias

DirectX 8 introdujo la noción de una secuencia para enlazar datos a registros de entrada para usarlos por sombreadores. Una secuencia es una matriz uniforme de datos de componentes, donde cada componente consta de uno o varios elementos que representan una sola entidad, como posición, normal, color, etc. Los flujos permiten que los chips gráficos realicen un acceso directo a la memoria desde varios búferes de vértices en paralelo y también proporcionan una asignación más natural de los datos de la aplicación. También habilitan la multitextura trivial frente a la multipaso. Piense en esto:

  • Un vértice se compone de n secuencias.
  • Una secuencia se compone de elementos m.
  • Un elemento es [position, color, normal, coordenada de textura].

El método IDirect3DDevice9::SetStreamSource enlaza un búfer de vértices a un flujo de datos del dispositivo, creando una asociación entre los datos del vértice y uno de varios puertos de flujo de datos que alimentan las funciones de procesamiento primitivo. Las referencias reales a los datos de la secuencia no se producen hasta que se llama a un método de dibujo, como IDirect3DDevice9::D rawPrimitive.

La asignación de los elementos de vértice de entrada a los registros de entrada de vértices para sombreadores de vértices programables se define en la declaración del sombreador, pero los elementos de vértice de entrada no tienen semántica específica sobre su uso. La interpretación de los elementos de vértice de entrada se programa mediante las instrucciones del sombreador. La función de sombreador de vértices se define mediante una matriz de instrucciones que se aplican a cada vértice. Los registros de salida de vértices se escriben explícitamente en, mediante instrucciones de la función de sombreador.

Sin embargo, para esta explicación, tenga menos preocupación con la asignación semántica de elementos a los registros y más preocupados por el motivo del uso de secuencias y qué problema se resuelve mediante el uso de secuencias. La principal ventaja de los flujos es que quitan los costos de datos de vértices asociados anteriormente con la multitexturing. Antes de las secuencias, un usuario tenía que duplicar conjuntos de datos de vértices para controlar el caso único y multitexture sin elementos de datos sin usar, o bien llevar elementos de datos que no se usarían excepto en el caso multitexture.

Este es un ejemplo de uso de dos conjuntos de datos de vértices, uno para una sola textura y otro para multitexturing.

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

La alternativa era tener un único elemento de vértice que contenía ambos conjuntos de coordenadas de textura.

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

Con estos datos de vértice, solo se lleva en memoria una copia de los datos de posición y color, a costa de llevar ambos conjuntos de coordenadas de textura alrededor para su representación incluso en el único caso de textura.

Ahora que el equilibrio es claro, los flujos proporcionan una solución elegante a este dilema. Este es un conjunto de definiciones de vértices para admitir tres secuencias: una con posición y color, una con el primer conjunto de coordenadas de textura y otra con el segundo conjunto de coordenadas de textura.

// 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 declaración de vértice sería la siguiente:

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

Ahora cree el objeto de declaración de vértices y establézcalo como se muestra:

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

m_pd3dDevice->SetVertexDeclaration(m_pVertexDeclaration);

Ejemplos de combinaciones

Color difuso de una secuencia

La declaración de vértices y la configuración de secuencia para la representación de colores difusos tendría este aspecto:

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

Dos secuencias con color y textura

La configuración de secuencia y declaración de vértices para la representación de textura única tendría este aspecto:

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

Dos secuencias con color y dos texturas

La declaración de vértices y la configuración de secuencia para la representación de varias texturas de dos texturas tendría este aspecto:

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

En todos los casos, basta con la invocación IDirect3DDevice9::D rawPrimitive .

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

Esto muestra la flexibilidad de los flujos para resolver el problema de la duplicación de datos o la transmisión de datos redundante en el bus (es decir, de desperdiciar ancho de banda).

Declaración de vértices