1

Hello,

Je réalise une application D3D managée, dans lequel j'utilise des Mesh, des vertex-buffer et indices-buffer pour gagner en fluidité.

La particularité du code est que les vertex composant les Mesh doivent être crées environs 30 fois par secondes, vitesse à laquelle je recois l'information sur la profondeur.

Du coté rendu, pas de soucis: si les 15 Mesh sont calculés avant le rendu, j'obtiens plus de 1500 fps.
Mais dès que je veux reconstruire régulièrement les 15 Mesh, le framerate chute à 10 fps.
Avec un buffer de Mesh, le framerate augmente, mais le rendu n'est pas fluide puisque la création des vertex reste effectuée à 10 fps.

Le problème se situe donc dans la re-construction dynamique des Mesh, pour cela j'utilise quasiment le code donné sur le site de MSDN, à cette adresse.. Code que j'applique plusieur fois, car ma depthmap fait 640 X 480, et qu'un mesh ne contient qu'un nombre très limités de vertex.
Il ne s'agit pas d'un problème de lockflag, car je ne lock pas mes vertex et indices buffers, cela faisait chuter encore plus le framerate.

Ma question est la suivante :
Est-ce que, dans ce genre de cas, il est judicieux d'utiliser plusieurs theads, pour la construction des Mesh?
Si oui, de quel ordre de grandeur le nombre de thread doit-il être? 2-4-10 ou pourquoi pas encore plus? Je n'ai jamais vu de code très threadés alors je ne me rend pas compte.
Si non, auriez vous une autre idée, parce que je ne peux plus trop optimiser le code de création de mesh, celui-ci étant déja fort simple.

Merci d'avance.

2

Tes mesh composent un objet statique ou dynamique ? Dans le premier cas, pourquoi le recréer et pas simplement le cacher en liste ? Si tu veux les reconstruires, plutôt que d'utiliser un thread pour ça, utilise le pour le réaffichage, et tous les 1/60ème de seconde, tu récupère le mesh que tu as fait (une sorte de vsync)

Kochise
avatar
Si Dieu m'a de nouveau fait homme, cette fois il m'a pas raté : marcher sur l'eau et dupliquer les pains, ça marche p'us :/

3

Merci de m'aider.
Comme je reconstruis les Mesh à chaque image après avoir vidé le vertex buffer, je suppose que c'est une succession d'objet statiques. Ce n'est peut-être pas le mieux, puisque "l'objectif" est de construire un objet qui semble dynamique, mais c'est comme cela que j'obtiens le meilleur rafraîchissement. J'ai testé le vertexBuffer.lock() afin de modifier uniquement la profondeur dynamiquement, mais c'était vraiment trop lent.

J'ai testé l'idée que tu suggères, enfin si j'ai compris ton explication, en mettant tout mes Mesh dans un tableau de Mesh, et lorsque la création du nouveau Mesh n'est pas terminée, j'affiche ce tableau. (un double buffering en quelque sorte)
Ça accélère effectivement le rendu: les rotations et déplacements de caméra sont très fluides, mais la déformation reste saccadée, puisque les Mesh ne sont recrées qu'au rythme pitoyable de 10 frames par seconde.
Pour faire une analogie, imagines une texture animée plaquée sur une face d'un cube qui tourne avec fluidité, mais la texture animée est, elle, très saccadée.

4

Mais qu'est ce que tu reproduit ? Si tu veux faire un personnage, fait un skeleton, les bras, jambes, tronc et tête que tu fous en liste, et tu les animes indépendamment directement dans le GPU. Tu peux éventuellement rajouter quelques triangles pour masquer les jointures (épaules, aine, cou) sans surcharger l'envoi des vertex à la carte 3D. Si tu compte effectivement "bourrer" chaque frame avec du vertex, essaye un bon algo de LOD avant. Personnellement, celui de stan melax me convient parfaitement vu qu'il est très paramétrable.

Kochise
avatar
Si Dieu m'a de nouveau fait homme, cette fois il m'a pas raté : marcher sur l'eau et dupliquer les pains, ça marche p'us :/

5

J'essais de transformer les donnéees (videos et profondeurs) du Kinect de Microsoft en modèle 3D.
J'ai essayé en OpenGL et C++, en D3D et .Net, avec des triangles list, strip, et maintenant avec des Mesh (avec vertex et indice buffer).
Mais je n'arrive pas au 30fps que m'envoit le Kinect.
J'ai un modèle 3D texturé correct, si ce n'est ce problème de framerate.
J'utilise à peu de chose près la fonction CreateHeightfieldMesh() du site MSD que j'ai cité plus haut, mais comme j'ai plus de 15 Mesh (un Mesh étant limité à 170X70), je l'appelle plusieurs fois comme cela :
int meshWidth = 170; // Nombre de ligne et colonne par Mesh, j'ai pris le maximum autorisé pour gagner en vitesse, au delà ça plante
int tileCols = (int)Math.Ceiling((float)(640 - 1) / (float)meshWidth);
int tileRows = (int)Math.Ceiling((float)(480 - 1) / (float)meshWidth);

public void BuildMeshFromDepth()
{
    for (int col = 0; col < tileCols; col++)
    {
        for (int row = 0; row < tileRows; row++)
        {
            CreateHeightfieldMesh(device, row, col); /col et row deviendont X et Y dans CreateHeightfieldMesh().
        }
    }
}
C'est, et de loin, la fonction qui prend le plus de temps dans mon rendu.
Je ne peu donc pas précalculer, ni stocker par avance en mémoire.
Je ne peu pas non plus simplifier le modèle, cela serait contre-productif en vitesse et en qualité.

6

Que fait "CreateHeightfieldMesh" ? Et bon, un HF de 4 par 3, t'es sûr de ce que tu fais ? Pourquoi diviser 640 et 480 par 170 ? Pas encore regardé le code MSDN...

Kochise
avatar
Si Dieu m'a de nouveau fait homme, cette fois il m'a pas raté : marcher sur l'eau et dupliquer les pains, ça marche p'us :/

7

CreateHeightfieldMesh crée un des Mesh, de la même façon que dans le code MSDN.
Ca ressemble à ça: (version simplifiée, j'ai viré la création du buffer d'indice, et d'autres trucs inutiles à la compréhension de la fonction)
        private void CreateHeightfieldMesh(Microsoft.DirectX.Direct3D.Device device, int col, int row)
        {
            // Data range - get one extra row/col around the tile for normal computation
            int startX = meshWidth * col - 1;
            int startY = meshWidth * row - 1;
            int endX = Math.Min(639, startX + meshWidth + 2);
            int endY = Math.Min(479, startY + meshWidth + 2);

            // For each point in the height field calculate the x, y, z and
            // texture coordinates.
            for (int y = startY; y <= endY; y++)
            {
                for (int x = startX; x <= endX; x++)
                {
                    CustomVertex.PositionNormalTextured vertex = new CustomVertex.PositionNormalTextured();
                    vertex.X = (float)X;
                    vertex.Y = (float)Y;
                    vertex.Z = (float)getDepth(x,y); // retourne la profondeur en (x,y)
                    arrayVertices[vertIndex++] = vertex;
                }
            }
           mesh.VertexBuffer.SetData(arrayVertices, 0, LockFlags.None);
        }
Et bon, un HF de 4 par 3, t'es sûr de ce que tu fais ?
J'ai trop simplifié en disant "col et row deviendont X et Y dans CreateHeightfieldMesh()" car en fait, col et row permettront de donner le debut et la fin en x ainsi qu'en y. En fait, la depthmap de 640X480 est découpée en carrés de 170 pixels de coté.
Pourquoi diviser 640 et 480 par 170 ?
Un Mesh ne contient malheureusement pas un nombre illimité de vertex. C'est essentiellement limité par la carte graphique, et 170 * 170 * 6 pour une carte graphique récente, enfin, la mienne, c'est le maximum, sinon directX plante. Donc pour créer des Mesh de maximum 170 * 170 * 6 vertex avec une depthMap de 640X480, je dois diviser la depthmap en 15 Mesh. Peut être moins avec des Mesh non carré, mais osef...
Pas encore regardé le code MSDN...
Pas de problème, c'est déja très sympas à toi de m'aider. Et puis je viens de mettre plus haut la seule fonction de la page que j'ai utilisé, plus besoin d'y aller.

(*) Ça me fait penser que je ne vois pas l’intérêt d'utiliser un indice-buffer, pour avoir 6 fois plus de vertex que de points dans la depthmap. C'est pourtant un exemple MSDN... Je jetterais un oeil au buffer d'indice plus tard, mais ce n'est pas ça qui me fera gagner mes 20 fps.

8

Tu es sûr que ton getDepth est assez rapide ? Je ne sais pas comment tu obtiens les valeurs, mais c'est peut-être ça qui ralentit tout...
Tu pourrais essayer de remplacer cet appel par autre chose de rapide (comme une constante) et voir si c'est plus fluide smile
avatar

9

Merci de ton aide.
J'ai testé en remplaçant "getDepth" par 1, j’obtiens un model plat, mais la vitesse est aussi lente.
Les valeurs viennent d'un pointeur non managé, si je ne les récupère pas, et que j'envois un tableau de 0 à la place à ma fonction de création de Mesh, le rendu reste lent.
Cela dit, tes idées étaient bonnes, merci.

Ça m’énerve, j'ai passé la soirée là dessus... Et j'ai tester avec les threads : les threads mettent longtemps à se lancer, je ne savais pas ça.
J'y gagne un peu, 2 FPS, ce qui n'est pas rien, mais l'application met 1 minutes avant d'afficher quelque chose. OK, j'ai exagéré : 15 threads grin, je réessaierais demain avec un nombre de thread plus réaliste.

10

GUNNM (./7) :
CustomVertex.PositionNormalTextured vertex = new CustomVertex.PositionNormalTextured();

Tu ne peux pas virer l'allocation de la boucle ? Genre, tu alloues une seule fois tous tes "CustomVertex.PositionNormalTextured" et tu mets chacun à jour à chaque appel de CreateHeightfieldMesh, sans en allouer de nouveaux à chaque fois. Une allocation, c'est pas forcément rapide, et là, ça doit garbage-collecter comme une vache.

11

D'ailleurs, en lisant mieux, pourquoi ne pas réutiliser arrayVertices directement ?

quelque chose dans ce genre là :
initIndépendantAppeléUneSeuleEtUniqueFois()
{
   initialiser arrayVertices avec des CustomVertex.PositionNormalTextured par défaut
}






private void createHeightfieldMesh( Microsoft.DirectX.Direct3D.Device device,
                                    int col, int row ) 
{
   init de startX-endY ;

   vertIndex= -1 ;
   for ( y ) {
      for ( x ) {
         CustomVertex.PositionNormalTextured vertex= arrayVertices[++vertIndex] ;
         vertex.X= (float)X ;
         vertex.Y= (float)Y ; 
         vertex.Z= (float)getDepth(x, y) ;
      }
   }
}



PS : c'est pas beau tes X/x, Y/y tongue
D'ailleurs, j'ai l'impression qu'ils devraient tous être en minuscule dans ton code pour que ça compile grin

12

Tu as pensé à utiliser BufferUsage.WriteOnly,LockFlags.Discard ?
Je constate qu'encore une fois tu ne comprends pas ce que tu fais ni vraiment ce que tu veux faire et tu recopies du code sans comprendre ce qu'il fait exactement… Pas étonnant que ça ne fonctionne pas comme tu veux.
Si tu écrivais le code toi même tu aurais sans doute eu l'occasion de lire la documentation de chacune des fonctions que tu as utilisé, ce que tu n'as probablement pas fait vu la façon dont tu présentes les choses.
En plus c'est encore le même problème que la dernière fois, on dirait que rien n'a changé. Mais si tu t'y prends mal en OpenGL, tu t'y prendras également mal en Direct3D, car malgré les différences entre les deux API, si tu comprends rien à l'un tu ne peux pas mieux comprendre l'autre…
Tu devrais essayer de lire des tutos au lieu de faire des bidouilles au petit bonheur la chance. La documentation de MSDN, si tu la lis en profondeur, ainsi que les forums et les tutos de GameDev.net sont de très bons points de départ si tu te poses des questions sur une fonction particulière…
Puis bon, j'ai déjà expliqué des trucs dans l'autre topic, alors je les redirai pas ici, tant pis…

Pen^2 > C'est du .NET, les types de CustomVertex sont des types valeur, le new() ne fait qu'un memset à 0 dans le pire des cas.
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

13

(Ah ? OK. Je connais pas bien .NET. Mais ça reste une très mauvaise habitude tongue)

14

Edit : je virre le HS, maintenant qu'il a été lu.
Tu as pensé à utiliser BufferUsage.WriteOnly,LockFlags.Discard ?

J'utilise bien LockFlags.Discard, mais il me semble que ça n'a d'effet que sur des buffers dynamiques.
Ce qui est redevenu le cas, suite aux conseils précédents, je précalcule plus de choses, comme les indices buffers, et j’atteins maintenant les 15fps, ce qui reste peu. Après test, à None ou discard, je n'ai pas de différences notables.

BufferUsage.WriteOnly n'est pas accessible pour des Mesh, qui ont leur propre vertex buffer et indice buffer. Merci quand même.

15

GUNNM (./14) :
on peut difficilement faire plus condescendant. roll
Oh mais rassures toi c'était entièrement le but recherché.
J'ai estimé que tu méritais quelque chose entre aucune réponse et une réponse merdique. (Je voulais me contenter de la première option au départ, mais j'ai eu de la pitié pour ceux qui ont essayé de te répondre étant donné la qualité des informations fournies en ./1)
Et tu me le rabâches à chacun de mes posts, c'est pénible. sick

Oh mais en fait c'est très simple. Je n'ai jamais oublié tes posts défoncés au crack, aux champi et aux acides, où tu traitais tout yN de con et de pourri d'une manière assez pitoyable et déplorable.
Et vu les efforts que tu mets dans la compréhension des choses (indice: un exemple c'est fait pour illustrer un principe, pas pour être recopié sans réflexion), je te donne simplement la réponse que tu mérites.
Ton post #0 ainsi que ton précédent topic sur la 3D OpenGL se résument à "J'ai recopié l'exemple en bidouillant 3 trucs mais ça marche pas. J'utilise des trucs dont je ne comprends pas le fonctionnement, et je comprends pas à quoi ils servent.".
Si ça te parait normal à toi, à moi non.
Si tu veux pour illustrer mieux, je vais répondre aux questions de ton post #0:
GUNNM (./1) :
Ma question est la suivante :Est-ce que, dans ce genre de cas, il est judicieux d'utiliser plusieurs theads, pour la construction des Mesh?
non
Si oui, de quel ordre de grandeur le nombre de thread doit-il être? 2-4-10 ou pourquoi pas encore plus? Je n'ai jamais vu de code très threadés alors je ne me rend pas compte.
1
Si non, auriez vous une autre idée, parce que je ne peux plus trop optimiser le code de création de mesh, celui-ci étant déja fort simple.
oui.

(Et au fait ma question c'est du singulier, or là je vois 3 questions, dont une où il manque le point d'interrogation)

Si tu veux, étant donné le nombre conséquent d'erreurs de compréhension visibles au travers de tes posts, répondre aux vraies questions que tu n'as pas posées reviendrait à écrire le programme à ta place.
Content ? tongue
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

16

GoldenCrystal (./15) :
J'ai estimé que tu méritais quelque chose entre aucune réponse et une réponse merdique. (Je voulais me contenter de la première option au départ, mais j'ai eu de la pitié pour ceux qui ont essayé de te répondre étant donné la qualité des informations fournies en ./1)
Une réponse merdique de ta part ne m'aurait pas surpris, et m'aurait suffit, puisque tu ne peux pas t'empêcher de poster et étaler ton pseudo-savoir. Si c'est pour dire que c'est trop facile pour que tu répondes, abstiens toi, prétentieux.
Oh mais en fait c'est très simple. Je n'ai jamais oublié tes posts défoncés au crack, aux champi et aux acides, où tu traitais tout yN de con et de pourri d'une manière assez pitoyable et déplorable.
Je te laisse dans tes rancœurs, évites donc de me lire. T'es le seul a avoir pourri quelqu'un d'autre ici.
Et vu les efforts que tu mets dans la compréhension des choses (indice: un exemple c'est fait pour illustrer un principe, pas pour être recopié sans réflexion), je te donne simplement la réponse que tu mérites.
Le code que j'ai n'est pas une repompe de celui de msdn, mais je n'allais pas poster mon code, qui est plein de particularités qui ne change rien au problème ici. Je passe le monde en metrique, puis je fais correspondre les deux webcams grace à une rotation et des translation. Si j'avais posté le code de ma fonction de plus de 80 lignes, personne ne l'aurait lu. Alors, tu te sens pas un peu con avec tes jugements de valeurs?
Ton post #0 ainsi que ton précédent topic sur la 3D OpenGL se résument à "J'ai recopié l'exemple en bidouillant 3 trucs mais ça marche pas. J'utilise des trucs dont je ne comprends pas le fonctionnement, et je comprends pas à quoi ils servent.".
Tu ne sais pas lire, j'y peux rien. J'essais de simplifier mes problèmes pour orienter les réponses, et éviter que ça parte dans tous les sens.
Si ça te parait normal à toi, à moi non.
T'es juge de ce que je peux faire? Où as tu vus que je demandais ton avis? Je vais t'avouer un truc : j'avais justement peur que tu répondes à ce topic , car tu fout la merde à chaque fois en disant globalement "démerdes-toi". Je savais que t'allais faire ça, sans rien apporter.

Si tu veux pour illustrer mieux, je vais répondre aux questions de ton post #0:
GUNNM (./1) :
Ma question est la suivante :Est-ce que, dans ce genre de cas, il est judicieux d'utiliser plusieurs theads, pour la construction des Mesh?
non
Si oui, de quel ordre de grandeur le nombre de thread doit-il être? 2-4-10 ou pourquoi pas encore plus? Je n'ai jamais vu de code très threadés alors je ne me rend pas compte.
1
Si non, auriez vous une autre idée, parce que je ne peux plus trop optimiser le code de création de mesh, celui-ci étant déja fort simple.
oui.

(Et au fait ma question c'est du singulier, or là je vois 3 questions, dont une où il manque le point d'interrogation)
J'ai oublié un S ! Je suis impardonnable. roll
Je ne te remercie pas pour tes réponses, puisque j'avais testé et si tu comprenais ce que tu lis, tu l'aurais vus.
Si tu veux, étant donné le nombre conséquent d'erreurs de compréhension visibles au travers de tes posts, répondre aux vraies questions que tu n'as pas posées reviendrait à écrire le programme à ta place.
Content ? tongue
Non, j'aurais préféré, comme à chaque fois, que tu n'intervienne pas.
Tu as encore foutu la merde, et ce topic est parti en vrille.
Je crois que t'as un vrais problème d'égo. Tu te prend pas pour un petit développeur, hein?

17

GUNNM (./16) :
Je passe le monde en metrique, puis je fais correspondre les deux webcams grace à une rotation et des translation.
Le problème ne vient-il pas de là ? As-tu essayé en désactivant cette partie ?
avatar

18

Oui, j'ai enlevé ces transformations et transformations, le framerate restait le même.

19

hum, rassure-moi, tu ne recree pas un _nouveau_ vertex buffer a chaque fois que tu mets a jour ta mesh non?

est-ce que tu recree aussi l'index buffer? si oui, il n'y a pas moyen qu'il reste identique?
ensuite, les locks, ca a toujours tres bien marche chez moi, j'update regulierement des vertex buffers d'une 100aine de milliers de vertex, a des framerates largement > a 60 fps...

un truc que tu peux faire, c'est utiliser un buffer memoire temporaire, de la meme taille que ton VB, que t'alloue de ton cote, tu le remplis avec ta fonction de generation la, ensuite une fois que c'est fait, tu Lock() le vertex buffer (en discard), et tu fais juste un gros memcpy() dedans (ou l'equivalent en managed.. j'imagine qu'il y a un equivalent ?)

et est-ce que t'as essaye de ne pas updater le vertex buffer mais de generer quand meme continuellement ta mesh dans un buffer local en ram ? histoire de voir si le goulot d'etranglement vient vraiment du passage a l'API graphique?
avatar
HURRRR !

20

Mon code n'a plus rien à voir avec ça, je passe maintenant par du displacement map géré par le GPU.
J'ai plus de 100 fps, c'est le jour et la nuit.
J'ai d'autres soucis, mais plus celui de la vitesse.
Merci quand même.

21

ok smile
avatar
HURRRR !

22

Salut,

Une petit question comment as tu resolu ton probleme?

Merci

23

Il y a un moment que je n'y ai pas touché, je jetterais un oeil dans le code si tu as besoin de savoir. Je l'ai passé sous XNA, mais je dois avoir une sauvegarde du code "D3D only".
De mémoire, je crois que je crée tous les objets (vertex, vertexbuffer, arrayVertices etc) une seule fois au début, et je ne les réinitialise jamais. C'est possible uniquement si le nombre de vertices reste identique, finalement seule leur position change. Bref, j'ai suivi les conseil de bearbecue.
Je n'ai pas ajouté de thread, j'avais essayé, sans résultats convaincants.
Le grand changement ça a été l'utilisation des shaders, en particulier le displacement map.



24

c'est bon a savoir comme optimisation, merci