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

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 ...

Plus en détail

Imagerie Numérique Rapport de projet sur le motion blur

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)

Plus en détail