lundi 16 avril 2012

Comment faire des captures d'images en Unity?

Vous avez ce jeu magnifique ou ce superbe effet et vous voulez le présenter au monde entier. Vous démarrez votre jeu et pressez la touche Print Screen (en mode Windowed, sinon l'image est noire). Vous allez dans Photoshop ou, comme moi dans GIMP et sélectionner l'écran de jeu et vous le copiez dans une nouvelle image. Vous avez votre capture d'écran. Jusqu'à maintenant, c'est la procédure que j'utilisais à défaut de connaître mieux.

Aujourd'hui, j'ai appris une commande magnifique: Application.CaptureScreen. Cette fonction prend une capture d'écran directement du jeu! Fini les manipulations dans GIMP! La fonction requière un argument obligatoire, le chemin d'accès au fichier comprenant le nom du fichier et la taille de l'image. La taille du fichier est un entier qui détermine combien de fois plus grande sera l'image. Si j'entre 3, la capture d'image sera 3 fois la taille de l'écran!

Voici le script que j'ai utilisé:
using UnityEngine;
using System.Collections;

public class ScreenShot : MonoBehaviour 
{

 // Update is called once per frame
 void Update () 
 {
  if ( Input.GetKeyUp( KeyCode.F3 ) )
  {
   Debug.Log("Screen captured.");
    Application.CaptureScreenshot("Screenshot.png"); 
  }
 }
}
et le résultat (j'ai utilisé le Prefab Big Tree dans Standard Asset/Tree Creator pour l'arbre):


J’utilise la touche F3 pour déclencher la capture d'image. La question maintenant: où est enregistrée l'image? Lors de l’exécution dans l'éditeur d'Unity, l'image est enregistrée dans le répertoire du projet. C'est le répertoire qui contient le répertorie Assets. Pour l'exécutable, c'est différent. La compilation du projet crée un .exe et un dossier nommé nom_du_exe_data. Par exemple, si mon .exe se nomme screenshot.exe, le répertoire sera screenshot_data. Ce dossier est le répertoire de base et c'est l'endroit où les captures d'images sont enregistrées. La fonction ne fait rien si déclencher à partir du lecteur Web.

vendredi 13 avril 2012

Comment ajouter un script n'importe où dans le menu Component d'Unity?

Par défaut, Unity ajoute les scripts dans le menu Component->Scripts. Ce sous-menu se remplit rapidement avec l'ajout de scripts et devient difficile à utiliser. Un peu de classification serait le bienvenu. La solution est de créer ses propres sous-menus dans le menu Component. Pour ce faire, l'attribut AddComponentMenu est ajouté avant la déclaration de la classe avec comme argument une chaîne de caractère contenant le nom du sous-menu suivi du nom du script:
[AddComponentMenu("SousMenuName/SousSousMenuName/NomDuScript")]
Reprenons le script RandomObjectsCreator.cs utilisé pour instancier des prefabs lorsque la touche "Espace" est pressée. Je veux que ce script apparaisse dans le menu Component->Mentalogicus->Creator. J'ajoute l'attribut AddComponentMenu de la manière suivante:
using UnityEngine;
using System.Collections;

[AddComponentMenu("Mentalogicus/Creator/RandomObjectsCreator")]
public class RandomObjectsCreator : MonoBehaviour 
{
 public Transform _prefab;
 public float _radius = 10;
 
 // Update is called once per frame
 void Update () 
 {
  if ( Input.GetKey("space") )
  {
   //Create a random position.
   //The insideUnitSphere return a random 
   //position inside a sphere of radius 1.
   Vector3 rndPos = Random.insideUnitSphere * _radius;
   
   //Create a random rotation.
   Quaternion rndRotation = Random.rotation;
   
   //Instantiate a new object at a random 
   //position with a random rotation.
   Transform newGameObj = Instantiate( _prefab, 
    rndPos, rndRotation) as Transform; 
  }
 }
}

RandomObjectsCreator.cs by Mentalogicus is licensed under a Creative Commons Attribution 3.0 Unported License.

Unity compile le script et le menu apparaît à l'endroit désiré!

jeudi 12 avril 2012

Sierpinski Cake

J'ai créé un gâteau de Sierpinski, qui est une fractale, dans Unity 3D. Une fois terminé et vue le résultat de face: je me suis demandé à quoi le gâteau de Sierpinski ressemble vue de l'intérieur. Pour ce faire, j'ai ajouté un petit script pour bouger la caméra à l'aide du clavier.
-->

Contrôle:

  • Flèche droite ou a: tourne vers la droite.
  • Flèche gauche ou d: tourne vers la gauche.
  • Flèche haut ou w: tourne vers le haut.
  • Flèche bas ou s: tourne vers le bas.
  • Barre espace: Accélération.
  • r: Repositionne la caméra à sa position initiale.

mardi 10 avril 2012

Comment faire une caméra orbitale en Unity?

Aujourd’hui, nous allons apprendre à faire une caméra orbitale en Unity. Une caméra orbitale est une caméra qui orbite un objet choisi comme cible. La caméra est tournée au moyen de la souris en appuyant sur le bouton gauche. Les mouvements de la souris sont transformés en rotations de la caméra. La caméra tourne en fixant constamment la cible choisie. De plus, je veux que la caméra zoom et dé zoom à volonté. Comme le dicton dit: une image vaut mille mots et un vidéo vaut au moins 24 images par secondes (pour 24 000 mots/s!!!). Voici le résultat final de ce que je veux implémenter:
Unity Web Player | WebPlayer -->
Principe de bases Lorsque le bouton droit de la souris est pressé, je convertis le mouvement du curseur en degrés selon les coordonnées x et y. J’utilise ces angles pour indiquer la rotation de la caméra. La rotation de la caméra autour du château implique deux mouvements: la rotation de la caméra sur elle-même et son déplacement dans l’espace.


Rotation de la caméra sur elle-même
Commençons par réglé le cas de la rotation de la caméra sur elle-même. Bougeons la caméra d’un angle a:

Sur le diagramme, la caméra du bas est la caméra dans sa position initiale. La caméra du haut est la caméra qui a tourné d’un angle a. La caméra ne pointe plus sur la cible. Pour corriger, la caméra doit être bougé d’un angle b. Les angles a et b sont alternes-internes; par conséquent, a=b. Vive la géométrie!

Unity utilise les quaternions pour représenter les rotations. Les quaternions sont des nombres hyper complexes (c’est-à-dire une extension des nombres complexes). Pour ceux intéresser à approfondir leur connaissance en math, je recommande chaudement Khan Academy. Il n’est pas essentiel de connaître les quaternions pour les utiliser. Je le mentionne pour que vous pensiez de convertir vos angles en quaternion. Les rotations en degrés sont converties en quaternion comme suit (aide Unity pour Quaternion.Euler):
 
Quaternion rotation = Quaternion.Euler( a,b,0 );
où a et b sont les angles de rotation par rapport à l’axe des x et y respectivement. L’axe des x est l’horizontale, l’axe y la verticale et l’axe z est la profondeur. Pourquoi le nom Euler et non pas Angle comme nom de fonction? Il y a une fonction Angle dans Unity. Elle retourne l’angle minimal entre deux rotations. Ici, il faut entrer 3 angles. C’est Leonhard Euler qui a introduit l’utilisation des 3 angles pour décrire l’orientation d’un corps solide. Le nom est resté. La caméra est tournée en modifiant la propriété rotation du composant transform:
 
transform.rotation = rotation;
Deux commandes, et la caméra est tournée!

Déplacement de la caméra
La caméra est à une distance d la cible et doit maintenir cette distance lors de la rotation. La caméra tourne comme attacher à une corde fixée à la cible.

La position de la caméra est égale à la somme des vecteurs \( \vec{p} \) et \( \vec{r} \). Le vecteur \( \vec{p} \) est connu, c’est la position de la cible. La longueur du vecteur \( \vec{r} \) est d, la distance de la caméra à la cible. Le changement de direction du vecteur \( \vec{r} \) est donné par la rotation de la caméra. Posons \( Fr \) comme une fonction de la rotation. La position de la caméra est: \( Fr(\vec{r}) + \vec{p} \). Ok, mais c’est quoi \( Fr \)? Vous vous rappelez les quaternions? Et bien, une de leurs fantastiques propriétés est que lorsqu’ils sont multipliés avec un vecteur, ils retournent un vecteur ayant subit la bonne rotation. Posons \(  Q \) comme étant le quaternion. La position de la caméra est fourni par l’équation: \[  Q \vec{r} + \vec{p} \] Une multiplication suivi d’une addition. Le code C# pour la position de la caméra est:
 
transform.position = rotation * r + p;
La combinaison du code pour la rotation de la caméra sur elle-même et le code pour modifier la position est:
 
void Rotate( float x, float y )
 {
  Quaternion rotation = Quaternion.Euler(y,x,0.0f);

  Vector3 position = 
   rotation * _distanceVector + _target.position;

  transform.rotation = rotation;
  transform.position = position;
 }

Les contrôles
La rotation de la caméra est activée en pressant le bouton gauche de la souris. La méthode GetButton de la classe statique Input  est ce qu’il nous faut. Cette fonction accepte une chaîne de caractère en entrée qui détermine le type de bouton et retourne un booléen qui indique si le bouton a été pressée. La chaîne de caractère pour le bouton gauche de la souris est  Fire1 dans Unity (pour plus de détails voir ici). Le code pour détecter que le bouton gauche a été pressée est:

void RotateControls()
 {
  if ( Input.GetButton("Fire1") )
  {
  
  }
 }
Maintenant, la position du curseur détermine l’angle de rotation. Pour déterminer la position du curseur, la méthode GetAxis de la classe Input est utilisée. Cette fonction retourne le mouvement de la souris suivant un axe en pixel. L’axe doit être spécifié. Pour la souris, les axes sont nommés Mouse X et Mouse Y. Le code est inséré à l’intérieur du If comme suit:
 
void RotateControls()
 {
  if ( Input.GetButton("Fire1") )
  {
   _x += Input.GetAxis("Mouse X") * _xSpeed;
   _y += -Input.GetAxis("Mouse Y") * _ySpeed;

   this.Rotate(_x,_y);
  }
 }
L’appel à la fonction Rotate, vu précédemment, complète le code pour la rotation. 

Zoom
Pour le zoom, j’utilise la roulette de la souris. Pour déterminer si la roulette a été tournée, la méthode GetAxis est appelée en utilisant la chaîne de caractères: Mouse ScrollWheel. Selon la direction de rotation, j’incrémente ou je décrémente la distance de la caméra à la cible. Ensuite, j’appelle la fonction Rotate pour repositionner la caméra au bon endroit. 

Le code complet est fourni ci-dessous.

OrbitCamera.cs

   
using UnityEngine;
using System.Collections;

/**
 * Change the camera into an orbital camera. An orbital is a camera
 * that can be rotated and that will automatically reorient itself to
 * always point to the target.
 * 
 * The orbit camera allow zooming and dezooming with the mouse wheel.
 * 
 * By clicking the mouse and dragging on the screen, the camera is moved. 
 * The angle of rotation  correspond to the distance the cursor travelled. 
 *  
 * The camera will keep the angular position when the button is pressed. To
 * rotate more, simply repress the mouse button et move the cursor.
 *
 * This script must be added on a camera object.
 *
 * @author Mentalogicus
 * @date 11-2011
 */
public class OrbitCamera : MonoBehaviour
{
 
 //The target of the camera. The camera will always point to this object.
 public Transform _target;
 
 //The default distance of the camera from the target.
 public float _distance = 20.0f;
 
 //Control the speed of zooming and dezooming.
 public float _zoomStep = 1.0f;
 
 //The speed of the camera. Control how fast the camera will rotate.
 public float _xSpeed = 1f;
 public float _ySpeed = 1f;
 
 //The position of the cursor on the screen. Used to rotate the camera.
 private float _x = 0.0f;
 private float _y = 0.0f;
 
 //Distance vector. 
 private Vector3 _distanceVector;
 
 /**
  * Move the camera to its initial position.
  */
 void Start ()
 {
  _distanceVector = new Vector3(0.0f,0.0f,-_distance);
  
  Vector2 angles = this.transform.localEulerAngles;
  _x = angles.x;
  _y = angles.y;
    
  this.Rotate(_x, _y);
  
 }

 /**
  * Rotate the camera or zoom depending on the input of the player.
  */
 void LateUpdate()
 {
  if ( _target )
  {
   this.RotateControls();
   this.Zoom();
  }
 }
 
 /**
  * Rotate the camera when the first button of the mouse is pressed.
  * 
  */
 void RotateControls()
 {
  if ( Input.GetButton("Fire1") )
  {
   _x += Input.GetAxis("Mouse X") * _xSpeed;
   _y += -Input.GetAxis("Mouse Y")* _ySpeed;
     
   this.Rotate(_x,_y);
  }
 
 }
 
 /**
  * Transform the cursor mouvement in rotation and in a new position
  * for the camera.
  */
 void Rotate( float x, float y )
 {
  //Transform angle in degree in quaternion form used by Unity for rotation.
  Quaternion rotation = Quaternion.Euler(y,x,0.0f);
  
  //The new position is the target position + the distance vector of the camera
  //rotated at the specified angle.
  Vector3 position = rotation * _distanceVector + _target.position;
    
  //Update the rotation and position of the camera.
  transform.rotation = rotation;
  transform.position = position;
 }
 
 /**
  * Zoom or dezoom depending on the input of the mouse wheel.
  */
 void Zoom()
 {
  if ( Input.GetAxis("Mouse ScrollWheel") < 0.0f )
  {
   this.ZoomOut();
  }
  else if ( Input.GetAxis("Mouse ScrollWheel") > 0.0f )
  {
   this.ZoomIn();
  }

 }
 
 /**
  * Reduce the distance from the camera to the target and
  * update the position of the camera (with the Rotate function).
  */
 void ZoomIn()
 {
  _distance -= _zoomStep;
  _distanceVector = new Vector3(0.0f,0.0f,-_distance);
  this.Rotate(_x,_y);
 }
 
 /**
  * Increase the distance from the camera to the target and
  * update the position of the camera (with the Rotate function).
  */
 void ZoomOut()
 {
  _distance += _zoomStep;
  _distanceVector = new Vector3(0.0f,0.0f,-_distance);
  this.Rotate(_x,_y);
 }
 
} //End class

OrbitCamera.cs by Mentalogicus is licensed under a Creative Commons Attribution 3.0 Unported License.

mardi 3 avril 2012

Logiciel de modélisation de corps humain.

Modéliser un corps humain réaliste en 3D est une tâche difficile à accomplir qui demande beaucoup de talents et de connaissances. Le maillage doit refléter les caractéristiques du corps humain pour se déformer correctement lors des animations. La connaissance de l'anatomie humaine est extrêmement utile dans ce processus. Si vous êtes déjà un modeleur, modeler un corps humain ne vous pose pas d'obstacle. Si vous êtes comme moi, c'est-à-dire,  un néophyte de la modélisation, modéliser le corps humain est simplement or de votre portée. Ou peut-être pas...

Internet pour un greffon pour Blender  de génération de modèle humain, j'ai trouvé... exactement ce que je cherchais. J'ai trouvé: MakeHuman. Le titre du logiciel explique exactement ce que le logiciel fait: il fait des humains! Le logiciel est Open Source et les modèles générés peuvent être utilisés dans des jeux commerciaux! Le projet est actif et l'équipe publie régulièrement des mises à jour du logiciel (chaque jour, ce sont des "Nightly Build"). Mise en garde: le logiciel est en phase alpha, présente plusieurs bogues et manque des fonctionnalités. Malgré ces limitations, MakeHuman est un outil prometteur.

Voici un écran de MakeHuman avec un modèle mâle généré aléatoirement:

Modèle 3D d'un homme généré par MakeHuman.
Le logiciel offre plusieurs contrôles classés par onglets permettant de modifier les différentes parties du corps humain selon vos désirs. Vous pouvez changer la grandeur, le poids, le tonus musculaire, la forme des yeux, du nez, de la bouche, du cou, de la tête, des bras, etc. L'onglet Pose vous permet de modifier la position du corps, de faire sourire votre personnage ou de le rendre triste. MakeHuman ajoute automatiquement un squelette à votre modèle, ce qui est fantastique pour animer par la suite.

Les modèles générés par MakeHuman sont importables dans Blender à travers le format MHX. Les modèles importés comportent le maillage, le squelette compatible avec Rigify, des cheveux, la carte UV pour la texture de la peau, des yeux, des cils, etc. Bref, le modèle est prêt pour l'animation. Cet utilitaire sauve littéralement des dizaines d'heures de modélisation.Voici un modèle que j'ai fait avec MakeHuman et modifier avec Blender, et ce, en quelques heures:

Le même travail, fait complètement dans Blender, m'aurait pris des semaines de travail et d'apprentissage pour un résultat moindre. Bravo et merci à l'équipe de MakeHuman pour cet outil.