Share via


Porter le langage GLSL

API importantes

Après avoir adapté le code utilisé pour créer et configurer vos mémoires tampons et vos objets nuanceurs, vous pouvez procéder au portage du code de ces nuanceurs du langage GLSL (GL Shader Language) d’OpenGL ES 2.0 vers le langage HLSL (High-level Shader Language) de Direct3D 11.

Dans OpenGL ES 2.0, les nuanceurs retournent des données après l’exécution à l’aide d’intrinsèques telles que gl_Position, gl_FragColor ou gl_FragData[n] (où n est l’index d’une cible de rendu spécifique). Dans Direct3D, les nuanceurs n’utilisent pas d’intrinsèques : ils renvoient les données dans le même type que celui de leurs fonctions main() respectives.

Les données à interpoler entre les étapes des nuanceurs, telles que les variables de vertex « position » ou « normal », sont gérées au moyen de la déclaration varying. En revanche, cette déclaration n’existant pas dans Direct3D, vous devrez ajouter une sémantique HLSL à toutes les données à transmettre d’une étape à l’autre dans les nuanceurs. La sémantique choisie dépend de la finalité des données. Par exemple, pour interpoler des données de vertex dans le nuanceur de fragments, déclarez-les comme suit :

float4 vertPos : POSITION;

ou

float4 vertColor : COLOR;

POSITION correspond à la sémantique définissant les données sur la position du vertex. POSITION est une sémantique particulière, car après l’interpolation, elle n’est plus accessible au nuanceur de pixels. Par conséquent, vous devez spécifier l’entrée dans le nuanceur de pixels avec SV_POSITION et les données de vertex interpolées seront placées dans cette variable.

float4 position : SV_POSITION;

Les sémantiques peuvent être déclarées dans les méthodes body (main) des nuanceurs. Pour les nuanceurs de pixels, SV_TARGET[n], qui indique une cible de rendu, est obligatoire sur la méthode body. (SV_TARGET sans suffixe numérique par défaut pour afficher l’index cible 0.)

Notez également que des nuanceurs de vertex sont nécessaires pour générer la sémantique de la valeur système SV_POSITION. Cette sémantique traduit les données de position du vertex en coordonnées, où x et y sont des valeurs comprises entre -1 et 1, z est divisé par la valeur w de la coordonnée homogène initiale (z/w), et w correspond à 1 divisé par la valeur w initiale (1/w). Les nuanceurs de pixels utilisent la sémantique de la valeur système SV_POSITION pour récupérer l’emplacement des pixels à l’écran, où x est compris entre 0 et la largeur cible de rendu et y est compris entre 0 et la hauteur cible de rendu (chaque décalage de 0,5). Le niveau de fonctionnalité 9_x nuanceurs de pixels ne peut pas lire à partir de la valeur SV_POSITION.

Les mémoires tampons constantes doivent être déclarées avec le mot clé cbuffer et être associées à un registre de démarrage spécifique pour la recherche.

Direct3D 11 : déclaration de mémoire tampon constante HLSL

cbuffer ModelViewProjectionConstantBuffer : register(b0)
{
  matrix mvp;
};

Dans cet exemple, la mémoire tampon constante utilise le registre b0 pour mettre en attente la mémoire tampon empaquetée. Tous les registres sont référencés sous la forme b#. Pour plus d’informations sur l’implémentation HLSL des mémoires tampons constantes, des registres et des données empaquetées, voir Constantes de nuanceur (HLSL).

Instructions

Étape 1 : Porter le nuanceur de vertex

Dans notre exemple simple de code OpenGL ES 2.0, le nuanceur de vertex reçoit trois données en entrée : une matrice 4x4 constante modèle-affichage-projection et deux vecteurs à quatre coordonnées. Ces vecteurs définissent la position et la couleur du vertex. Le nuanceur transforme le vecteur de position en coordonnées de perspective et l’affecte au gl_Position intrinsèque pour la rastérisation. La couleur du vertex est copiée dans une variable « varying » qui sera également utilisée lors de la rastérisation, pour l’interpolation.

OpenGL ES 2.0 : nuanceur de vertex pour l’objet cube (GLSL)

uniform mat4 u_mvpMatrix; 
attribute vec4 a_position;
attribute vec4 a_color;
varying vec4 destColor;

void main()
{           
  gl_Position = u_mvpMatrix * a_position;
  destColor = a_color;
}

Désormais, dans Direct3D, la matrice constante modèle-affichage-projection est contenue dans une mémoire tampon constante empaquetée dans le registre b0, et la position et la couleur du vertex sont définies avec des sémantiques HLSL spécifiques (POSITION et COLOR, respectivement). Étant donné que notre disposition en entrée correspond à un emplacement précis de ces deux valeurs de vertex, vous créez une structure pour les contenir, puis déclarez cette structure en tant que type de paramètre d’entrée pour la fonction body (main) du nuanceur. (Vous pourriez aussi définir ces deux valeurs sous forme de paramètres individuels, mais cette pratique n’est pas recommandée.) Par ailleurs, vous indiquez un type de sortie pour cette étape, qui contient la position et la couleur interpolées, puis vous le déclarez en tant que valeur de retour pour la fonction body du nuanceur de vertex.

Direct3D 11 : nuanceur de vertex pour l’objet cube (HLSL)

cbuffer ModelViewProjectionConstantBuffer : register(b0)
{
  matrix mvp;
};

// Per-vertex data used as input to the vertex shader.
struct VertexShaderInput
{
  float3 pos : POSITION;
  float3 color : COLOR;
};

// Per-vertex color data passed through the pixel shader.
struct PixelShaderInput
{
  float3 pos : SV_POSITION;
  float3 color : COLOR;
};

PixelShaderInput main(VertexShaderInput input)
{
  PixelShaderInput output;
  float4 pos = float4(input.pos, 1.0f); // add the w-coordinate

  pos = mul(mvp, projection);
  output.pos = pos;

  output.color = input.color;

  return output;
}

Le type des données en sortie (PixelShaderInput) est indiqué au moment de la rastérisation, puis transmis au nuanceur de fragments (pixels).

Étape 2 : Porter le nuanceur de fragments

Notre exemple de nuanceur de fragments dans GLSL est extrêmement simple : fournissez le gl_FragColor intrinsèque avec la valeur de couleur interpolée. OpenGL ES 2.0 transmettra cette valeur à la cible de rendu par défaut.

OpenGL ES 2.0 : nuanceur de fragments pour l’objet cube (GLSL)

varying vec4 destColor;

void main()
{
  gl_FragColor = destColor;
} 

Le processus Direct3D est presque aussi simple. La seule différence notable concerne la fonction body du nuanceur de pixels, qui doit renvoyer une valeur. Étant donné que la couleur est une valeur float à 4 coordonnées (RVBA), vous indiquez float4 comme type de retour, puis spécifiez la cible de rendu par défaut comme sémantique de la valeur système SV_TARGET.

Direct3D 11 : nuanceur de pixels pour l’objet cube (HLSL)

struct PixelShaderInput
{
  float4 pos : SV_POSITION;
  float3 color : COLOR;
};


float4 main(PixelShaderInput input) : SV_TARGET
{
  return float4(input.color, 1.0f);
}

La couleur du pixel situé à la position indiquée est transmise à la cible de rendu. Pour plus d’informations sur l’affichage du contenu de la cible de rendu, voir Dessiner à l’écran.

Étape précédente

Porter les mémoires tampons et données de vertex

Étape suivante

Dessiner vers l’écran

Remarques

Pour faciliter le débogage de votre code et avoir plus de latitude pour l’optimiser, il est essentiel de bien comprendre le fonctionnement des sémantiques HLSL et du packaging des mémoires tampons constantes. Si vous le pouvez, lisez les articles Syntaxe des variables (HLSL), Présentation des mémoires tampons dans Direct3D 11 et Procédure : Création d’une mémoire tampon constante. Sinon, prenez au moins connaissance des quelques conseils ci-dessous concernant l’utilisation des sémantiques et des mémoires tampons :

  • Vérifiez toujours le code de configuration Direct3D de votre convertisseur afin de vous assurer que les structures de vos mémoires tampons constantes correspondent aux déclarations de structure cbuffer indiquées dans votre code HLSL, et que les types scalaires des composants sont identiques dans l’ensemble des déclarations.
  • Dans le code C++ de votre convertisseur, utilisez les types DirectXMath dans les déclarations de mémoires tampons constantes pour garantir un packaging correct des données.
  • Pour optimiser l’utilisation des mémoires tampons constantes, classez les variables de nuanceur dans ces mémoires en fonction de la fréquence de leur mise à jour. Par exemple, si certaines de vos données uniformes sont mises à jour une fois par trame, alors que d’autres ne sont mises à jour qu’après un mouvement de la caméra, il vaut mieux placer ces données dans deux mémoires tampons constantes distinctes.
  • Vérifiez soigneusement toutes les sémantiques utilisées. En effet, les premières erreurs de compilation d’un nuanceur (FXC) sont souvent dues à un oubli de sémantiques ou à leur utilisation incorrecte. La documentation fournie peut être confuse, du fait que beaucoup de pages et d’exemples publiés précédemment font référence aux différentes versions de sémantiques HLSL antérieures à Direct3D 11.
  • Assurez-vous que le niveau de fonctionnalité Direct3D utilisé est approprié pour chaque nuanceur. La sémantique du niveau de fonctionnalité 9_* est différente de celle de 11_1.
  • La sémantique SV_POSITION résout les données de position post-interpolation associées pour coordonner les valeurs où x est compris entre 0 et la largeur de la cible de rendu, y est compris entre 0 et la hauteur cible de rendu, z est divisé par la coordonnée homogène d’origine w valeur (z/w), et w est divisé par la valeur w d’origine (1/w).

Guide pratique pour porter un convertisseur OpenGL ES 2.0 simple vers Direct3D 11

Porter les objets nuanceur

Porter les mémoires tampons et données de vertex

Dessiner vers l’écran