Pipeline Graphique Programmable: Vertex et Pixel Shaders
Transcription
Pipeline Graphique Programmable: Vertex et Pixel Shaders
U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Pipeline Graphique Programmable: Vertex et Pixel Shaders Leçon n°8 : HLSL Année universitaire 2004-2005 Pascal Mignot [email protected] HLSL Introduction U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E HLSL = High Level Shading Language Définition: Langage de programmation haut-niveau permettant d’écrire des Vertex et Pixels Shaders avec une syntaxe proche du C. Objectifs: – simplifier l’écriture des shaders complexes, – simplifier les liens entre les shaders et le code DirectX. Historiquement: spécifications écrites par nVidia (ressemble étrangement à Cg). HLSL U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Introduction (2) • est aux shaders ce que le C est à l’assembleur. • compilation d’un code HLSL: HLSL → ASM → code objet • permet a priori d’obtenir un meilleur code qu’avec une écriture directe en assembleur (optimisation faite par le compilateur). Remarques: • profils cibles vs3 et ps3 désormais supportés sur les GeForces 6800 et 6600. • le fait qu’il soit possible d’écrire l’algorithme en HLSL ne signifie pas qu’il sera possible de l’exécuter (l’équivalent ASM doit être possible, i.e. en type d’instructions supportés, ...). HLSL U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Types de variable et modificateurs (1) Types de scalaire: bool booléen (true ou false) int entier 32 bits float flottant 32 bits Vecteurs et matrices: (1≤n≤4, 1≤p≤4). typen : vecteur de taille n et de type type. typenxp : matrice de taille n x p et de type type Définition de nouveaux types: typedef oldtype newtype; // nouveau type newtype équivalent à oldtype. Modificateurs: const (global+local) constante. static (global) constante locale au shader. (local) valeur persistante entre 2 appels. extern (global) variable fixée à l’extérieur du shader (défaut, exclusive de static). uniform (global) constante lors de l’exécution, variable à l’appel. shared (global) variable partagée entre effets. HLSL U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Types de variable et modificateurs (2) Exemples: float4 a; static float2 b; float4x4 m; typedef float4 vecteur; Rappel: dans un shader (cf ASM), • les types naturels des variables sont float4, int4, bool, float4xp. • les entiers ne sont utilisés que comme indice de tableau ou de boucle (+ mova dans les VS). • les booléens ne sont utilisés que dans les tests (+ setp_op si reg. predicat supporté). Conclusion: les autres utilisations peuvent engendrer des pertes de performances: tenter de conserver les écritures vectorielles. Remarque: à signaler l’existence des types half (float) et double. half a son intérêt avec les PS1.x (cf. partial précision), et double n’est pas encore supporté. HLSL U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Casting et initialisations Casting Exemples: promotion: float → floatp en recopiant p fois la valeur. réduction: float a=1; floatn → floatp si n≥p en recopiant les p premières composantes. floatnxm → floatpxq si n≥p et m≥q en recopiant la pxq premières composantes de la matrice nxm. interdiction: floatn ↔ floatpxq si les tailles sont incompatibles (pxq ≠ n). Initialisations vecteur: initialisation: floatn v={a1,...,an}; constructeur: floatn(a1,…,an) matrice: initialisation: floatnxp m={a11,a12,…,anp}; constructeur: floatnxp({a11,…,a1p},…,{an1,…,anp}) notes: • • • à l’initialisation ou dans le constructeur, tout p-uplet a1,…,ap peut être remplacé par un floatp. le constructeur peut être utilisé à l’initialisation ou pour la construction « inline » d’un vecteur/matrice lors d’un calcul. Attention dans les initialisations de ne pas remplacer {.} par (.) qui passe à la compilation mais ne donne pas le résultat attendu. float2 b={0,1}; float2 b=float2(0,1) float2x2 c={0,1,2,3}; float2x2 c={b,2,3} float2x2 c=float2x2({0,1},{2,3}) b=1; // = float2(1,1) b=c; // = float2(c.x,c.y) HLSL U N IVERSIT É D E R EIMS Accès aux composantes: floatq, intq et floatqxp, q≤4 C H AMP AGN E-A RD EN N E Accès aux composants d’un vecteur (floatq avec q≤4) accès par champs: x,y,z,w ou r,g,b,a (exemple: vec.x) Accès aux composants d’une matrice: accès par champs: _ij (0≤i≤3, 0≤j≤3) ou _mij (1≤i≤4, 1≤j≤4). accès par tableau: [i] pour la ième ligne, [i][j] pour la composante i,j (0≤i≤3, 0≤j≤3) Masques d’écriture comme pour ASM, les contraintes en moins (exemple: a.yxwz = b) également possible sur les matrices (accès par champs). Swizzling comme pour ASM, mais dépend maintenant de la taille du vecteur ou de la matrice utilisée. également possible pour les matrices (accès par champs). exemples: float2 a; float3 b; b=a.yx; // signifie b=a.yxx float2x2 a; float2 b; b=a._11_22; Remarque: seules les composantes existantes sont disponibles (exemple: x et y pour un float2). HLSL U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Définition et manipulation de structures Définition de structure: struct nstruct { type1 field1; … typen fieldn; }; struct LIGHT { float4 pos; float4 color; } uniform LIGHT light1; // variable externe typedef Color float4 float4 CalcLight(float P, float N) { lightdir = normalize(light.pos – P); Accès aux champs: retun light1.color * dot3(N,lightdir); } nstruct var; var.fieldi permet d’accéder (en lecture ou en écriture) au champs fieldi de la variable var de type nstruct. Initialisation d’une structure: var = (nstruct)0; pour initialiser tous ses champs à 0. var = { valfield1, …, valfieldn}; // pour initialiser tous les champs. Sémantique des champs: (voir VS/PS in/out) On spécifie la sémantique de chaque champs avec: type field:semantic; HLSL U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Opérateurs et comparaisons Opérateurs arithmétiques: Tout s’effectue composante par composante. incréments: ++ -- (préfixe ou postfixe). arithmétiques: + - * / % arithmétiques avec assignation: += -= *= /= %= test puis affectation: (a?b:c) Exemples: Autres fonctions: clip(x) élimine le pixel courant si un xi<0 (équivalent de texkill). lerp(x,y,s) interpolation linéaire: x + s(y-x) D3DCOLORtoU BYTE4(x) convertit le vecteur float (0≤xi ≤1) en ubyte4. float4 a,b,c; a = 3 * b * c + 4; c++; Opérateurs de comparaison: comparaisons: < > <= >= == != logique: || && ! Fonctions de test: isfinite(x) vrai si un xi est infini, 0 sinon. isinf(x) vrai si un xi est fini, 0 sinon. isnan(x) vrai si un xi est NAN. all(x) vrai si tous les xi sont positifs. any(x) vrai si au moins un xi est positif. HLSL U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Opérations sur vecteurs et matrices Stockage des matrices vector row 1 row 2 row 3 row 4 vector column 1 column 2 column 3 column 4 Rappel: les matrices sont stockés (par défaut) en mode « column-major ». En tenir compte lors du passage de paramètres dans l’API. Note: ce mode de stockage peut être modifié (row-major). Calcul matriciel determinant(m) retourne le produit scalaire mul(m1,m2) produit matrice-matrice ou vecteur-matrice (col-major) ou matrice-vecteur (row-major). transpose(m) retourne la transposée de la matrice. Calcul vectoriel dot(x,y) produit scalaire cross(x,y) produit vectoriel distance(x,y) distance de x à y length(x) norme (ou longueur) de x normalize(x) normalisation de x reflect(V,N) vecteur réfléchi (N=normale, V=entrée) refract(V,N,n) vecteur réfracté (N=normale, V=entrée, n=indice de réfraction). 0 si réflexion totale. lit(NL,NH,ns) retourne (ambient,diffuse,speculaire,1) où ambient=1 diffus=(NL<0 ? 0 : NL) speculaire=(NL<0 || NH<0 ? 0 : pow(NH,ns)) faceforward(U,V,N) renvoie –N.sign(dot(V.N)) HLSL U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E fonctions exp(x) exponentielle exp2(x) 2x pow(x,y) xy sqrt(x) √x rsqrt(x) 1 / √x log(x) logarithme sin(x) sinus cos(x) cosinus tan(x) tangente log2(x) logarithme en base 2 sincos(x,a,b) au retour: a=sin(x),b=cos(x) log10(x) logarithme en base 10 asin(x) arc-sinus ldexp(x,y) x . 2y acos(x) arc-cosinus frexp(x,y) mantisse de x, y=exposant de x atan(x) arc-tangente (ri∈[-π/2,+π/2]) atan2(x,y) arc-tangente (ri∈[-π,+π]) sinh(x) sinus hyperbolique cosh(x) cosinus hyperbolique tanh(x) tangente hyperbolique radians(x) conversion degrés→radians degrees(x) conversion radians →degrés saturate(x) borne x dans l’intervalle [0,1]. clamp(x,a,b) borne x dans l’intervalle [a,b]. step(x,y) (yi >= xi ? 1 : 0) smoothstep(a,b,x) 0 si xi<ai, 1 si si x1>bi, interpolation d’hermite entre 0 et 1 sinon. sign(x) signe (-1,0,+1) abs(x) valeur absolue ceil(x) plus petit entier supérieur floor(x,y) plus grand entier inférieur round(x) entier le plus proche frac(x) partie fractionnaire fmod(x) reste de la division entière modf(x,y) retourne la partie fractionnaire, y contient au retour la partie entière. max(x,y) maximum par composante min(x,y) minimum par composante HLSL U N IVERSIT É D E R EIMS Textures et sampler C H AMP AGN E-A RD EN N E Déclaration d’une variable de type sampler (en global seulement): samplerX : échantillonneur de type texture X = 1D, 2D, 3D ou CUBE (sampler=sampler2D). Exemple: sampler2D wood; // déclare le sampler 2D nommé « wood ». Configuration du sampler: configuration directe des caractéristiques du sampler associé à la variable. Exemple: sampler normal_sampler = sampler_state { Texture = (Texture1); // utile pour les annotations (voir la leçon sur les effets) MinFilter = LINEAR; // = SetSamplerState(x, D3DSAMP_MINFILTER, D3DTEXF_LINEAR) MagFilter = LINEAR; MipFilter = LINEAR; }; Tous les états du sampler sont configurables à savoir: – – pour AddressU AddressV AddressW MagFilter MinFilter MipFilter, utiliser les énumérations associées sans le préfixe. pour BorderColor MaxAnisotropy MaxMipLevel MipMapLodBias SRGBTexture, utiliser directement les valeurs (float4 pour les couleurs). HLSL U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Textures et sampler (2) Etage de texture associé à une variable de type sampler: Deux possibilités: • l’ordre détermine l’étage (au premier sampler déclaré est associé l’étage 0, …). • la déclaration suivante permet d’affecter l’étage de texture x (registre sx) au sampler var: sampler var : register(sx); Fonctions d’échantillonnage de textures: tex1D(s,t) 1.1 valeur de la texture 1D s aux coordonnées t. tex2D(s,t) 1.1 valeur de la texture 2D s aux coordonnées t. tex3D(s,t) 1.1 valeur de la texture 3D s aux coordonnées t. texCUBE(s,t) 1.1 valeur de la texture CUBE s aux coordonnées t. tex*proj(s,t) 2.0 = tex* avec projection (= division de t par t.w). tex*bias(s,t) 2.0 = tex* avec MipMap biaisé (biais = t.w). tex*grad(s,t,ddx,ddy) 2.0 = tex* avec MipMap utilisant le gradient (ddx,ddy). tex*lod(s,t) 3.0 = tex* avec MipMap (lod = t.w) PS : cf version VS≥3.0 : tex*lod HLSL U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Contrôle de flux Tests Boucles if (test) instr1; if (test) {…} if (test) instr1; else instr2; if (test) {…} else {…} for(int i=i0; i<in; i++) {…} do { …} while (test); while (test) { …}; Remarques • • • sur les profils (VS/PS) ne supportant pas les boucles, elles sont déroulées. sur les modèles ne supportant pas les tests, le then et le else sont tous deux évalués. les limitations des « flow controls » du modèle cible s’appliquent. En tenir compte lors de l’écriture du code HLSL. HLSL U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Fonctions Syntaxe: rtype fname(type1 var1, …, typen varn) { … return val; } Remarques: • • • pour obtenir une procédure: le type de retour est void (dans ce cas, pas de return). s’il n’y a pas d’argument, la liste des arguments est void. par défaut, les paramètres sont passés par valeur. Ce comportement peut être changé en ajoutant au type les mots-clés: in, out ou inout. in : passage par valeur (défaut). Si changement, pas de répercussion sur la variable d’appel. out : paramètre de sortie, il doit être affecté dans la fonction. inout : passage par référence. Il peut être modifié lors de la fonction, la modification est répercutée sur la variable d’appel. • par défaut, le point d’entrée d’un VS ou d’un PS est la fonction nommée main. HLSL U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Entrées/sorties (1) : sémantique • Vertex Shader input: POSITION[n] position BLENDWEIGHT[n] output: POSITION position poids pour le blending PSIZE taille des points BLENDINDICES[n] indices pour le blending FOG brouillard NORMAL[n] vecteur normal COLOR[n] couleurs PSIZE[n] taille des points TEXCOORD[n] coordonnées de texture COLOR[n] couleurs (diffuse,spéculaire) 11 registres float4 + 1 float (PSIZE) au plus. TEXCOORD[n] coordonnées de texture TANGENT[n] tangente BINORMAL[n] binormal TESSFACTOR[n] facteur de décomposition. pour un total de 16 registres float4 au plus. sémantique = celle du FVF. Sémantique autorisée = celle possible dans les VS et PS avec les limitations indiquées ici (notamment les restrictions sur la sortie des VS et l’entrée des PS). • Pixel Shader input: COLOR[n] couleur TEXCOORD[p] texture 10 registres float4 au plus output: COLOR[n] couleur (n=0…3) DEPTH[n] profondeur (n=0) HLSL U N IVERSIT É D E R EIMS Entrées/sorties (2) : format C H AMP AGN E-A RD EN N E FVF • POSITION[n] BLENDWEIGHT[n] BLENDINDICES[n] NORMAL[n] PSIZE[n] COLOR[n] TEXCOORD[n] TANGENT[n] BINORMAL[n] TESSFACTOR[n] Vertex Shader COLOR[n] TEXTURE[n] Pixel Shader COLOR[n] DEPTH POSITION PSIZE FOG Vertex Shader entrée: fixé avec SetFVF ou SetVertexDeclaration. sortie: fixé dans le Vertex Shader (contient au moins POSITION). • Pixel Shader entrée: celui en sortie du Vertex Shader, POSITION, PSIZE et FOG en moins. sortie: fixé dans le Pixel Shader (contient au moins COLOR). Remarque: les champs précisés ici indiquent ceux qui sont utilisables (il n’est pas nécessaire d’utiliser tous les champs disponibles). HLSL U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Structure d’un Vertex/Pixel Shader La structure d’un vertex shader comporte en général: • la déclaration des variables globales. • la déclaration de la structure d’entrée du VS avec sa sémantique. • la déclaration de la structure de sortie du VS avec sa sémantique. • la fonctions appelées par le VS. • la fonction principale (point d’entrée) du VS avec pour paramètre d’entrée la structure d’entrée et renvoie la structure de sortie. Pour un Pixel Shader : pareil. Note importante pour les VS: veillez à ce que la coordonnée w contienne 1 avant la transformation d’une sommet. Exemple: VS minimal (vs1.fx) // variables globales float4x4 MGlobViewProj; // structure d’entrée du VS struct VSin { float4 pos : POSITION; // i.e. passer un float4 avec w=1 }; // structure de sortie du VS struct VSout { float4 pos : POSITION; } // fonction principale VSout main(VSin In) { VSout Out; Out.pos = mul(In.pos,MGlobViewProj); return Out; } HLSL U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E commentaires et préprocesseur • commande du préprocesseur (idem C++) voir: #define, #undef, #if, #ifdef, #ifndef, #else, #elif, #endif, #include, #line, #pragma, #error. particularités: #pragma def(vs_2_0, c0, 1,2,3,4) si le code HLSL est compilée en VS2, la ligne suivante est ajoutée au code: def c0,1,2,3,4 #pragma warning( mode : warnum ) indique comment traiter le warning numéro warnum où mode est parmi: once : n’afficher qu’une seule fois ce warning. defaut : comportement par défaut. disable : déactiver ce warning. error : ce warning provoque une sortie sur erreur. • commentaires: les formes C et C++ sont utilisables. // commentaires jusqu’à la fin de la ligne /* commentaires de là à là */ U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E chargement et compilation d’un code HLSL: méthode manuelle (1) Un code HLSL est souvent créé sous forme d’un fichier texte (ex: myshader.fx). La compilation se fait en deux phases: • compilation du code HLSL avec fxc.exe : on obtient un code assembleur (vsh ou psh suivant les cas. Dans l’exemple ci-dessous, le code assembleur myshader.vsh est créé). C:\DX90SDK\Utilities> fxc /T:vs_2_0 /E:VSmain /Fc:myshader.vsh myshader.fx Microsoft (R) D3DX9 Shader Assembler 4.09.00.1126 Copyright (C) Microsoft Corporation 2002-2003. All rights reserved. assembly succeeded; see myshader.vso • compilation du code assembleur pour obtenir le code objet (avec psa.exe ou vsa.exe suivant les cas ou l’API, cf le cours ASM). Les principales options de fxc.exe sont les suivantes: /T:profil profil = type de code assembleur à générer (vs_2_0, ps_2_0, …) /E:name name = nom de la fonction d’entrée (défaut = main). /Fo:objcode objcode = nom du fichier objet généré. /Fc:asmcode asmcode = nom du fichier assembleur généré. /Od ne pas optimiser le code généré. Important: toujours compiler le code final au moins une fois à la main, et lire le code ASM: 1. 2. vérifier que le code assembleur obtenu est conforme à ce qui est attendu. récupérer la table des constantes à fixer à travers l’API DirectX. U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E chargement et compilation d’un code HLSL: méthode manuelle (2) Exploitation de la sortie du compilateur fxc: C:\Devel\DirectX9\Utilities\test>..\fxc /T:vs_2_0 vs1.fx Microsoft (R) D3DX9 Shader Compiler 4.09.00.1126 Copyright (C) Microsoft Corporation 2002-2003. All rights reserved. // // Generated by Microsoft (R) D3DX9 Shader Compiler 4.09.00.1126 // // fxc /T:vs_2_0 vs1.fx // // // Parameters: // // float4x4 MGlobViewProj; // // // Registers: // // Name Reg Size // ------------- ----- ---// MGlobViewProj c0 4 // vs_2_0 dcl_position v0 dp4 oPos.x, v0, dp4 oPos.y, v0, dp4 oPos.z, v0, dp4 oPos.w, v0, c0 c1 c2 c3 // approximately 4 instruction slots used C:\Devel\DirectX9\Utilities\test> Commande utilisée pour compiler ce code Variables globales déclarées dans le code HLSL et utilisées par le shader. Table des constantes associées aux variables globales avec les infos nécessaires pour les fixer dans l’API (SetVertexShaderConstant*). Les valeurs par défaut sont précisées s’il y en a. code ASM du vertex shader U N IVERSIT É D E R EIMS Chargement et compilation d’un code HLSL: utilisation de l’API C H AMP AGN E-A RD EN N E La fonction D3DXCompileShaderFromFile permet de charger et compiler un code HLSL: D3DXCompileShaderFromFile(fname, NULL, NULL, entry, profil, flags, &pShaderBuf, &pErrMsg , &pCstTable) fname : nom du fichier contenant le code HLSL. entry : chaîne contenant de la nom la fonction d’entrée (en général, "main“) profil : chaîne définissant le profil (au besoin, utiliser D3DXGetPixelShaderProfile). Vertex Shader: vs_1_1, vs_2_0, vs_2_a, vs_2_sw (cf D3DXGetVertexShaderProfile). Pixel Shader: ps_1_1, ps_1_2, ps_1_3, ps_1_4, ps_2_0, ps_2_a, ps_2_b, ps_2_sw (cf D3DXGetPixelShaderProfile). flags : flag de compilation 0 ou D3DXSHADER_DEBUG (mode debug). cf doc. pShaderBuf [out] pointeur sur le code objet du shader (type=LPD3DXBUFFER). pErrMsg [out] NULL ou message d’erreurs à l’issu de la compilation (type=LPD3DXBUFFER). pCstTable [out] NULL ou la table (type=LPD3DXCONSTANTTABLE). • En fonction du profil, on génère: – – • • • soit le code objet d’un vertex shader (fxc + vsa). soit le code objet d’un pixel shader (fxc + psa). Cette fonction renvoit un HRESULT (à tester pour savoir si la compilation a échouée). La méthode GetBufferPointer() de D3DXBUFFER permet de récupérer le pointeur du buffer qui contient le code objet du shader (pShaderBuf) ou le texte du message d’erreur créé (pErrMsg). La table de constantes donne un moyen symbolique de fixer les constantes du shader (voir la partie sur le passage de variables). Ne pas oublier de libérer cette interface (SAFE_RELEASE). U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Création et utilisation d’un shader La méthode est la même que celle vue dans le cours ASM: Vertex Shader: Création de l’interface vertex shader: ou avec la méthode du Device CreateVertexShader(pShaderObj,pShader) où pShaderObj est le code objet, et pShader le pointeur sur l’interface du Vertex Shader à créer. Utilisation d’un vertex shader avec la méthode du Device SetVertexShader(pShader) où pShader est le pointeur sur l’interface du Vertex Shader créé avec CreateVertexShader ou NULL pour rétablir le VS du pipeline graphique fixe. Pixel Shader: Création de l’interface pixel shader: ou avec la méthode du Device CreatePixelShader(pShaderObj,pShader) où pShaderObj est le code objet, et pShader le pointeur sur l’interface du Pixel Shader à créer. Utilisation d’un pixel shader avec la méthode du Device SetPixelShader(pShader) où pShader est le pointeur sur l’interface du Pixel Shader créé avec CreateVertexShader ou NULL pour rétablir le PS du pipeline graphique fixe. Remarque: remplacer un code ASM par un code HLSL consiste donc à remplacer D3DXAssembleShaderFromFile par D3DXCompileShaderFromFile (attention quand même au passage de variables). HLSL U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E • Passage de variables à un VS/PS (1) Par registre (cas classique) utilisation des méthodes du Device SetVertexShaderConstantx (pour un VS) ou SetPixelShaderConstantx (pour un PS). Voir le cours ASM. on peut s’aider en cela de la table des registres et des paramètres en sortie de fxc. • Par symbole (utilisation de la table des constantes) les constantes sont définies avec leurs noms symboliques définis dans le code HLSL (nommés sname par la suite) en utilisant la table des constantes pCstTable (obtenues dans le dernier paramètre de D3DXCompileShaderFromFile). Les méthodes de pCstTable pour initialiser les constantes sont: SetBool(pDEV,sname,B) : initialise le booléen sname à B. SetInt(pDEV,sname,N) : initialise le flottant sname à N. SetFloat(pDEV,sname,F) : initialise le flottant sname à F. SetVector(pDEV,sname,pF) : initialise le vecteur flottant 4D sname à pF (D3DXVECTOR4*). SetMatrix(pDEV,sname,pM) : initialise la matrice sname à pM (D3DXMATRIX*, non transposée). SetMatrixTranspose(pDEV,sname,pM) : initialise la matrice sname à pM (D3DXMATRIX*, déjà transposée). SetValue(pDEV,sname,pD,n) : initialise la structure sname à pF (LPCVOID) dont la taille est n bytes. (voir aussi des méthodes pour les tableaux dans la documentation de la méthode ID3DXConstantTable). La totalité du code (HLSL + API) n’utilise ainsi plus que des noms symboliques. HLSL U N IVERSIT É D E R EIMS Passage de variables à un VS/PS (2) C H AMP AGN E-A RD EN N E Exemple: on reprend le cas du VS minimal: HLSL API : passage de variables au shader par registre // vs1.fx // variables globales float4x4 MGlobViewProj; … // matrice complète de transformation MFull = MWorld * MView * MProj; // transposée pour passer au shader D3DXMatrixTranspose(&TMFull,&MFull); // Fixe les constantes // Matrice de transformation complete (c0,4 float4) pDEV->SetVertexShaderConstantF(0,(float *)&TMFull,4); fxc ASM // Parameters: // float4x4 MGlobViewProj; // // Registers: // Name Reg Size // ------------- ----- ---// MGlobViewProj c0 4 … API : passage de variables au shader par symbole // matrice complète de transformation MFull = MWorld * MView * MProj; // pCstTable est le dernier paramètre de D3DXCompileShaderFromFile // Matrice de transformation complete nommée MGlobViewProj // dans le code HLSL. // La matrice est transposée lors de l’appel à SetMatrix pCstTable->SetMatrix(pDEV, "MGlobViewProj“ ,&TMFull); La sortie de fxc donne des indications claires pour l’API. HLSL U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Forçage des variables assembleur Le modificateur register permet de spécifier les constantes ou les samplers à utiliser lors de la génération du code assembler. Cette spécification permet donc: – de fixer les constantes – de fixer les étages de texture. qui seront utilisés par le shader et à initialiser dans le code directX Exemple: • code HLSL float4x4 matWorldViewProj : register(c0); float4 scaleFactor : register(c4); sampler damier : register(s0); • // c0-c3 = matWorldViewPro // c4 = scaleFactor // damier : à charger dans l’étage 0 code DirectX pDEV->SetVertexShaderConstantF(0,(float *)&TMFull,4); pDEV->SetVertexShaderConstantF(4,(float *)&Scale,1); pDEV->SetTexture(0,pTX0); // charger la texture damier dans pTX0 Note: la table des constantes permet de récupérer également toutes les informations sur les constantes et les samplers utilisés dans un code HLSL. HLSL U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E • • Règles d’écriture d’un code choix du profil de compilation: utiliser la version PS/VS supportée par la carte sinon: ver. profil > ver. carte : exécution en SW. ver. profil < ver. carte : risque d’émulation. Instr. Cst. Tmp. vs_1_1 ≥128 ≥96 12 vs_2_0 256 ≥256 12 vs_2_a 256 ≥256 13 vs_2_sw ∞ 8192 8192 vs_3_0 ≥512 ≥256 ≥256 ps_1_1 à 1_3 12 8 8 rappel: ps_1_4 28 8 8 – ps_2_0 96 32 12 ps_2_a 512 32 22 ps_2_b 512 32 32 ps_2_sw ∞ 8192 8192 ps_3_0 ≥512 224 32 ps_3_sw ∞ 8192 8192 voir les caractéristiques des « flowcontrol » du profil de compilation pour savoir ce qu’il est possible d’écrire. si les boucles ne sont pas supportées: elles sont déroulées. – si le flow-control dynamique n’est pas supporté, le then et le else sont tous les deux évalués. Le code obtenu peut alors ne pas tourner avec le profil choisi (voir table ci-contre). • toujours lire le code assembleur généré. HLSL U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Exemple: ombrage de Phong Code HLSL du Vertex Shader // variables globales float4x4 MGlobViewProj; float4 LightPos; // fonction principale VSout VSmain(VSin In) { VSout Out=(VSout)0; // structure d’entrée du VS struct VSin { float4 position : POSITION; float4 normal : NORMAL; float4 color : COLOR; float2 coordtx : TEXCOORD0; }; // transformation Out.transpos = mul(In.position,MGlobViewProj); // donnees passees directement au PS Out.color = In.color; Out.coordtx = In.coordtx; // direction de la source de lumiere float4 LDir; LDir = normalize(LightPos - In.position); // structure de sortie du VS struct VSout { float4 transpos : POSITION; float4 color : COLOR; float2 coordtx : TEXCOORD0; float3 normal : TEXCOORD1; float3 lightdir : TEXCOORD2; float3 position : TEXCOORD3; }; // geometrie Out.normal Out.lightdir Out.position passee au PS pour interpolation = In.normal; = LDir; = In.position; code ASM obtenu // fxc /T:vs_2_0 /E:VSmain // // Parameters: // float4 LightPos; // float4x4 MGlobViewProj; // // Registers: // Name Reg Size // ------------- ----- ---// MGlobViewProj c0 4 // LightPos c4 1 // vs_2_0 dcl_position v0 dcl_normal v1 dcl_color v2 dcl_texcoord v3 dp4 oPos.x, v0, c0 add r0, -v0, c4 dp4 oPos.y, v0, c1 dp4 r0.w, r0, r0 dp4 oPos.z, v0, c2 rsq r0.w, r0.w dp4 oPos.w, v0, c3 mul oT2.xyz, r0, r0.w mov oD0, v2 mov oT0.xy, v3 mov oT1.xyz, v1 mov oT3.xyz, v0 return Out; } // approximately 12 instruction slots used code ASM obtenu HLSL U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Exemple: ombrage de Phong Code HLSL du Pixel Shader // variables globales float4 LightColor; float ns; float3 ObsPos; // fonction principale PSout PSmain(PSin In) { PSout Out=(PSout)0; float4 N,L,V,R; float4 MatColor,Ld,Ls; // texture de l'etage 0 sampler2D damier; // calcul de la geometrie N = normalize( float4(In.normal,0) ); L = normalize( float4(In.lightdir,0) ); V = normalize( float4(ObsPos-In.position,0) ); R = - reflect(L,N); // structure d'entree du PS struct PSin { float4 color : COLOR; float2 coordtx : TEXCOORD0; float3 normal : TEXCOORD1; float3 lightdir : TEXCOORD2; float3 position : TEXCOORD3; }; // structure de sortie du PS struct PSout { float4 color : COLOR; }; // couleur et texture du materiaux MatColor = In.color*tex2D(damier,In.coordtx); // calcul de la sortie Ld = dot(N,L); // diffus Ls = pow(max(dot(R,V),0),ns); // speculaire Out.color = LightColor*( MatColor * Ld + Ls ); return Out; } // fxc /T:ps_2_0 /E:PSmain // // Parameters: // float4 LightColor; // float3 ObsPos; // sampler2D damier; // float ns; // // Registers: // Name Reg Size // ------------ ----- ---// LightColor c0 1 // ns c1 1 // ObsPos c2 1 // damier s0 1 // ps_2_0 def c3, 0, 0, 0, 0 dcl v0 dcl t0.xy dcl t1.xyz dcl t2.xyz dcl t3.xyz dcl_2d s0 texld r0, t0, s0 mov r1.xyz, t1 mov r1.w, c3.x dp4 r2.w, r1, r1 rsq r2.w, r2.w mul r1, r1, r2.w mov r2.xyz, t2 mov r2.w, c3.x dp4 r3.w, r2, r2 rsq r3.w, r3.w mul r2, r2, r3.w dp4 r3.w, r2, r1 add r4.w, r3.w, r3.w mad r1, r1, -r4.w, r2 add r2.xyz, -t3, c2 mov r2.w, c3.x dp4 r4.w, r2, r2 rsq r4.w, r4.w mul r2, r2, r4.w dp4 r1.w, -r1, r2 max r2.w, r1.w, c3.x pow r1.w, r2.w, c1.x mul r0, r0, v0 mad r0, r0, r3.w, r1.w mul r0, r0, c0 mov oC0, r0 // approximately 28 instruction slots used (1 texture, 27 arithmetic) Génération de textures U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Texture Shader D3DX propose des fonctions pour générer (offline) des textures avec un PS sur le GPU. Fonctions disponibles: D3DXFillTextureTX, D3DXFillCubeTextureTX, D3DXFillVolumeTextureTX (pendant des fonctions de génération de texture D3DXFill*Texture sur le CPU). Elles prennent en entrée la texture à remplir (créée avec Create*Texture). Particularité du SM utilisé (texture shader) Profil de compilation: tx_1_0 (texture shader) Paramètres d’entrée: floatn POSITION : coordonnées de la texture à générer (n dépend du type de texture). floatn PSIZE : ??? (pas d’info, mais a priori, taille du point). Paramètre de sortie: float4 COLOR : la couleur de la texture à cette position. Passage de constantes: n float4 peuvent être passées au shader (2 derniers paramètres de D3DXFillTexture*TX) correspondants aux constantes c0,…,cn-1. déclarer les constantes dans le code HLSL et vérifier les affectations avec la table des constantes générées par fxc. Fonctions HLSL supplémentaire: noise(x) : génère un bruit de Perlin. Lectures et exercices U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Lectures: DirectX 9, K. Gray chapitres 6, 7 et 8. ShaderX2 - Introduction & Tutorials, W.F. Engel chapitre 1 Introduction to 3D Game Programming, F.D. Luna chapitre 16, 17 et 18 Programming Vertex & Pixel Shaders - W.F. Engel excellent livre qui couvre la majorité des shaders HLSL classiques. Exercices: réécrire les codes d’exemple ASM de la leçon 7 en HLSL. On comparera les codes ASM obtenus. Techniques de programmation: ShaderX2, ShaderX3 - W.F. Engel
Documents pareils
Télécharger la version PDF
[β] produit vecteur du α-D (u) et
matrice αxβ (v) résultat stocké dans
les β premières coordonnées de d.
le ième coordonnées de d contient le
produit scalaire α -D entre u et vk+i.
défini pour les ...
Imagerie Numérique Rapport de projet sur le motion blur
in float2 texCoord : TEXCOORD,
uniform float4x4 WVProj,
out float4 wpos : POSITION,
out float2 texCoord0 : TEXCOORD0,
out float2 texCoord1 : TEXCOORD1)