Utilisation de Vertex Buffers - C++ - Programmation
Marsh Posté le 04-10-2006 à 19:30:08
Est-ce que ca peut t'aider ?
http://nehe.gamedev.net/data/lesso [...] ?lesson=45
Marsh Posté le 04-10-2006 à 20:13:35
Merci, pour le lien !
Mais en fait, je connaissais. C'est a partir de NeHe que j'ai appris ce que je sais d'openGL...
- Bon par contre c'est vrai que c'est intéressant sur le fait du glDeleteBuffer() : il n'a pas l'air de l'utiliser après chaque affichage... Donc à priori, je peux me permettre dans une certaine mesure de conserver mes buffers.
- mais, il utilise encore une autre méthode (qui était décrite dans le document que j'avais trouvé...) qui consiste a utiliser deux buffer distinc pour l'affichage : un pour les vertices et un pour les coordonnées de textures. C'est toujours mieux qu'un array mais je pense que je vais essayer de regrouper au maximum mes donnée...
toujours est-il Merci de ta réponse !
Marsh Posté le 04-10-2006 à 21:39:20
le mieux est d'utiliser un indexbuffer (en plus):
http://www.blitzbasic.com/Communit [...] opic=47065
ça permet d'utiliser le cache post-T&L, et ainsi de reduire le nombre de vertexs a transformer par primitive.
Marsh Posté le 05-10-2006 à 14:28:39
Oui, c'est ce que je pensais faire.
Donc la méthode que j'ai choisie, c'est de tout mettre dans un même buffer, en donnant les tableaux en trois fois. Puis pour l'affichage j'utilisearai un index buffer.
Donc en gros y'a plus qu'a...
Merci a tous !
Marsh Posté le 05-10-2006 à 15:24:29
normalement c'est ce que développera un maximum d'efficacité.
idéalement, ré-organiser l'indexbuffer pour que les triangles fassent le plus de cache hit (très gros gains possibles), et défragmenter le vertexbuffer pour des accès le plus contigu possible (des pouillèmes de gains possible, surtout quand les gpu deviendront massivement MMU-isés pour rester dans la même page mémoire) .
Marsh Posté le 05-10-2006 à 15:37:32
là j'avais donné un exemple:
http://forum.hardware.fr/hardwaref [...] tm#t331004
Marsh Posté le 05-10-2006 à 19:27:36
hola c'est monstrueux (et maginfique...) comme méthode !
Bon, par contre ce qui me fait un peu peur, c'est la complexité de ce type d'algorithme... Enfin du point de vue algorithmique, ça va pas me donner un algo de complexité exponentielle non ? enfin, je le sens comme ça... Même dans un temp de chargement ça risque d'être long. Va falloir que je crée un petit utilitaire pour "défragmenter" mes vertices, pour pouvoir les charger sans soucis après...
C'est quand même bizare que les éditeurs 3D ne le fasse pas
preparez vous a me voir arriver avec mon algo de défragmentation qui marche pas
Sinon, je note la remarque que tu avait fait (il y a 3 ans...) de n'envoyer que les objects suceptible d'être affiché plutôt que tout envoyer a la carte graphique et de la laisser se demerder.
Allez a très bientôt
Marsh Posté le 06-10-2006 à 16:33:01
Salut,
Si tu as quelques sous à dépenser et que le domaine du moteur 3D te botte vraiment, je te recommande chaudement la lecture de "3D Game Engine Design" de David Eberly. C'est "un peu" tendu niveau math (mais bon, je suis pas un bon, donc ceci explique cela ).
Il y explique tout ça, et le bouquin est accompagné d'un moteur 3D qu'il a développé, donc tu as tout le code nécessaire pour lire et apprendre comment le tout s'organise.
Il a aussi écrit 3D Game Engine Architecture qui vient en complément; par contre je ne l'ai pas encore acheté (mais ça va pas tarder )
Marsh Posté le 06-10-2006 à 18:30:57
Salut !
Merci pour la réfernece du livre. Seul problème, c'est que je suis étudiant donc pas très riche. Et les 84$ du livre ça fait un peu trop pour moi pour l'instant. Mais je garde la référence pour pouvoir eventuellement me le prendre dans quelques mois...
Merci
Marsh Posté le 06-10-2006 à 22:03:51
Salut !
Bon, j'ai un petit soucis avec mon implémentation d'un vertex buffer. Dans un premier temp je veut juste envoyer mes vertices sans index buffer (je l'ajouterais ensuite). Voilà la partie qui gère la mise des données dans le buffer :
Code :
|
Bon le truc c'est qu'il plante dès l'appel de glGenBuffers() (ça ressemble beaucoup a problème de pointeur comme crash). Je suis sûr que le pointeur ptr est valide. Car j'ai put tester qu'il y a bien les coordonnées de mes vertices dans le pointeur. Donc sur le coup je ne vois pas d'où celà viens. Vous avez une idée ?
Merci
Marsh Posté le 07-10-2006 à 14:49:28
Salut !
J'ai même essayé de simplifier encore plus mon code et rien que ça, ça ne marche pas :
Code :
|
j'ai la MessageBox() qui me dit passe 0 et ensuite visual just in time debugger se lance et me dit "an unhandled win32 exception occured in _Xero_.exe " et ensuite le programme s'arrête. J'ai essayé de mettre le glGenBuffers() dans un bloc try pour essayer d'avoir l'erreur mais j'ai rien récupéré. Vous auriez une idée ?
Merci
Marsh Posté le 07-10-2006 à 19:17:54
Bon, j'ai finalement réussit !
Donc l'histoire, c'est que j'avais voulut utiliser une librairie applelée glew qui définissait d'elle même les vertex buffer. Et là je sais pas pourquoi ça ne marche pas. Donc j'ai du laisser tomber ma méthode de faignant et récupérer mes différentes méthodes via des wglGetProcAddress()... Et là comme ça ça marche impécable
prochaine étape : les index buffer
Marsh Posté le 07-10-2006 à 20:36:56
pourquoi tu stoques pas tout dans une seule structure et via un seul vector<> ?
Marsh Posté le 07-10-2006 à 21:18:59
Ben, par ce que j'ai lu que la méthode qui permet de faire celà est
Code :
|
Mais ils disent également qu'elle est obsolète... et qu'il vaut mieux utiliser les tableaux entrelacés. Mais après si tu dit que c'est mieux, je le fait, y a pas de soucis...
Marsh Posté le 07-10-2006 à 21:28:33
et ils disent également que cette méthode est inadaptée aux rendus utilisant du multitexturing et des shaders...
Marsh Posté le 08-10-2006 à 10:46:15
Bonjour !
Bon, je suis en train de regarder comment je peut utiliser le glInterleavedArrays(). Mais j'ai un proglème : je vois pas comment on l'utilise. Je suis allé voir sur MSDN. là j'ai crut comprendre qu'il fallait que je fasse ça :
Code :
|
avec Data un vector de Vertex. (Vertex étant la structure dont j'ai parlé dans mon prmier post...)
Et donc
Code :
|
remplace
Code :
|
c'est bien ça ? Si oui, j'ai un soucis car ça ne marche pas...
Merci
Marsh Posté le 17-10-2006 à 02:17:40
Amonchakai a écrit : Ben, par ce que j'ai lu que la méthode qui permet de faire celà est
|
je sais pas trop ce que vaux cette façon de faire, et je sais pas si ça correspond à ce que je pense.
ça me semble liés aux Arrays d'OpenGl 1.1 ou un truc du genre, et pas aux VBOs.
a priori je pense qu'il faut plus faire un:
glBindBufferARB(
glVertexPointer(
glTexCoordPointer(
...
avec les bons strides & offsets.
Marsh Posté le 17-10-2006 à 02:19:22
mais j'avoues là, je sais pas quel est le bon séquencement grâce à la coexistance des Arrays classiques et des VBOs.
Marsh Posté le 17-10-2006 à 18:21:22
Salut !
Ha d'accord, je viens enfin de comprendre ce que tu veut dire...
Oui, par ce que j'avais en tête ce que j'avais vu sur directX (bon de très loin car je ne sais pas utiliser DirectX actuellement...) et j'avais compris qu'il fallait déclarer la structure des données qu'il fallait envoyer, et qu'il existait des flags qui permetait de spécifier le format utilisé. Ce que j'ai donc cherché à retrouver en openGL, d'où le glInterleavedArrays().
Toujours est-il que maintenant je vois bien le truc. je vais mettre ça a jour
Merci
Marsh Posté le 18-10-2006 à 16:14:58
oki
effectivement, sous Direct3D 9, il existe aussi un peu une co-existance un peu comme les Arrays et les VBOs de l'OpenGl, au niveau de la déclaration des VertexBuffers:
Tu as une fonction SetFVF() qui est un héritage du T&L fixe datant de D3D 7 (je crois car j'ai pas connu heureusement ), ou tu déclares le format des données par Vertex avec des combinaisons de flags.
Et maintenant avec D3D9 (ou depuis le 8 je sais plus ), tu as un truc pour déclarer le format du Vertex bien plus adapté aux Vertexs & Pixels Shaders dans lequel tu passes un tableau d'eléments déclarant bien plus précisément la nature d'un élément du Vertex:
taille, offset dans le vertex, nature "simple" (position, normale, valeur quelconque...), et la manière de faire la tessellation si la géométrie doit passer par un tessellateur.
D3D10 dégagant les restes du T&L fixe a grands coups de shotgun, ce qu'il fait qu'il ne restera plus que l'approche utilisant une description plus précise de la structure d'un Vertex.
Marsh Posté le 18-10-2006 à 22:06:22
Merci pour l'explication !
Je regarderais ça plus en détail quand je m'occuperai de l'implémentation DirectX pour le moment j'ai déja bien à faire avec openGL.
(Je me suis mis à l'algo de "défragmentation" de vertex. et j'ai quelques petit soucis... je le posterai quand je l'aurrai fini )
Salutation !
Marsh Posté le 19-10-2006 à 00:01:05
alors attention: bien que ce soit utilie, il est -BIEN- plus important de réorganiser les triangles, dumoins leurs indexes pour bien utiliser le cache Post-T&L.
Personnellement je suis parti de nvStrip de nVidia pour faire mon propre réorganiseur de triangle.
ce qu'il faut comprendre, pour maximiser le rendement:
les strips c'est bien mais:
des strips indépendants (rafales de quelques dizaines de triangles) c'est mal car ça génère des petits batches (trop de commandes de traçages OpenGl ou D3D)
il faut donc générer des strips dits "dégénérés" ou tu places un vrai-faux triangle dont deux sommets sont à un indice identique, le triangle sera neutralisé par le culling, et ça permet des connecter des strips géométriquement indépendants afin de faire toute la géométrie (a matériau identique) en une commande.
perso j'ai joué avec ça, et j'ai fini par faire des triangles indépendants optimisés pour le cache Post-T&L.
donc en compromis tu as:
- strips isolés: trop de commandes de traçage
- strips dégénérés: "vrai-faux" triangles pour connecter des strips isolés, si les strip sont trop "courts", le pourcentage de "vrai-faux" triangles peut faire perdre en rendement.
- triangles indépendants: triangles et commandes de traçage minimales, consomme un peu plus de bande-passante mémoire dans l'absolu pour "fetcher" les indices (3 indices 16bits ou 32bits par triangle au lieu de 1 indice dans le cas d'un strip)..... mais l'ordre de grandeur est ridicule en comparaison aux vertexs eux-mêmes et aux accès texture.
généralement tu est gagnant (attention c'est mon avis perso) avec les triangles indépendants étant donné qu'en bonus c'est beaucoup plus d'actualiser la géométrie procéduralement (ie dégager ou insérer des triangles à la volée dans une géométrie stripifiée est potentiellement pête-couilles, alors qu'avec des triangles indépendants c'est assez trivial)
--
en fait moi je fais tout cette optimisation dans mon exporteur 3DSMax..
je fait une optimisation du flux de triangles indépendants par brute-force :
je simule le cache Post-T&L (par exemple une Geforce 1 qui a utilise un cache FIFO de 12 entrées), pour chaque vertex je maintiens la liste des triangles qui l'utilise, et partant du premier triangle de mon lot de triangles, je cherche le triangle suivant non déjà émis qui procurera le plus de "cache-hit".
ie j'ai le premier triangle dont les sommets sonts 12 32 789:
j'ai auparavant stoqué par vertex quel triangles étaient utilisés.
ça me donne un cache FIFO comme ça:
12 32 78 X X X X X..... (X pour rien de caché, jusqu'aux 12 ou+ vertexs cachés)
et ensuite pour chercher le prochain triangle a emettre, je regarde pour quel est l'élu qui me donnera le plus de cache-hit vis à vis du cache FIFO.
une fois que je l'ai, je l'émets dans un buffer, et j'actualise le cache FIFO en y poussant les vertexs non cachés tu triangles émis.
et comme ça je construit une bonne séquence de triangles (pas forcément la meilleure dans l'absolu).
ce qui peut donner: (* cache hit | état cache FIFO)
12 32 78 * 0 | 12 32 78 X X X X.....
12 32 85 * 2 | 85 12 32 78 X X X X.....
12 78 56 * 2 | 56 85 12 32 78 X X X X...
78 85 56 * 3 | 56 85 12 32 78 X X X X....
une fois que un as un flux de triangles bien-bien, tu peux commençer à défragmenter et réindexer les vertexs pour avoir des accès mémoires optimaux.
---
Pourquoi me baser sur une Geforce 1 (ou 2 ché pu je m'étais baser sur les infos de nvStrip) pour le cache Post-T&L ?
=> Parceque en termes de cache, il vaux mieux se baser sur le plus petit "connu", ie même si sur une carte moderne (genre Geforce 7 ou Radeon X1900) tu as un cache bien plus efficace genre (pseudo-)LRU 32/64/1024 entrées (j'imagines totalement là je sais pas du tout où en est), les performances seront quand même largement correctes, alors que si tu optimises pour un cache excellent alors que t'as un ptit truc, tu va cache-trasher à mort. (c'est pareil pour un CPU, si tu bosses dans un buffer 16Ko alors que ton CPU a 4Ko de L1 ça va trasher en dehors du L1, alors que si bosses avec un buffer 4Ko, et même si ton CPU a un cache 16Ko de L1, les perfs seront quand même excellentes).
Marsh Posté le 19-10-2006 à 00:05:51
et on est bien d'accord que l'export de la géométrie depuis 3DSMax mets des "plombes" (ie une poignée de seconde, 4/5secs grand max pour un modèle conséquent, genre l'Apollo de base fourni en exemple)
donc c'est clairement quelque chose à faire en hors-ligne (hors moteur 3D temps-réel).
Marsh Posté le 19-10-2006 à 00:25:06
mais bon avant de te prendre la tête avec ça, fait que ton code OpenGl utilise correctement les VBOs et ce qui fait office d'IndexBuffer.
Marsh Posté le 19-10-2006 à 21:03:51
j'ai justement fini mon implémentation des vertex Buffer utilisant un index Buffer :
Code :
|
Et ça marche
Bon étape suivante : la réorganisation des triangles...
Marsh Posté le 19-10-2006 à 23:40:04
niquel, 2/3 petites remarques:
il vaut mieux mettre la position en premier dans le vertex. (idéalement dans un VertexShader il faut "sortir" la position transformée le plus tôt possible, donc dans le doute question latence ça peut être mieux).
tu peux grapiller un peu de bande-passante et de conso mémoire en utilisant des shorts pour l'IndexBuffer.
remarque de design objet:
tu as déporté le code OpenGl vers OGLRender, mais tu stoques des handles "propres" à OpenGl dans MeshToDisplay (buffer, indexbuffer).
si tu veux vrairement faire "abstraction" de l'api 3D il faudrait trouver un moyen de masquer ces buffer, indexbuffer via une classe interface, ptet style:
class RendererHandles
{
public:
virtual ~RendererHandles() = 0;
};
class MeshToDisplay
{
public:
std::vector<CVertex> data;
std::vector<unsigned int> index;
smart_ptr<RendererHandles> Handles;
};
class OGLHandles : public RenderHandles
{
public:
bool inBuffer;
unsigned int buffer;
unsigned int indexBuffer;
...
};
et grâce au destructeur tu libères les buffers OpenGl.
bon ça c'est plus une remarque de principe, hein dans un premier temps je te conseillerais de rester uniquement en OpenGl et pas a chercher a faire une abstraction de l'API 3D.
Marsh Posté le 20-10-2006 à 19:15:05
De retour, avec la première partie de mon algo : la réorganisation des triangles
Code :
|
Et ça a l'air de bien marcher
Ca te parait correct ?
reste plus qu'a réorganiser les indices des vertices...
[edit] j'ai retiré 2-3 commentaires pour pas trop foutre en l'air la mise en page du forum...
Marsh Posté le 21-10-2006 à 17:53:56
Salut !
heu, bjone ton exporteur mettait vraiment 4/5 s pour exporter un modèle .3ds ?
par ce que pour le moment le mien il met..... 25s pour un modèle de seulement 8000 triangles
Je pense qu'il y a un gros boulôt d'optimisation à faire...
Marsh Posté le 21-10-2006 à 19:48:49
En fait, ça viens peut-être que 8000 triangles c'est énorme... Je viens de revoir le personnage que j'avais modélisé sous milkshape3D et il fait 900 Triangles, et son exportation va plutôt vite... (j'ai pas le temp de le chronométrer a la montre...) Donc en fait, j'ai quand même fait une petite optimisation : quand j'ai un cache hit de 3 c'est pas la peine d'aller chercher plus loin... Et ça marche plutôt bien.
Salutation !
Marsh Posté le 21-10-2006 à 19:53:36
bin heu j'ai un Nostromo de 300000 triangles
attends je benches
Marsh Posté le 21-10-2006 à 20:17:24
Bon ça fait 15 secondes pour 300K triangles
(mais bon C2D à 3.4Ghz )
http://img332.imageshack.us/img332 [...] omowv4.png
ça tiens à 200fps sur ma X1900XTX:
http://img326.imageshack.us/img326 [...] orthz1.jpg
t'inquiètes pas c'est pas moi qui est modélisé le biniou, je l'ai pris sur un site de modèle 3DS (d'ailleurs il était ils construit n'importen'awaquement avec 10000 nodes de 30 triangles)
Marsh Posté le 21-10-2006 à 21:27:20
Et bien franchement il est tout simplement magnifique !
Et félicitation pour avoir réussit a l'afficher avec un 200fps... (au passage ça a l'air sympa ce que tu fait )
bon moi avec mon modeste unique CPU Athlon64 3400+ et bien je met 7min 15s pour... 17500 triangles. (Milkshape veut pas comprendre que ça existe des models de plus de 17500 triangles...). Je sais pas comment tu l'a fait, mais je crois que sans multithreading ça sert a rien d'avoir plusieurs CPU... Donc la lenteur de mon programme, ça doit venir de mon algo. Je vais voir si j'arrive a l'améliorer. Au pire a mon échelle (de 1000 triangles) ça reste acceptable.
Marsh Posté le 22-10-2006 à 02:26:06
pour accélérer la réorganisation, tu peux maintenir, pour chaque triangle, ses triangles adjacents sur chaqun de ces cotés. et dans le cache FIFO maintenir par entrée de cache quel triangle utilisait l'entrée (en plus de l'indice).
comme ça tu peux trouver très rapidement si un triangle adjacent fait un gros cache hit.
perso au lieu d'échanger un triangle, je maintiens une table de remapping (genre avec un -1 pour dire non re-mappé), ce qui permet de maintenir la cohérence avec les tables de triangles adjacents.
de plus les tables de triangles adjacent peut être aussi utile lors de génération de decals qui suivent la géométrie du mesh. (impacts de projectiles/éraflures)
Marsh Posté le 31-10-2006 à 21:32:40
Kikou !
Bon, je réssucite mon topic juste pour dire que j'ai retouché a mon algo et maintenant je fais 9s pour 175 000 triangles
Merci a toi bjone pour tes conseils avisés dans l'optimisation de mon programme...
Marsh Posté le 01-11-2006 à 01:57:40
y'a certainement d'autres trucs à dire, mais vérifies le framerate avec un très gros modèle voir si tu touches bien les limites des perfs géométriques de ta carte.
Marsh Posté le 04-10-2006 à 18:44:21
Bonjour !
Dans le cadre d'un de mes projet je voudrais afficher une Mesh d'un object modelisé sous un éditeur 3D.
Le truc c'est que me retrouve avec une série de vertices, de normales, et de coordonnées de texture et je voudrais tout afficher. Jusque la pas de problème : j'ai tout d'abord commencé par implémenter une méthode d'affichage via des l'utilisation de glDrawArray() (oui, par ce que je suis en openGL ). Mais on m'a fait remarquer que cette méthode n'était pas très "amicale" vis a vis du cache du GPU. Donc du coup je passe a l'utilisation de vertex buffer.
Mais voilà, un petit coup de recherche Google et je tombe sur ça : http://www.g-truc.net/article/vbo-fr.pdf (le fait que celà soit en français n'était pas recherché. il se trouve que c'est en français, tant mieux...)
Et donc là j'ai quelques soucis :
- tout d'abord ils n'ont pas l'air de de faire de déclarations de vertex... alors que j'aurrais pensé faire une structure du genre
faire un vector de vertex et tout envoyer d'un coup...
Disons que fait, tout en bas du document il parlent de la méthode glInterleavedArrays(GLenum format, GLsizei stride, GLvoid* pointer); qui a l'air de faire justement ça. MAIS ils disent qu'elle est obsolète.... Donc en gros pas à utiliser...
- Ensuite ils ont l'air de recommender des glBufferSubData() pour remplir un buffer unique (créé avec glDataBuffer() ) pour stocker tous les vertex, puis toutes les normales, puis toutes les coordonnées de texture. Ce qui semble intéressant puisqu'ils affirment ensuite que je pourrais modifier le buffer partiellement... ce qui pourrais être intéressant pour les animations... Mais voilà ça me fait quitter le fait de tout envoyer d'un coup, ce qui était le but initial... Vous en pensez quoi ?
- dernière question au sujet du stockage : je vois qu'après avoir tout affiché ils font un glDeleteBuffers(). heu, moi j'aurrais plutôt pas envis de détruire le buffer : ce qui est dans la mémoire de la carte graphique ne sera pas a renvoyer au prochain affichage... Bien sûr dans tous les cas je gardes mon vector de Vertex, mais si en plus je pourrais garder mon buffer, ça serait un gain de temp non ? Après j'imagine que c'est un compromis entre la vitesse et la mémoire de la carte graphique... Enfin votre avis m'intéresse
Voilà, Merci a ceux qui me répondront
Message édité par Amonchakai le 08-10-2006 à 10:46:59