Est-il une alternative rapide à la création d'un Texture2D à partir d'un objet Bitmap dans XNA?
J'ai regardé autour d'un lot, et les seules méthodes que j'ai trouvé pour la création d'un Texture2D à partir d'une image sont:
using (MemoryStream s = new MemoryStream())
{
bmp.Save(s, System.Drawing.Imaging.ImageFormat.Png);
s.Seek(0, SeekOrigin.Begin);
Texture2D tx = Texture2D.FromFile(device, s);
}
et
Texture2D tx = new Texture2D(device, bmp.Width, bmp.Height,
0, TextureUsage.None, SurfaceFormat.Color);
tx.SetData<byte>(rgbValues, 0, rgbValues.Length, SetDataOptions.NoOverwrite);
Où rgbValues est un tableau d'octets contenant l'image des données de pixels en 32 bits format ARGB.
Ma question est, est-il plus vite que les approches que je peux essayer?
Je suis en train d'écrire un éditeur de carte qui est à lire dans la coutume-format des images (cartes) et de les convertir dans Texture2D textures à afficher. La précédente version de l'éditeur, qui est une implémentation C++, converti les images d'abord dans les bitmaps et puis en textures à tirer de l'utilisation de DirectX. J'ai tenté la même approche, cependant, les deux approches ci-dessus sont beaucoup trop lents. Pour charger en mémoire toutes les textures nécessaires pour une carte prend pour la première approche ~250 secondes et pour la deuxième approche ~110 secondes sur un raisonnable spec ordinateur (à titre de comparaison, le code C++ a pris environ 5 secondes). Si il y a une méthode pour modifier les données d'une texture directement (comme avec la classe Bitmap de la méthode LockBits) alors je serais en mesure de convertir le format des images directement dans un Texture2D et espérons, de gagner du temps de traitement.
Toute aide serait très appréciée.
Grâce
OriginalL'auteur Matthew Bowen | 2010-05-19
Vous devez vous connecter pour publier un commentaire.
Vous voulez LockBits? Vous obtenez LockBits.
Dans mon application j'ai passé dans le GraphicsDevice de l'appelant pour que je puisse faire cette méthode générique et statique.
Merci pour votre réponse, cependant j'ai voulu dire dans ma question initiale que j'avais essayé cette approche à l'aide de SetData(). J'ai couru une analyse plus approfondie, et de créer les images à l'aide de LockBits a pris 2,7 secondes. Quand je l'ai ajouté à ce code, pour chaque image générée: Texture2D tx = new Texture2D(appareil, bmp.Largeur, bmp.Hauteur, 0, TextureUsage.Aucun, SurfaceFormat.Couleur); Elle double le temps nécessaire à 74 secondes!! Juste pour créer une nouvelle texture pour chaque image, et même pas de le remplir. Ce type de temps de chargement n'est pas acceptable pour un jeu 2D. Je ne pense pas que XNA serait cette lente. :/
merci, fixe!
maintenant que j'ai relu votre question, je vois que je ne comprenais pas correctement. Désolé à ce sujet. Pouvez-vous donner une estimation du nombre et de l'étendue de Texture2Ds votre sera à la fin de la création?
L'une des plus grandes cartes que j'ai besoin de charger contient 1235 feuilles en tuiles, carreaux feuille représentant une image composite de tuiles de carte qui sont utilisés par le terrain de la carte. J'ai besoin de créer une texture pour chacun de ces carreau des feuilles pour dessiner la carte. La taille des textures, j'ai besoin de la gamme de 128x128px de très grande taille (2048x2048px ou peut-être même 4096px) si l'on considère qu'ils doivent être des puissances de 2. Les textures larges représentent les objets de la carte, tels que les maisons et les bâtiments (la tuile feuille de figure que j'ai donné ne comprend pas les objets de la carte - ci serait chargé dans et hors de la mémoire nécessaire).
OriginalL'auteur bufferz
ils ont changé le format de bgra à rgba dans XNA 4.0, ainsi que la méthode donne d'étranges couleurs, le rouge et le bleu doit être commuté. Voici une méthode que j'ai écrit qui est super rapide! (charges 1500x 256x256 pixels textures en environ 3 secondes).
Oh, merci, ça fonctionne pour moi.
+1 C'est pratique, même si (comme @Cameron a suggéré), il serait mieux si vous n'avez pas à changer l'image d'origine, mais plutôt travaillé sur la
imgData
tableau directement (vous n'avez même pas besoin deunsafe
dans ce cas).Les détails exacts de faire ce que @Groo suggère: 1) Déplacer
Marshal.Copy
ligne AVANT la boucle qui passe d'ordre des octets. 2) remplacerbyteData
les références à l'intérieur de cette boucle avecimgData
. 3) supprimerunsafe
etuint* byteData = (uint*)origData.Scan0;
etbyteData = null;
4) peut-être aussi changerimgData
àuint[] imgData
, plutôt que deint
de sorte que la formule fonctionne correctement et/ou ne cause pas de dépassement numérique si en cours d'exécution danschecked
mode - mais peut-être pas; je ne l'ai pas testé.OriginalL'auteur Jaska
J'ai trouvé que j'avais pour spécifier le PixelFormat comme .Format32bppArgb lors de l'utilisation de LockBits comme vous le suggérez, pour saisir les images de la webcam.
OriginalL'auteur Peter Goode
Quand j'ai lu cette question, j'ai supposé que c'était
SetData
performance qui a été à la limite. Cependant la lecture des OP commentaires dans le haut de réponse, il semble être à l'allocation d'une beaucoup de grand Texture2D.Comme une alternative, pensez à avoir un pool de Texture2D, que vous allouez au besoin, de retour à la piscine lorsqu'il n'est plus nécessaire.
La première fois chaque fichier de texture est nécessaire (ou dans un "pré-charger" au début de votre processus, selon l'endroit où vous souhaitez que le retard), charger chaque fichier dans un
byte[]
tableau. (Stocker cesbyte[]
tableaux dans un LRU Cache - sauf si vous êtes sûr que vous avez assez de mémoire pour les garder tous autour de tous les temps.) Ensuite, lorsque vous avez besoin de l'un de ces textures, de saisir l'un de la piscine textures, (en allouant un nouveau, si aucun de taille appropriée est disponible), SetData à partir de votre tableau d'octets - alto, vous avez une texture.[J'ai omis des détails importants, tels que la nécessité d'une texture à être associé à un dispositif spécifique, mais vous pouvez déterminer les besoins à partir des paramètres pour les méthodes que vous appelez. Le point que je fais est de réduire les appels à la Texture2D constructeur, surtout si vous avez beaucoup de grandes textures.]
Si vous avez vraiment de fantaisie, et de traiter avec beaucoup de différentes tailles de textures, vous pouvez également appliquer LRU Cache principes de la piscine. Plus précisément, le suivi du nombre total d'octets de la "libre" des objets détenus dans votre piscine. Si ce total dépasse un certain seuil que vous avez défini (peut-être combiné avec le nombre total de "libre" des objets), puis sur next demande, jeter des plus anciens libre de la piscine éléments (de la mauvaise taille, ou d'autres mauvais paramètres), pour rester en dessous de votre permis de seuil de "gaspillage" de l'espace du cache.
BTW, vous pouvez faire amende simplement suivi le seuil, et de jeter tous objets libres lorsque le seuil est dépassé. L'inconvénient, c'est un moment hoquet la prochaine fois que vous allouer un tas de nouvelles textures que vous pouvez améliorer si vous avez des renseignements au sujet de quelles tailles vous devez garder autour. Si ce n'est pas assez bon, alors vous avez besoin LRU.
OriginalL'auteur ToolmakerSteve