Je fais donc du développement DirectX, en utilisant SharpDX sous .NET pour être exact (mais les solutions API DirectX / C ++ sont applicables). Je recherche le moyen le plus rapide de rendre les lignes dans une projection orthogonale (par exemple, simuler un dessin au trait 2D pour des applications scientifiques) à l'aide de DirectX.
Voici une capture d'écran des types de tracés que j'essaie de rendre:
Il n'est pas rare que ces types de tracés aient des lignes avec des millions de segments, d'épaisseur variable, avec ou sans anticrénelage par ligne (ou en plein écran AA activé / désactivé). J'ai besoin de mettre à jour les sommets des lignes très fréquemment (par exemple 20 fois / seconde) et de décharger autant que possible sur le GPU.
Jusqu'à présent, j'ai essayé:
- Rendu logiciel, par exemple GDI + en fait pas de mauvaises performances mais est évidemment lourd sur le CPU
- API Direct2D - plus lente que GDI, en particulier avec l'anticrénelage activé
- Direct3D10 utilisant cette méthode pour émuler AA en utilisant les couleurs de sommet et la pavage côté CPU. Aussi lent (je l'ai profilé et 80% du temps est consacré au calcul des positions des sommets)
Pour la 3ème méthode, j'utilise des tampons Vertex pour envoyer une bande triangulaire au GPU et la mise à jour toutes les 200 ms avec de nouveaux sommets. J'obtiens un taux de rafraîchissement d'environ 5 images par seconde pour 100 000 segments de ligne. J'ai besoin de millions idéalement!
Maintenant, je pense que le moyen le plus rapide serait de faire la tessellation sur le GPU, par exemple dans un Geometry Shader. Je pourrais envoyer les sommets sous forme de liste de lignes ou regrouper dans une texture et décompresser dans un Geometry Shader pour créer les quads. Ou, envoyez simplement des points bruts à un pixel shader et implémentez le dessin Bresenham Line entièrement dans un pixel shader. Mon HLSL est rouillé, shader model 2 de 2006, donc je ne sais pas ce que les GPU modernes peuvent faire de fou.
La question est donc: - quelqu'un a-t-il déjà fait cela, et avez-vous des suggestions à essayer? - Avez-vous des suggestions pour améliorer les performances avec une mise à jour rapide de la géométrie (par exemple une nouvelle liste de sommets toutes les 20 ms)?
MISE À JOUR 21 janvier
J'ai depuis implémenté la méthode (3) ci-dessus en utilisant des shaders de géométrie en utilisant LineStrip et Dynamic Vertex Buffers. Maintenant, j'obtiens 100FPS à 100k points et 10FPS à 1000000 points. C'est une énorme amélioration, mais maintenant je suis à taux de remplissage et à calcul limité, j'ai donc pensé à d'autres techniques / idées.
- Qu'en est-il de l'instanciation matérielle d'une géométrie de segment de ligne?
- Qu'en est-il de Sprite Batch?
- Qu'en est-il des autres méthodes orientées (Pixel shader)?
- Puis-je éliminer efficacement le GPU ou le CPU?
Vos commentaires et suggestions très appréciés!
Réponses:
Si vous allez rendre
Y = f(X)
graphiques uniquement, je vous suggère d'essayer la méthode suivante.Les données de courbe sont transmises en tant que données de texture , ce qui les rend persistantes et permet des mises à jour partielles, par
glTexSubImage2D
exemple. Si vous avez besoin de faire défiler, vous pouvez même implémenter un tampon circulaire et ne mettre à jour que quelques valeurs par image. Chaque courbe est rendue sous forme de quadruple plein écran et tout le travail est effectué par le pixel shader.Le contenu de la texture à un composant pourrait ressembler à ceci:
Le travail du pixel shader est le suivant:
41.3
elle choisirait40
,41
,42
et43
.X,Y
paires en espace d'écranVous pouvez remplacer 4 par des valeurs plus grandes en fonction du niveau de zoom potentiel.
J'ai écrit un shader GLSL très rapide et sale implémentant cette fonctionnalité . Je peux ajouter la version HLSL plus tard, mais vous devriez pouvoir la convertir sans trop d'effort. Le résultat peut être vu ci-dessous, avec différentes tailles de lignes et densités de données:
Un avantage évident est que la quantité de données transférées est très faible et que le nombre d'appels n'est qu'un.
la source
Il y avait un chapitre GPU Gems sur le rendu des lignes anti-crénelées: Fast Prefiltered Lines . L'idée de base est de rendre chaque segment de ligne en quadruple et de calculer, à chaque pixel, une fonction gaussienne de la distance du centre du pixel par rapport au segment de ligne.
Cela signifie dessiner chaque segment de ligne dans le graphique comme un quadruple séparé, mais dans D3D11, vous pouvez certainement utiliser un ombrage de géométrie et / ou instancier pour générer les quads, réduisant la quantité de données à transférer vers le GPU aux seuls points de données se. J'aurais probablement configuré les points de données en tant que StructuredBuffer à lire par le vertex / geometry shader, puis effectuer un appel de dessin en spécifiant le nombre de segments à dessiner. Il n'y aurait pas de tampons de vertex réels; le vertex shader utilise simplement SV_VertexID ou SV_InstanceID pour déterminer les points de données à examiner.
la source
@ Dr.ABT - Toutes mes excuses, c'est une question, pas une réponse. Je n'ai pas trouvé de moyen de le demander dans la réponse de Sam Hocevar ci-dessus.
Pourriez-vous partager plus de détails sur la façon dont vous avez finalement implémenté les lignes de votre graphique? J'ai le même besoin d'une application WPF. Merci d'avance pour tout détail ou code que vous pouvez partager à ce sujet.
la source