Forum |  HardWare.fr | News | Articles | PC | Prix | S'identifier | S'inscrire | Aide Recherche
1861 connectés 

  FORUM HardWare.fr
  Programmation
  C#/.NET managed

  [XNA, HLSL][Résolu] Paramètres shader génériques

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

[XNA, HLSL][Résolu] Paramètres shader génériques

n°1942589
Stnaire
Posté le 19-11-2009 à 22:42:27  profilanswer
 

Bonjour,
 
Je me retrouve une nouvelle fois devant un problème que je n'arrive pas a résoudre proprement.
Dans la réalisation de mon petit moteur 3D j'aimerai gérer une quantité n de matériaux différents.
 
Chaque matériau doit être facilement applicable à un modèle et décrit à l'aide d'un fichier .xml et d'un fichier .fx.
 
Le soucis est que dans cette optique, je ne connais ni le type, ni le nombre de variables qui seront à transmettre à la carte graphique, hormis les classiques matrices monde, vue, projection et les paramètres d'éclairage.
 
Par exemple, dans le cas d'un shader d'eau, j'ai un bon nombre de variable à passer :
 
- 2 textures : les maps de reflection et refraction.
- Plusieurs vecteurs : direction du vent, hauteur des vagues & co.
- des floats : comme par exemple le temps écoulé depuis la dernière frame.
 
Tout ces paramètres sont simple à passer en dur, mais j'aimerai ne pas m'amuser a faire une classe par matériau, l'idée de les ajouter via l'éditeur, au clic.
 
Donc au risque de me répéter, il faudrait que tout ces paramètres soit entièrement décrit dans un fichier de matériaux (un .xml dans mon cas).
 
Voici la ligne permettant d'ajouter un paramètre de façon classique (ici la couleur de l'eau) :

Code :
  1. this.effect.Parameters["xWaterColor"].SetValue(this.waterColor);


 
Le soucis est que SetValue() n'aime pas du tout les types génériques, elle possède une surcharge pour chaque type supporté.
 
J'ai donc pensé à une solution que je trouve TRÈS moche que voici :

Code :
  1. private SerializableDictionary<string, float> floatList     = new SerializableDictionary<string, float>();
  2. private SerializableDictionary<string, int> intList         = new SerializableDictionary<string, int>();
  3. private SerializableDictionary<string, Vector2> vector2List = new SerializableDictionary<string, Vector2>();
  4. [...]


 
Pour chaque type de paramètres supporté, j'ai un dictionnaire décrit dans le XML.
La clef du dictionnaire correspond au nom de la variable dans code HLSL, et la valeur, la valeur à passer.
 
D'une c'est moche, et absolument pas souple, ici pas de support de variables changeant au runtime (comme par exemple le temps), ce ne sont que des valeurs statiques et décrites de façon très lourde.
 
Voila j'espère ne pas avoir faire trop long, si l'un de vous à une solution plus souple et rapide je lui en serai fortement reconnaissant !
 
Merci :)


Message édité par Stnaire le 21-11-2009 à 00:28:19
mood
Publicité
Posté le 19-11-2009 à 22:42:27  profilanswer
 

n°1942621
Fred82
Posté le 20-11-2009 à 01:38:48  profilanswer
 

Je n'ai pas vraiment compris ce que tu cherches à faire, ni quel est ton problème, mais en même temps il se fait tard :o
 
Je me dis qu'il y a bien un moment où ton programme ne fera pas tout à ta place, il y aura forcément du travail :D
 
Si j'ai bien compris, il faut passer des paramètres grâce à cette ligne :
this.effect.Parameters["xWaterColor"].SetValue(this.waterColor);
 
Et si j'ai bien compris tu pars notamment d'un fichier XML.
J'imagine que ton fichier XML contient d'une part le nom du paramètre "xWaterColor", et sa valeur, de type float, int, Vector2...
 
Ben facile, non ?
 
Tu lis le fichier XML, tu récupères chaque paramètre, avec son nom, tu castes suivant le type, et tu remplis ta collection this.effect.Parameters.
 
Il doit me manquer une info, c'est plus compliqué que cela peut-être, mais je ne vois pas, mais en même temps il est tard. [:dodo]


---------------
Vos smileys favoris sur HFR : Script Greasemonkey / Topic HFR officiel
n°1942623
Stnaire
Posté le 20-11-2009 à 02:10:56  profilanswer
 

Alors, salut et merci pour ta réponse.
 
Ce que je cherche a faire, c'est une implémentation propre.
Effectivement mon fichier XML contiendra de toute façon, une pair clef - valeur agrémentée d'un type.
 
Exemple :
 

Code :
  1. <Item>
  2.    <Key>WaterColor</key>
  3.    <Value>
  4.       <Vector4>
  5.          <X>.2f</X>
  6.          <Y>.1f</Y>
  7.          <Z>.6f</Z>
  8.          <W>1</W>
  9.       </Vector4>
  10.    </Value>
  11. </Item>


 
J'ai donc bien une pair clef - valeur.
La clef est "WaterColor" qui correspond au nom de la variable HLSL.
La valeur est contenu dans un Vector4.
 
Le problème c'est que pour avoir ce type de structure dans le XML il faut que j'ai le type de code que j'ai posté dans mon 1er message pour le recevoir, il faut bien que j'ai en dur dans mon code un  

Code :
  1. Dictionary<string, Vector4> vector4List;


 
 
Je suis oblige d'avoir ca pour chacun des types et je trouve simplement ca moche.
L'ideal serait un truc du genre :
 

Code :
  1. Dictionary<string, object> paramsList;


 
Le probleme c'est que je ne peux pas passer a SetValue() directement un type object, il faut le caster.
Et pour le caster je dois tester le type..
 

Code :
  1. if (paramsList.ElementAt(i).Value is Vector4)
  2.    this.effect.Parameters[paramsList.ElementAt(i).Key].SetValue((Vector4)paramsList.ElementAt(i).Value);


 
Je trouve ca encore plus moche que parcourir chacun des dictionnaires de type.
 
Voila, donc le probleme n'est pas vraiment "Comment le faire fonctionner", mais comment le rendre réellement générique, car pour moi tout ca reste encore plus ou moins en dur.
 

n°1942900
Fred82
Posté le 20-11-2009 à 17:50:13  profilanswer
 

Tu devras forcément traiter chaque type indépendamment, ton SetValue() ne prend pas de type object, tu n'as pas le choix.
 
C'est quoi d'aileurs this.effect.Parameters comme type de donnée ? C'est une collection ? Tu es sûr qu'il n'y a pas un point d'entrée en type object ?
 
Autrement, attention à ne pas répéter un même accès plusieurs fois
 

Code :
  1. if (paramsList.ElementAt(i).Value is Vector4)
  2. this.effect.Parameters[paramsList.ElementAt(i).Key].SetValue((Vector4)paramsList.ElementAt(i).Value);


 
Tu fais accès à paramsList.ElementAt(i) 3 fois alors qu'il vaudrait mieux le conserver dans une variable intermédiaire. Mais c'est peut-être pour l'exemple que tu as écris ça, ok :)
 
C'est quoi paramsList sinon ??
 
Et si Value est de type object, tu n'as pas le choix !! Obligé de faire un "is".
 
En fait pour conclure, je ne vois toujours pas vraiment ce que tu cherches à faire, et dans quel ordre surtout !
Tu cherches à lire un fichier XML ? A l'écrire ? D'où viennent tes données d'entrée que tu cherches à traiter ? C'est très flou !


---------------
Vos smileys favoris sur HFR : Script Greasemonkey / Topic HFR officiel
n°1942919
Stnaire
Posté le 20-11-2009 à 18:35:59  profilanswer
 

Fred82 a écrit :


C'est quoi d'aileurs this.effect.Parameters comme type de donnée ? C'est une collection ? Tu es sûr qu'il n'y a pas un point d'entrée en type object ?


 
C'est un type Effect, maintenant je connais que cette façon d'assigner un paramètre HLSL, si il y a un moyen plus générique je suis curieux de le connaitre.
 
 

Fred82 a écrit :


Autrement, attention à ne pas répéter un même accès plusieurs fois
 

Code :
  1. if (paramsList.ElementAt(i).Value is Vector4)
  2. this.effect.Parameters[paramsList.ElementAt(i).Key].SetValue((Vector4)paramsList.ElementAt(i).Value);


 
Tu fais accès à paramsList.ElementAt(i) 3 fois alors qu'il vaudrait mieux le conserver dans une variable intermédiaire. Mais c'est peut-être pour l'exemple que tu as écris ça, ok :)


 
C'était bien sur pour l'exemple, j'ai codé ca sur le forum pendant la rédaction du message, l'idée ici était de présenter le problème pas d'optimiser :)
 

Fred82 a écrit :


C'est quoi paramsList sinon ??


 
Il est défini juste au dessus dans mon précédent message :

Code :
  1. Dictionary<string, object> paramsList;


 

Fred82 a écrit :


En fait pour conclure, je ne vois toujours pas vraiment ce que tu cherches à faire, et dans quel ordre surtout !
Tu cherches à lire un fichier XML ? A l'écrire ? D'où viennent tes données d'entrée que tu cherches à traiter ? C'est très flou !


 
Bah je sais pas quoi te dire..  
 
Je vais avoir en entrée un XML chargé de décrire un matériau, ce matériau utilisera un fichier .fx qui demandera des variables à assigner dans le code XNA.
Le but était d'éviter de faire 50 000 dictionnaire comme je l'ai présenté dans mon 1er message, et d'éviter de faire un switch avec des "is" de 100 lignes pour tester chaque type.
 
Maintenant si c'est trop complexe ca en devient inutile, simplement si une solution simple existe j'aurai aimé la connaitre.

n°1942933
Fred82
Posté le 20-11-2009 à 19:21:37  profilanswer
 

Donc si je comprends bien, ton process, c'est :
1) Lecture du fichier XML
2) Lecture du fichier .fx
3) Assignation dans le code XNA
 
Par conséquent, si c'est bien ça, quand tu lis le fichier XML, tu connais le type de chaque donnée vu qu'il y est codé. Donc pas besoin de "is".
Tu peux faire directement
Vector4 valeur = <valeur du fichier XML>
string nom_cle = <valeur du fichier XML>
this.effect.Parameters[nom_cle]SetValue(valeur);
 
Et ceci tu le fais en boucle dans le fichier XML. Et pareil dans le .fx peut-être (dont je ne connais pas la structure)
 
C'est plus compliqué que ça ? Pas besoin de liste intermédiaire... Et si le besoin se fait sentir, faire un dictionnaire <string, Vector4> n'est pas la mort, t'en a beaucoup de types différents (combien ?) ? Mais de toute façon tu n'as pas le choix, il faudra traiter les types un par un, faut pas rêver. Mais pas besoin de "is", vu que tu connais le type quand tu lis le fichier XML. Il aurait fallu que SetValue soit générique, mais ce n'est pas le cas. Ce n'est pas ton code ce SetValue.


---------------
Vos smileys favoris sur HFR : Script Greasemonkey / Topic HFR officiel
n°1942966
Stnaire
Posté le 20-11-2009 à 21:37:16  profilanswer
 

Hum, le XML je le déserialise qu'on soit bien d'accord, j'aurais peut-être du etre plus clair la dessus dès le début.
 
Donc vu que je le déserialise je suis obligé d'avoir la représentation de la structure du XML en code C# pour reconstruire un objet.
 
D'ou mes listes pour chaque type.
 
Un exemple du genre de XML que j'utilise :
 

Code :
  1. <?xml version="1.0"?>
  2. <Dictionary>
  3.   <Item>
  4.     <Key>
  5.       <string>Water</string>
  6.     </Key>
  7.     <Value>
  8.       <Material xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  9.         <AsReflection>false</AsReflection>
  10.         <AsRefraction>false</AsRefraction>
  11.         <FloatList>
  12.           <Item>
  13.             <Key>
  14.               <string>Water heights</string>
  15.             </Key>
  16.             <Value>
  17.               <float>12.24</float>
  18.             </Value>
  19.           </Item>
  20.           <Item>
  21.             <Key>
  22.               <string>Water speed</string>
  23.             </Key>
  24.             <Value>
  25.               <float>22.24</float>
  26.             </Value>
  27.           </Item>
  28.           <Item>
  29.             <Key>
  30.               <string>Water movement</string>
  31.             </Key>
  32.             <Value>
  33.               <float>112.24</float>
  34.             </Value>
  35.           </Item>
  36.         </FloatList>
  37.         <Vector2List>
  38.           <Item>
  39.             <Key>
  40.               <string>TexCoord</string>
  41.             </Key>
  42.             <Value>
  43.               <Vector2>
  44.                 <X>10</X>
  45.                 <Y>102.2</Y>
  46.               </Vector2>
  47.             </Value>
  48.           </Item>
  49.         </Vector2List>     
  50.       </Material>
  51.     </Value>
  52.   </Item>
  53. </Dictionary>


 
Chaque <Item> du 1er <Dictionary> décrit un matériau.
Ensuite à l'intérieur les variables sont classées par type, un dico par type.
La classe material est donc de la forme suivante :
 

Code :
  1. [Serializable]
  2. public class Material : IMaterial
  3. {
  4.         #region Fields
  5.         [NonSerialized, XmlIgnore]
  6.         private Effect effect;
  7.         private bool asReflection;
  8.         private bool asRefraction;
  9.         private SerializableDictionary<string, string> textureList      = new SerializableDictionary<string, string>();
  10.         private SerializableDictionary<string, float> floatList         = new SerializableDictionary<string, float>();
  11.         private SerializableDictionary<string, int> intList             = new SerializableDictionary<string, int>();
  12.         private SerializableDictionary<string, Vector2> vector2List     = new SerializableDictionary<string, Vector2>();
  13.         private SerializableDictionary<string, Vector3> vector3List     = new SerializableDictionary<string, Vector3>();
  14.         private SerializableDictionary<string, Vector4> vector4List     = new SerializableDictionary<string, Vector4>();
  15.         private SerializableDictionary<string, Matrix> matrixList       = new SerializableDictionary<string, Matrix>();
  16.         #endregion
  17.    [...]
  18. }


 
C'est un extrait des champs qu'utilise chaque matériaux.
A savoir que si 20 objets utilise le même matériau, ils utilisent la même instance, sinon bonjour la mémoire.


Message édité par Stnaire le 20-11-2009 à 21:41:00
n°1942972
Fred82
Posté le 20-11-2009 à 22:57:20  profilanswer
 

Ha ben parfait, super la sérialisation XML.

 

Ben avec la solution de la sérialisation XML, tu n'as pas le choix, tu dois écrire la structure C# qui décrit ton fichier XML. Mais c'est parfait, ça, quel est le problème ?

 

Tu dis ça :

Citation :

D'une c'est moche, et absolument pas souple, ici pas de support de variables changeant au runtime (comme par exemple le temps), ce ne sont que des valeurs statiques et décrites de façon très lourde.

 

Ben... pas le choix, ta structure C# doit décrire ton fichier XML, tu n'as pas d'autre choix que de la décrire. Et ta solution me semble très bien. Un fichier XML, c'est une normalisation. Si ton fichier XML ne respecte pas une norme, tu ne pourras pas le deviner. Sauf si tu prévois quelles libertés on peut se permettre dans le fichier XML. Mais ça je ne peux le deviner pour toi.

 

D'autre part, si tu retrouve les mêmes listes dans plusieurs types différents, tu peux faire de l'héritage afin d'éviter de réécrire chaque listes dans toutes les classes...

 

Bref... Je n'ai toujours pas compris le problème...

Message cité 1 fois
Message édité par Fred82 le 20-11-2009 à 22:57:44

---------------
Vos smileys favoris sur HFR : Script Greasemonkey / Topic HFR officiel
n°1942980
Stnaire
Posté le 20-11-2009 à 23:32:07  profilanswer
 

Fred82 a écrit :


D'autre part, si tu retrouve les mêmes listes dans plusieurs types différents, tu peux faire de l'héritage afin d'éviter de réécrire chaque listes dans toutes les classes...


 
Non ces listes sont uniquement décrites dans la classe Material, pas besoin d'héritage ici.
 

Fred82 a écrit :


Bref... Je n'ai toujours pas compris le problème...


 
Ce n'est vraiment un problème comme je pensais l'avoir expliqué, c'est simplement que j'étais "choqué" d'avoir à créer toutes ces listes et je pensais passer a coté d'une fonctionnalité du C# en étant obligé de faire comme ca.
 
Maintenant si aucune autre manière n'existe pas de problème je garde mes dicos, ca marchera ;)

n°1942982
Fred82
Posté le 20-11-2009 à 23:56:19  profilanswer
 

Moi ça ne me choque pas :p


---------------
Vos smileys favoris sur HFR : Script Greasemonkey / Topic HFR officiel
n°1942985
Stnaire
Posté le 21-11-2009 à 00:25:12  profilanswer
 

Fred82 a écrit :

Moi ça ne me choque pas :p


 
^^, je vais en rester là dans ce cas.
 
Merci beaucoup pour ton aide et pour le temps passé à me répondre :)

n°1942989
Fred82
Posté le 21-11-2009 à 00:37:41  profilanswer
 

Tiens j'ai pensé à un truc, tu peux écrire ceci :
 

Code :
  1. SerializableDictionary<string, int> floatList = new SerializableDictionary<string, int>();
  2. foreach (var paire in floatList)
  3. {
  4.    this.effect.Parameters[paire.Key].SetValue(paire.Value);
  5. }


---------------
Vos smileys favoris sur HFR : Script Greasemonkey / Topic HFR officiel
n°1943025
Stnaire
Posté le 21-11-2009 à 11:36:33  profilanswer
 

Fred82 a écrit :

Tiens j'ai pensé à un truc, tu peux écrire ceci :
 

Code :
  1. SerializableDictionary<string, int> floatList = new SerializableDictionary<string, int>();
  2. foreach (var paire in floatList)
  3. {
  4.    this.effect.Parameters[paire.Key].SetValue(paire.Value);
  5. }



 
Oui et il faut le faire pour chacun des dico ^^, mais bon ca a la mérite de fonctionner c'est déjà bien :)

n°1959020
PERECil
Posté le 20-01-2010 à 13:32:21  profilanswer
 

Dans XNA 3.0, il y a un Content Importer spécifique qui fait pile poil ce que tu cherches. Voir http://www.gulix.fr/blog/spip.php?article142


Message édité par PERECil le 20-01-2010 à 13:36:24
mood
Publicité
Posté le   profilanswer
 


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  C#/.NET managed

  [XNA, HLSL][Résolu] Paramètres shader génériques

 

Sujets relatifs
[Résolu][PHP] lecture d'objet XML en php[RESOLU] >>> Redirection vers une URL selon le mot de passe !
[Self-Résolu] Port Série (COM) et WriteFile()[GLSL - fragment shader] indéxer une texture
(résolu) Positionnement de footer[résolu][PHP/XML] lecture de fichier XML en PHP
[RESOLU] [AS2] Chemin[C] [resolu] lecture matrice alloué dynamiquement
Execution javascript et condition unique [resolu][Ruby] exécution d'une commande 'echo' avec ruby [résolu]
Plus de sujets relatifs à : [XNA, HLSL][Résolu] Paramètres shader génériques


Hit-Parade
Copyright © 1997-2012 Hardware.fr SARL / Groupe LDLC / LesNumeriques.com / Version anglaise du site: BeHardware