récupérer les pixels (glReadPixels trop lent) [OpenGL] - C++ - Programmation
Marsh Posté le 11-07-2006 à 07:44:45
Je ne suis pas sûr qu'il y ait mieux à faire. OpenGL, et surtout les puces graphiques, ne sont pas faits pour relire des données pixel rapidement. Le bus a une très grande bande passante en écriture de données (vers la CG), mais pas dans l'autre sens.
Quoi que tu fasses, tu ne pourras pas récupérer la vidéo avec le framerate optimal.
Marsh Posté le 11-07-2006 à 09:09:02
Est ce que tu as regardé du côté de: glCopyTexImage2D ?.
Il y a des exemples de son utilisation sur sulaco:
Render Faces et Render to Texture
Marsh Posté le 11-07-2006 à 12:32:53
J'ai regardé tes exemples, il me semble que le résultat doit malheureusement être le même que le coûteux glReadPixel.
Sinon, j'ai trouvé la fonction glGetPointerv qui normalement me renvoie pointeur du tableau désiré, en l'occurence GL_COLOR_ARRAY_POINTER. Mais sur internet, impossible de trouver un exemple concret et le manuel n'est pas vraiment explicit d'autant plus que j'ai vérifié la valeur du pointeur qui s'avère être 0 (idem pour les pointeurs des vertex et normal array)... Quelqu'un sait s'en servir...
>Réponse à El muchacho
Dans le pire des cas (ultime), j'ai les sources de l'implémentation donc il me semble qu'il me sera possible de modifier le comportement de l'API a ma sauce...
Marsh Posté le 11-07-2006 à 13:50:01
L'idée du Render to texture, est que tu rends toute ta scène dans une texture, que tu affiches à l'écran en texturant une primitive qui couvre tout l'écran.
Ce devrait être plus rapide que le glReadPixels, puisque tu peux bosser sur ta texture avant l'affichage, enfin... normalement.
Marsh Posté le 11-07-2006 à 15:50:52
D'accord j'ai remplacé mon
glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels);
par:
GLuint RenderedTex;
glBindTexture(GL_TEXTURE_2D, RenderedTex);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, width, height, 0);
Comment accéder au contenu d'une texture?
Marsh Posté le 11-07-2006 à 23:25:37
Il me semble que tu n'as plus qu'à toucher au buffer que tu as fourni à la création de la texture. Une fois modifié comme tu le sens, tu appelles glTexSubImage2D pour mettre à jour ta texture.
Mais bon, il vaut mieux avoir une doc plus détaillée, ça repose sur des extensions que j'espère que ton matos supporte, je suis loin d'être bon là-dedans
Sinon, c'est comme el muchacho a dit; j'ai lu à plusieurs endroits que le format de texture pouvait te faire gagner un peu de perf. A voir aussi donc.
Marsh Posté le 13-07-2006 à 21:27:32
Marche po
Marsh Posté le 13-07-2006 à 23:40:12
Désolé, j'ai du mal avec le post de messages...
Marsh Posté le 13-07-2006 à 23:42:31
Nop, je peus rien faire avec ses extensions, elles ne sont pas supportés par mon implémentation.
Voilà ce que j'ai fais:
unsigned char pixels = new unsigned char [glWindowWidth*glWindowHeight*4];
GLuint RenderedTex;
glGenTextures(1, &RenderedTex);
glBindTexture(GL_TEXTURE_2D, RenderedTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glWindowWidth, glWindowHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
void drawScene(int width, int height)
{
// Scene ...
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, RenderedTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
}
le render to texture marche (je l'applique à un cube à la fin)
Question
le pBuffer passé en paramètre à la création de la texture est-il recopié ou sert-il de référence?
Parce que lorsque je le consulte, pas de trace des pixels de rendu...
Marsh Posté le 14-07-2006 à 01:06:22
le buffer est recopié, tu peux même le supprimer après avoir initialisé la texture. Par contre, est-ce que tes hauteurs et largeur sont une puissance de 2?
Tiens, je viens de chopper un exemple, ça a l'air simple comme ça
Marsh Posté le 14-07-2006 à 02:59:44
Oui, c'est 128*128, j'arrive à rendre sur la texture donc à ce niveau plus de problème...
En revanche, ce que je ne comprend pas c'est que si je met NULL en dernier paramètre de glTexImage2D à la place de pixels, ma texture sera remplie de noir. Comme si pixels était nécessaire pour recevoir le rendu, par contre, il n'est en rien modifié, c'est ce qui m'embête...
Sinon, comment puis-je :
>"...toucher au buffer que tu as fourni à la création de la texture..."
???
Je précise aussi que je n'utilise pas glCopyTexImage2D (ne fonctionnne pas pour moi) mais glTexImage2D...
Marsh Posté le 14-07-2006 à 03:25:42
on peut savoir ce que tu fais sur ton image entre le moment où tu la lis et celui où tu la réécris ?
Marsh Posté le 14-07-2006 à 12:16:11
je suppose que tu parles de mon tableau de pixels, je ne le réécris pas puisque je souhaite y recevoir le rendu d'opengl pour le lire ensuite et le recopier dans une surface de mon choix...
Marsh Posté le 14-07-2006 à 12:21:33
quel est l'intérêt ? fonctionnellement tu fais quoi ? quel est le but de ton application ?
autant te le dire tout de suite : ta question sent la mauvaise idée, comme disent les consultants étasuniens y'a un "smell"
Marsh Posté le 14-07-2006 à 18:44:59
Je l'ai pourtant expliqué dans le 1er post, mais je vais la refaire...
L'intérêt est de faire ce qu'on appelle du offscreen rendering, c'est à dire faire fonctionner une appli opengl sans pour autant la relier à une fenêtre et tout son tintouin...
L'idée est de récupérer le résultat une image (celle qui normalement aurait dû être affichée à l'écran) afin de l'exploiter à sa convenance, dans mon cas la réafficher dans une appli gérée par une librairie 2D, ce qui donne une application géré par une librairie hybride 2D + 3D. Ca marche impeccable avec glReadPixels excepté au niveau des performances sur le PDA (sur le PC, c impec), je souhaitais savoir comment trouver un moyen de contourner ce problème...
Pour terminer, je n'ai pas inventé la technique, elle existe belle et bien, je me demande même si ce n'est pas comme ça que fonctionne SDL et OpenGL, enfin bon...
Sinon, je suis en train de regarder si il ne vaut pas mieux effectuer un rendu dans un pixmap, chose qui semble finalement plus aisée, à moins que quelqu'un n'ait trouvé la solution?
Marsh Posté le 15-07-2006 à 05:17:19
Bon ben, ce n'était pas de tout repos mais la solution à mon problème est bien le pixmap rendering. En gros:
1 - On crée une pixmap qui servira à recevoir le rendu
2 - On l'associe au rendu
3 - Lors de la création de la Pixmap, on lui a associé un pointeur vers son Image buffer, facilement lisible par la suite...
Résultat: je retrouve mes 45FPS à comparer aux 17FPS via la méthode glReadPixels qui finalement, ne sert à rien qu'à dégradé les performances sans apporter du mieux par rapport à du PixMap rendering.
Bien sûr tout ça dépend de votre implémentation... je n'aurais surement pas eu à faire tant de pied et de main sur une implémentation PC (moi c OpenGL ES).
Merci encore à tous.
Marsh Posté le 15-07-2006 à 11:29:33
De rien. Tu apportes là une info intéressante.
Marsh Posté le 10-07-2006 à 14:04:50
Bonjour,
Ayant de besoin de récupérer l'image générée par OpenGL dans un programme 2D devant tourner à 45 FPS, j'utilise glReadPixels qui me donne le bon résultat mais qui s'avère beaucoup trop lent (je tombe à 17 FPS). En effet, ma technique est de:
1 - récupérer les pixels dans un tableau avec glReadPixels
2 - lire le tableau pour le transformer en surface 2D
3 - afficher ma surface 2D
Ce qu'il faudrait c'est arriver à pouvoir lire directement le tableau de pixels d'OpenGL sans avoir à le recopier avec glReadPixels(). Quelqu'un sait comment faire ?
Je précise que le tout tourne sur PDA (d'ou le framerate bas) avec OpenGL ES (comporte moins de fonctions redondantes qu'OpenGL desktop), mais ne vous focaliser pas du tout dessus, le principe est absolument le même...