[DB-AL] Enregistrer en tant qu'image le visuel d'une caméra.

Pour les scripts écrits en Javascript (UnityScript). :!: Obsolète :!:
Règles du forum
Merci de respecter la NOMENCLATURE suivante pour vos TITRES de messages :

Commencez par le niveau de vos scripts
DB = Débutant
MY = Moyen
CF = Confirmé

Puis le domaine d'application
-RS = Réseau
-AL = Algorithmie

Exemple :

[DB-RS] Mouvement perso multijoueur
Xann_71
Messages : 93
Inscription : 23 Juin 2015 22:25
Localisation : Le puy en velay

[DB-AL] Enregistrer en tant qu'image le visuel d'une caméra.

Message par Xann_71 » 19 Juil 2017 01:43

Bonsoir, Je viens vous demander de l'aide pour créer une image à partir d'une caméra.
Je souhaite créé un logiciel type pixart très simplifié. En gros l'utilisateur dispose d'un damier dont toutes les cases sont de la même couleur au départ et lorsqu'il clic sur une case, celle ci change de couleur. Jusque là tout va bien.
Une fois son travail terminé, l'utilisateur doit pouvoir en créer une image. J'ai donc fouillé sur le net et ai trouvé une solution que je ne maîtrise pas du tout.
J'ai un bouton "Enregistrer" qui doit récupérer ce que voit une caméra secondaire et l'enregistrer dans un dossier.

Voici donc mon script:

Code : Tout sélectionner

#pragma strict

public var cameraRender: Camera;

function Start ()
{

}

function Update ()
{

}

function OnMouseUp()
{

	print (Application.persistentDataPath);
	var img: Texture2D = new Texture2D(cameraRender.targetTexture.width, cameraRender.targetTexture.height, TextureFormat.RGB24, false);
	img.ReadPixels(new Rect(0, 0, cameraRender.targetTexture.width, cameraRender.targetTexture.height), 0, 0);
	//img.Apply();
	//File.WriteAllBytes(Application.persistentDataPath+"/test.png", bytes);
}
Désolé pour la présentation du code sans les retour à la ligne, ce sont les balises code qui ont tout serré. Pour ceux qui comme moi voient plus clair avec les retours à la ligne je vous l'ai fait en couleur juste en dessous:

#pragma strict

public var cameraRender: Camera;

function Start ()
{

}

function Update ()
{

}

function OnMouseUp()
{

print (Application.persistentDataPath);
var img: Texture2D = new Texture2D(cameraRender.targetTexture.width, cameraRender.targetTexture.height, TextureFormat.RGB24, false);
img.ReadPixels(new Rect(0, 0, cameraRender.targetTexture.width, cameraRender.targetTexture.height), 0, 0);
//img.Apply();
//File.WriteAllBytes(Application.persistentDataPath+"/test.png", bytes);
}

J'ai directement une erreur à la ligne var img: Texture2D qui m'indique:
NullReferenceException: Object reference not set to an instance of an object
Enregistrer.OnMouseUp () (at Assets/scripts/Enregistrer.js:19)
UnityEngine.SendMouseEvents:DoSendMouseEvents(Int32, Int32)

La variable cameraRender étant bien renseignée depuis l'Inspector, j'imagine que l'erreur vient du "targetTexture.width" mais sans en avoir la certitude, j'essaye de récupérer les dimensions de la caméra afin que l'image créée corresponde bien à ce que voit la caméra, si ce n'est pas ça comment fait on? Je n'ai pas vu de CameraRender.width ou quelque chose de semblable sur la documentation.

Bien que mon erreur m'empêche d'aller plus loin, j'imagine que le peu de code que j'ai ensuite ne suffira pas. En essayant d'appliquer les indications de la page "https://docs.unity3d.com/ScriptReferenc ... ixels.html" (j'ai mis le img.Apply() en commentaire car je ne suis pas certain de son utilité dans mon cas), j'ai constaté un lien en bas de page qui renvoie vers une fonction EncodeToPng, mais lorsque l'on tente de l'atteindre on tombe sur une page blanche.
Y'a t il parmi vous quelqu'un qui maîtrise ce type d'opération et qui pourrait donc m'indiquer les erreurs et éventuellement me proposer une solution?

Autre petite question pendant que j'y suis, j'ai ma caméra principale qui affiche la totalité de la page du logiciel et j'ai créé une caméra secondaire qui affiche uniquement le damier (c'est cette dernière qui doit créer l'image). Mon problème est que son rendu s'affiche sur lon écran, par dessus l'affichage de la caméra principale. Comment puis je faire pour empêcher l'affichage de cette dernière au milieu de l'écran de l'utilisateur?
Merci d'avance pour vos réponses.

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

Re: [DB-AL] Enregistrer en tant qu'image le visuel d'une caméra.

Message par boubouk50 » 19 Juil 2017 09:25

As-tu lu la documentation? https://docs.unity3d.com/ScriptReferenc ... xture.html
This is done by creating a RenderTexture object and setting it as targetTexture on the camera. The camera will then render into that texture.
When targetTexture is null, camera renders to screen.
When rendering into a texture, the camera always renders into the whole texture; effectively rect and pixelRect are ignored.

Je pense que targetTexture est null donc tu ne peux pas accéder à la width et height. Tu n'as pas assigné de RenderTexture à ta caméra.

Dans des cas comme cela, pour trouver le coupable, utilise des Debug.Log (variable) pour afficher le contenu de tes variables. Et vas-y pas à pas. Par exemple ici:
Debug.Log (cameraRender);
Debug.Log (cameraRender.targetTexture);
Debug.Log (cameraRender.targetTexture.width);

Le code plantera à l'endroit où l'accession est impossible, tu auras donc affiché la dernière valeur de la variable (ici, probablement null pour cameraRender.targetTexture.
"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

Xann_71
Messages : 93
Inscription : 23 Juin 2015 22:25
Localisation : Le puy en velay

Re: [DB-AL] Enregistrer en tant qu'image le visuel d'une caméra.

Message par Xann_71 » 19 Juil 2017 23:20

Ok, merci pour ta réponse, Effectivement TargetTexture etait null, je pensais qu'il s'agissait de définir les dimensions de la caméra.
J'ai finalement atteint mon but avec la fonction suivante:

Code : Tout sélectionner

function CaptureImg ()
{
	yield WaitForEndOfFrame ();
	var img: Texture2D = new Texture2D(334, 333, TextureFormat.RGB24, false);
	img.ReadPixels(new Rect(399, 152, 334, 333), 0, 0);
	img.Apply();
	var bytes: byte[] = img.EncodeToPNG();
	Destroy(img);
	Debug.Log(Application.persistentDataPath);
	System.IO.File.WriteAllBytes("test.png", bytes);	//Application.persistentDataPath +
	//System.IO.File.WriteAllText("Mon_nouveau_test.txt", "Ce test fonctionne parfaitement");
}
Il me reste cependant 2 problèmes à résoudre:
_Le premier est que j'ai fixé à tâtonnement les paramètres des lignes

Code : Tout sélectionner

var img: Texture2D = new Texture2D(334, 333, TextureFormat.RGB24, false);
	img.ReadPixels(new Rect(399, 152, 334, 333), 0, 0);
afin que l'image finale ne contienne que la partie d'écran que je souhaitais. Cependant j'aimerais dans un premier temps pouvoir décider moi même de la taille de l'image finale (512 x 512 pour commencer), l'idée étant qu'au final, l'utilisateur puisse lui même décider des dimensions que l'image aura. Existe t il une fonction pour demander à unity "je veux que tu convertisse l'image en 512 x 512"?
J'ai bien essayé avec les 2 derniers paramètres de la ligne:

Code : Tout sélectionner

img.ReadPixels(new Rect(399, 152, 334, 333), 0, 0);
Mais je n'ai pas obtenu le résultat souhaité, je n'ai d'ailleurs pas encore compris à quoi ils servent.

_Le second point est de savoir comment modifier le dossier de destination de l'image. Par défaut il vient se mettre dans le dossier mère de mon projet. Si je mets la ligne:

Code : Tout sélectionner

System.IO.File.WriteAllBytes(Application.persistentDataPath + "test.png", bytes);	// 
Il me crée l'image dans un coin perdu de l'ordinateur. Si je tente de créé un dossier de cette manière:

Code : Tout sélectionner

System.IO.File.WriteAllBytes("/img/test.png", bytes);
il me renvoie une erreur car le chemin n'existe pas (pour ça, je devrais trouver un "System.IO.File ..." qui crèe un dossier plutôt qu'un fichier, sa devrait être simple). Mais une fois le projet compilé, conserve t il la même structure de dossiers que celle qu'il a en tant que projet unity en cours(Nom_projet/Asset/... ?
Merci d'avance.
PS: Si tu souhaite que je ré affiche mes codes comme lors du premier message pour plus de lisibilité, je peux le faire.

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

Re: [DB-AL] Enregistrer en tant qu'image le visuel d'une caméra.

Message par boubouk50 » 20 Juil 2017 10:45

C'est écrit dans la doc: https://docs.unity3d.com/ScriptReferenc ... ixels.html
Et avec juste ReadPixels + Unity dans Gogole, tu tombes sur des exemples et des problématiques similaires aux tiennes:
http://answers.unity3d.com/questions/10 ... dpixe.html
http://answers.unity3d.com/questions/44 ... creen.html
etc.

Les chemins éditeur et build ne sont pas les mêmes voire même impossible. Dans l'éditeur, tu peux créer des dossiers/fichiers dans la hiérarchie de ton projet car tu as les droits, dans un build, ce n'est pas forcément le cas (en fonction de la plateforme utilisée). Il faut toujours tester avec la version build.
Tu es sous quelle plateforme? iOS? Android? Win? Linux? etc
"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

Xann_71
Messages : 93
Inscription : 23 Juin 2015 22:25
Localisation : Le puy en velay

Re: [DB-AL] Enregistrer en tant qu'image le visuel d'une caméra.

Message par Xann_71 » 27 Juil 2017 00:45

Merci pour tes réponses. Pour commencer je suis sous w7, j'aimerais pouvoir utiliser cette appli sous w7 et éventuellement sous android mais j'ai cru comprendre qu'il est un peu plus compliqué de faire des builds pour les OS de smartphone.
J'ai moi aussi trouvé des sujets similaire pour la capture d'image et j'ai d'ailleurs opté pour une solution un peu différente. Ayant un fond d'écran uni (blanc) et une zone à capturer au milieu, je commence par créer un premier rendu de toute ma fenêtre pour vérifier les pixels un par un. le premier qui n'est pas blanc correspond au coin bas gauche de mon image et le dernier au coin haut droit. Ensuite je crèe un second rendu ne prenant que la zone concernée. Ainsi j'ai résolu un problème survenu dans mes tests: Si la fenêtre à une taille différente de celle que j'utilisais sous unity, l'image créée ne sera pas décalée.
Cependant je ne trouve pas de solution à ma problématique. Prenons le cas de ma dernière image réalisée. elle fait 254 x 254 pixels. Je ne parviens pas à redimensionner en 512 x 512.

Pour l'histoire de la création de fichiers et dossiers. Il doit exister un moyen d'obtenir les droits non? Comment font tout autre logiciel pour enregistrer un fichier? Autre question, je souhaiterais laisser le choix à l'utilisateur de l'emplacement de la sauvegarde (un "enregistrer sous"). Mon problème c'est que dés que je fais des recherches sur la sauvegarde sous unity, je tombe sur les sauvegarde de données de jeu tantôt juste avec des variables, tantôt avec les users pref. il doit bien exister un script pour faire appel à la fenêtre windows qui nous propose de choisir le chemin de dossiers où l'on souhaite enregistrer notre fichier non?
Merci d'avoir pris le temps de lire.

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

Re: [DB-AL] Enregistrer en tant qu'image le visuel d'une caméra.

Message par boubouk50 » 27 Juil 2017 09:19

Pour faire une sauvegarde sous, tu peux utiliser UnityStandAloneFileBrowser, il n'y a rien de défini dans Unity pour cela (un jeu fait rarement un Save as).
Pour le redimensionnement, as-tu essayé Texture2D.Resize ()?
Concernant les droits en écriture, c'est à l'utilisateur du PC de les définir pas à Unity lui-même, tu comprends bien qu'un logiciel ne peut pas s'approprier des droits comme ça. Ce serait le porte ouverte à toutes les intrusions. Même si quand tu acceptes l'installation, tu acceptes de céder les droits en soi... Je parlais surtout des OS mobiles plus stricts.
"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

Verrouillé

Revenir vers « (Js) Javascript »