[RESOLU] Charger une gallerie de photo sans faire freezer l'app 10 secondes

Questions à propos du scripting. Hors Shader, GUI, Audio et Mobile.
Avatar de l’utilisateur
rattle-snake
Messages : 187
Inscription : 23 Jan 2012 23:37

[RESOLU] Charger une gallerie de photo sans faire freezer l'app 10 secondes

Message par rattle-snake » 18 Août 2016 22:41

Bonjour a tous,
Je travaille actuellement sur la création d'une gallerie photo de type carousel.

Tout va bien sauf que je n'arrive pas a faire apparaître les photos au compte goutte (comme on le vois sur les galleries android/IOS) sans faire freezer mon app.

En gros j'ai une premiere fonction qui crée les GameObjects avec Component UI.Image contenant juste une couleur noire (pour un temps de chargement quasi instantané).

Ensuite une deuxième fonction se charge de loader les textures sur chaque game Object respectifs.

Ci dessous mon code,
Est ce que je m'y prend de la bonne manière ?
Est-il possible de charger une texture dans monopoliser 100% des procs/freezer le programme ?

Code : Tout sélectionner

function displayCarousel(numeroImageEnCours:int)
	{
		//On met a jour localement le numero de slide en cours
		numeroSlideEnCoursCarousel = numeroImageEnCours;

		//On parcours le tableau une premiere fois pour generer les images carousel avec une couleur noire
		for(var i:int=0; i < gestionGallerieJS.files.Length; i++)
		{
			
			//Si l'image en cours est l'image sur laquelle on a cliqué...
			if (i == numeroImageEnCours)
			{
				//On crée l'instance avec le focus
				generateBlackInstanceOfCarouselImage(i, true);
			}
			
			else
			{
				//On crée l'instance sans le focus
				generateBlackInstanceOfCarouselImage(i, false);
			}
		}
		
		
		//On parcours le tableau une deuxieme fois pour inserer les textures (au fur et a mesure)
		for(var i2:int=0; i2 < gestionGallerieJS.files.Length; i2++)
		{
			yield StartCoroutine(uploadCarouselTrueTexture(i2));
		}
	}
	
function generateBlackInstanceOfCarouselImage(numeroImageEnCours:int, isOnActivated:boolean)
	{
		// On crée les component
		var imageGameObject:GameObject;
		var componentImage:UI.Image;
		var componentToggle:UI.Toggle;
		var componentLayoutElement:UI.LayoutElement;

		// On crée un nouveau GameObject
		imageGameObject = new GameObject();
		//On l'ajoute a notre tableau pour pouvoir le réutiliser plus tard :
		listeCarouselGameObjects.Add(imageGameObject);   
		
		imageGameObject.transform.name="imageCarousel"+numeroImageEnCours; //On renomme le gameObject
		imageGameObject.layer=LayerMask.NameToLayer("UI"); //On definit le layer UI pour ce gameObject
		
		//On le ratache à un canvas
		imageGameObject.transform.SetParent(contentCarouselGallerie.GetComponent(RectTransform), false);

		// On rajoute le componentImage
		componentImage = imageGameObject.AddComponent(UI.Image);
		//On met une couleur noire a l'image (en attendant qu'elle recoive ensuite sa vraie texture)
		componentImage.color = Color.black;
		componentImage.preserveAspect=true;
		
		// On rajoute le componentToggle
		componentToggle = imageGameObject.AddComponent(UI.Toggle);
		componentToggle.interactable = false;
		componentToggle.transition = Selectable.Transition.None;
		componentToggle.group = toggleGroupImageCarousel;
		
		//Uniquement sur l'ImageCarousel de lanvement, on met le toggle sur On
		componentToggle.isOn = isOnActivated;
		
		
		//////////////////////////////
		//Ajout d'un Layout Element//
		////////////////////////////
		
		// On rajoute un LayoutElement pour definir la longueur de l'image
		componentLayoutElement = imageGameObject.AddComponent(UI.LayoutElement);
		
		//A la création on definit la largeur du rect "contentCarouselGallerie"
		var scaleFactor:float = canvasGallerie.scaleFactor;
		
		componentLayoutElement.preferredWidth = fileDialog.GetComponent(RectTransform).rect.width;
		componentLayoutElement.preferredHeight = fileDialog.GetComponent(RectTransform).rect.height;
	
		//Pour eviter un bug de transparence, on masque et réaffiche notre gameObject
		imageGameObject.SetActive(false);
		imageGameObject.SetActive(true);
	}
	
	function uploadCarouselTrueTexture (numeroImageEnCours:int)
	{

		///////////////////////
		//Ajout de l'image ://
		/////////////////////
		
		//On recupere le chemin de l'image en cours
		var cheminImage:String = gestionGallerieJS.files[numeroImageEnCours];
		
		// On charge l'image en mémoire. On rajoute "file:///" car www en a besoin pour savoir que c'est un fichier local. Selon la plateforme, cela peut etre aussi : "file://" (a tester)
		var www:WWW = new WWW("file:///"+cheminImage);
		
		yield www; // On attend que l'image soit completement chargée (on laisse l'appli tourner pendant ce temps)
		var widthImageOri = www.texture.width;
		var heightImageOri = www.texture.height;
		
		
		// On crée la Texture 2D
		var imageTexture:Texture2D = new Texture2D(www.texture.width, www.texture.height, TextureFormat.RGB24, false);
		//On injecte l'image dans la texture 2D
		www.LoadImageIntoTexture(imageTexture);
		
		//On injecte la Texture 2D dans le sprite
		var spriteImageCarousel:Sprite = Sprite.Create(imageTexture, new Rect(0,0,widthImageOri, heightImageOri), new Vector2(0.5,0.5));
		
		//On injecte la texture 2D dans notre imageCarousel en cours
		listeCarouselGameObjects[numeroImageEnCours].GetComponent(UI.Image).sprite = spriteImageCarousel;
		//On met une couleur blanche a l'image (pour que la textrue soit visible)
		listeCarouselGameObjects[numeroImageEnCours].GetComponent(UI.Image).color = Color.white;
	}
Merci par avance si vous avez la solution :)
Bonne soirée !

Edit :
Pour résumer http://www.LoadImageIntoTexture freeze l'application le temps de l'opération (et comme je loop toutes mes images et bin....).
Même si j'espace ma loop de 2 secondes, je vais freezer quand même toutes les 2s.
Donc y aurait il un moyen de donner une priorité de calcul plus basse ou quelque chose comme ça ?

http://WWW.threadPriority n'a l'air de rien changer :
http://docs.unity3d.com/400/Documentati ... ority.html

Pas plus que :
Thread.CurrentThread.Priority = System.Threading.ThreadPriority.Lowest;
ou
Application.backgroundLoadingPriority = ThreadPriority.Low;

Avatar de l’utilisateur
F@B
Messages : 1844
Inscription : 01 Août 2013 10:41
Contact :

Re: Charger une gallerie de photo sans faire freezer l'app 10 secondes

Message par F@B » 19 Août 2016 08:51

Salut
Si tu appelles tout ça dans un Update() ça parait normal que ton app ne face plus rien non?

tu devrais regarder du coté des coroutine http://docs.unity3d.com/Manual/Coroutines.html
ʕ·͡ᴥ·ʔ ==> Mon Portfolio <== ʕ·͡ᴥ·ʔ

Merci de lire et de prendre en considération la Nétiquette des Forums avant de poster un sujet !

Avatar de l’utilisateur
rattle-snake
Messages : 187
Inscription : 23 Jan 2012 23:37

Re: Charger une gallerie de photo sans faire freezer l'app 10 secondes

Message par rattle-snake » 19 Août 2016 09:06

Bonjour FAB,
Merci pour ta réponse.

La fonction displayCarousel() qui appelle les autres fonctions est lancée seulement une fois (par un clique de bouton).

La fonction uploadCarouselTrueTexture() qui upload les textures sur toutes les images est une coroutine
=>

Code : Tout sélectionner

      //On parcours le tableau une deuxieme fois pour inserer les textures (au fur et a mesure)
      for(var i2:int=0; i2 < gestionGallerieJS.files.Length; i2++)
      {
         yield StartCoroutine(uploadCarouselTrueTexture(i2));
      }
      
Comme dit plus haut dans l'Edit, le problème vient du fait que le www.LoadImageIntoTexture à l'interieur bouffe tout le processeur lors du traitement (individuellement image par image) : je tombe a genre 6FPS et l'application n'est plus utilisable pendant ce temps.

Avatar de l’utilisateur
boubouk50
ModoGenereux
ModoGenereux
Messages : 6222
Inscription : 28 Avr 2014 11:57
Localisation : Saint-Didier-en-Bresse (71)

Re: Charger une gallerie de photo sans faire freezer l'app 10 secondes

Message par boubouk50 » 19 Août 2016 09:43

Essaie de lâcher un peu de lest en attendant les fins de frame entre différents appels.
Dans tes boucles, mets un WaitForEndOfFrame() pour que la boucle suivante se fasse sur une frame suivante.
Ça allonge le temps de chargement, mais peut permettre de moins freezer ton appli.

http://answers.unity3d.com/questions/54 ... issue.html
http://answers.unity3d.com/questions/87 ... thout.html
"Ce n'est pas en améliorant la bougie, que l'on a inventé l'ampoule, c'est en marchant longtemps."
Nétiquette du forum
Savoir faire une recherche
Apprendre la programmation

Avatar de l’utilisateur
simonj
Messages : 293
Inscription : 29 Nov 2015 20:47
Localisation : Lyon

Re: Charger une gallerie de photo sans faire freezer l'app 10 secondes

Message par simonj » 19 Août 2016 11:52

Coucou !

Ahaha c'est marrant ça fait un petit moment que je suis sur une application qui dois charger des miniatures pour les médias présents sur la tablette de l'utilisateur et je me suis posé exactement la même question.

En fait il me semble que le vrai problème c'est les co-routine. Il faut bien comprendre que ce ne sont pas des threads séparés. Ils tournent sur le thread principal, c'est juste qu'ils peuvent être mis en pause pour un temps déterminé (Une frame, un update, X secondes, ...) et c'est très bien.
Mais sauf que si tu fais des grosses opérations dans tes co-routine, les temps de calculs et de processing ont quand même un impact sur le thread principal et donc sur l'affichage.

Il y a plusieurs choses à regarder mais déjà fait bien attention que ton script que le chargement, création, et toutes les opérations soient hyper optimisées. C'est à dire pas d'appel de fonctions qui pourrais être évités. Par exemple sur dans le www il a un TextureNonReadable qui est beaucoup plus rapide en accès. Et pas besoin de passer par une texture en plus si tu veux juste créer un sprite.

Une autre optimisation, que j'ai fait moi, est un système de queue. C'est à dire qu'a la place de lancer X chargements en même temps, je stocke mes données de chargement et je ne peux lancer que 1 ou quelques chargement en même temps. Et dès qu'un chargement se termine, tu lances un autre téléchargement. Ca permet de ne pas surcharger d'opérations le thread principal.

Enfin, le conseil ultime c'est d'utiliser des threads. Malheureusement il faut savoir que les threads et Unity ne sont pas vraiment copain. C'est à dire que tu ne peux pas utiliser les fonction liées à Unity dans un thread car ce n'est pas ThreadSafe. Donc pas de Co-Routine, pas www, pas de Texture, ... Par contre tu peux lire des bytes quand tu veux charger ta texture avec des fonctions natives. Bref tout ce que tu peux externaliser, il faut le passer dans un thread à coté.
C'est ULTRA lourd à coder parce que c'est pas naturel. Mais c'est, d'après mes recherches, la meilleure solution pour avoir un chargement vraiment asynchrone.

Avatar de l’utilisateur
F@B
Messages : 1844
Inscription : 01 Août 2013 10:41
Contact :

Re: Charger une gallerie de photo sans faire freezer l'app 10 secondes

Message par F@B » 19 Août 2016 13:03

+1avec simonj et désolé pour incompréhension de mon premier post

perso je fais un système de Queue et ça se passe très bien, la conversion texture en sprite est lourde aussi, un petit waitForSecond permet de soulager un peu le chargement de tout ça. j'ai un loader sur ma Lazylist...

il est certain que si tu lance le chargement de 500 www d'un coup ça assomme aussi le proc
ʕ·͡ᴥ·ʔ ==> Mon Portfolio <== ʕ·͡ᴥ·ʔ

Merci de lire et de prendre en considération la Nétiquette des Forums avant de poster un sujet !

Avatar de l’utilisateur
rattle-snake
Messages : 187
Inscription : 23 Jan 2012 23:37

Re: Charger une gallerie de photo sans faire freezer l'app 10 secondes

Message par rattle-snake » 20 Août 2016 18:41

Ca fait plaisir de revenir sur le poste et de revoir tous ces précieux conseils :)

Simonj, merci pour l'astuce, je vais encore pouvoir optimiser le code grâce a toi !!!
Je vais me pencher sur cette histoire de queue ! J'imagine que le concept c'est de lancer des coroutines les unes après les autres dès que celle d'avant a finie (et avec des petits yields par-ci par là ^^).

Cette histoire de Thread m'a l'air assez chaude effectivement, si on ne pas pas utiliser les fonctions de Unity, je crains que le niveau ne soit trop élevé pour un humble graphiste :lol:

Je vais essayer de mettre en pratique tout ça !

Merci !
Seb

Avatar de l’utilisateur
Iwa
Messages : 1131
Inscription : 25 Avr 2012 16:20
Contact :

Re: Charger une gallerie de photo sans faire freezer l'app 10 secondes

Message par Iwa » 12 Oct 2016 11:58

Hello,

As-tu tout ce qu'il te faut? Si oui, pense a basculer ton sujet en [RESOLU] en éditant le premier message.
"N'est stupide que la stupidité Monsieur..." - Forest Gump
... sauf si tu lis pas ça :)

Si tu as tout ce qu'il te faut, merci de penser à basculer ton sujet en [RESOLU] en éditant ton tout premier post ;)

Avatar de l’utilisateur
E3DStef
Administrateur
Administrateur
Messages : 1646
Inscription : 14 Juil 2013 18:30
Localisation : https://www.carte-des-membres.com/fr/Unity3D-France/

Re: [RESOLU] Charger une gallerie de photo sans faire freezer l'app 10 secondes

Message par E3DStef » 01 Nov 2016 01:32

Je l'ai mis à RESOLU, si l'auteur n'as pas ses réponses il pourra toujours ré éditer...
Le Savoir n'est Précieux que s'il est Partagé

Si besoin urgent de me contacter, faites moi un mail sur : franceunity3d@gmail.com

Répondre

Revenir vers « Scripting »