David Catuhe
Conception avancée de shaders DirectX 10.0
Mise en place d’un mécanisme maintenable et performant pour la gestion des shaders générique avec DirectX 10.0
Par David Catuhe publié le 28/10/2009 à 20:22, lu 1834 fois, 6 pages
 3 | Utilisation des variables uniformes
L’idée derrière notre shader va donc être de tout coder comme si TOUTES les options étaient actives et par la suite nous allons mettre en place un mécanisme pour activer ou désactiver les options que l’on ne veut pas.
Pour notre exemple, nous allons mettre en place un effet qui pourra gérer le vertex color et l’émissif. Il est bien évident que le vrai uber shader proposerait plus d’options mais pour ne pas complexifier le code HLSL inutilement nous allons nous contenter de ces 2 options.
Le code de base de notre effet est donc le suivant :

float4 emissive;

 

struct VS_IN

{

    float4 pos : POSITION;

    float4 col : COLOR;

};

 

struct PS_IN

{

    float4 pos : SV_POSITION;

    float4 col : COLOR;

};

 

PS_IN VS( VS_IN input )

{

    PS_IN output = (PS_IN)0;

 

    output.pos = input.pos;

    output.col = input.col + emissive;

 

    return output;

}

 

float4 PS( PS_IN input ) : SV_Target

{

    return input.col;

}

 

technique10 Render

{

    pass P0

    {

        SetGeometryShader( 0 );

        SetVertexShader( CompileShader( vs_4_0, VS() ) );

        SetPixelShader( CompileShader( ps_4_0, PS() ) );

    }

}

Comme nous pouvons le voir, nous avons un vertex shader et un pixel shader très simple. Le vertex shader récupère des vertices avec une position écran et une couleur. Nous avons une variable globale qui contient la couleur d’émissif globale. Les couleurs s’ajoutent et sont transmises au pixel shader qui fait juste une sortie écran de la couleur.
Pour mettre en place nos options, nous allons donc déclarer un constant buffer qui portera tous les booléens permettant de switcher le code avec des conditions :

cbuffer cbGlobals

{

    float4 emissive;

    bool vertexColor;

    bool emissiveColor;

};

 

struct VS_IN

{

    float4 pos : POSITION;

    float4 col : COLOR;

};

 

struct PS_IN

{

    float4 pos : SV_POSITION;

    float4 col : COLOR;

};

 

PS_IN VS( VS_IN input )

{

    PS_IN output = (PS_IN)0;

 

    output.pos = input.pos;

 

    if (vertexColor)

        output.col += input.col;

 

    if (emissiveColor)

        output.col += emissive;

 

    return output;

}

 

float4 PS( PS_IN input ) : SV_Target

{

    return input.col;

}

 

technique10 Render

{

    pass P0

    {

        SetGeometryShader( 0 );

        SetVertexShader( CompileShader( vs_4_0, VS() ) );

        SetPixelShader( CompileShader( ps_4_0, PS() ) );

    }

}

Pour activer nos booléens, il nous suffit dans le code avant le rendu de récupérer nos variables et de les affecter à vrai ou faux selon le contexte :

effect.GetVariableByName("vertexColor").AsScalar().Set(true);

effect.GetVariableByName("emissiveColor").AsScalar().Set(true);

Ce fonctionnement est tout à fait acceptable dans le cadre de DirectX10 ou les branchements sont bien gérés. Toutefois si l’on compare la vitesse de rendu de ce shader à celui de la fonction fixée de DirectX9 on se retrouve un peu en dessous.
Il est évident que la programmation par tests de booléens est élégante à écrire mais ne donne pas la même puissance qu’un code sans test.
 
» Démarrer une discussion