Réaliser une visionneuse de panorama VR en AS3

Cet article a été mis à jour le 14 mars 2009 afin d'être compatible avec la dernière version en date de Papervision

Ce premier article se consacre à la réalisation de visionneuses en Flash qui exploitent des images panoramiques

I > Type d'images panoramiques

Les photos VR, appelées parfois « Photographies Immersives », sont des images panoramiques qui , lorsqu'elles sont exploitées dans une visionneuse spécifique, permettent au spectateur de se mettre au centre de l'environnement, de tourner autour de soi et de regarder dans toutes les directions.

En 2000, Apple a lancé son fameux QTVR qui reste aujourd'hui une des solutions les plus utilisées pour la visualisation de panoramiques. Nous allons voir comment il est possible de réaliser le même type d'application mais qui tourne avec le player Flash.

Tout d'abord, regardons les différents types d'images panoramiques qui existent :

- Planaire : Ne sont pas destinées à être utilisé par un player VR car elles ne donnent pas l'illusion de perspective.

- Cylindrique : Les panoramas cylindriques proviennent de l'assemblage de plusieurs clichés pris autour d'un axe fixe et permettent un champ de vision de 360° horizontalement et environ 60° verticalement. Idéal pour observer un environnement extérieur.

- Sphérique : Les panoramas sphériques permettent d'obtenir une immersion totale puisque le champ de vision est global ,360° en horizontal et 360° en vertical. Ils sont donc très utiles pour les environnements intérieurs.

- Cubique : Offrent aussi un champ de vision global. Il ne s'agit plus ici d'une seule image mais de 6 ,qui sont projetées sur un cube.

(Vous trouverez une représentation visuelle de ces types de panoramas ,qui sera peut-être plus parlante , ici)

II> Création d'images panoramiques

Le but ici n'étant pas d'expliquer comment réaliser ce type d'images, je vous laisse donc le soin de consulter les sites spécialisés sur ce sujet.

Après avoir parcouru quelques uns de ces sites, je n'ai malheureusement pas trouvé de scènes disponibles dans les 3 types qui nous intéressent et qui auraient pu servir d'exemple. Mais ce n'est pas grave, cela va nous permettre de s'intéresser à une autre source pour nos images panoramiques, les images de synthèse.

Nous allons utiliser ici 3DSMax afin de modéliser une scène intérieure et de l'exporter sous forme de panoramique cylindrique, sphérique et cubique. Là encore, il ne s'agit pas de faire un tutorial sur la modélisation , le mapping ou l'éclairage dans 3DS. Si vous n'y connaissez pas grand chose, les rendus sont disponibles en téléchargement.

Créez votre pièce, placez une caméra libre au milieu de celle-ci, à une hauteur d'environ d'1m60 et qui fait face à un des murs. Nous allons utiliser l'exporteur de panorama pour réaliser nos images. Pour le trouver, il faut aller dans l'onglet 'Utilitaires' -> 'Autres' -> 'Exportation de panorama' (panorama exporter dans le version us).

Un nouveau menu s'affiche alors. Cliquer sur 'Rendu' , une nouvelle fenêtre devrait apparaître.

Exporteur panorama

Nous allons prendre 1024*512 comme résolution de sortie et 36 comme largeur d'ouverture.
Cliquez alors sur 'Rendu' après s'être assuré d'avoir choisi la bonne caméra dans la liste.

Exporteur panorama

Le rendu effectué , la visionneuse de 3DS s'ouvre automatiquement. Il s'agit de ce type de visionneuse que nous allons réaliser en AS3.
Dans le menu fichier de la visionneuse, cliquez sur exporter. 3 options sont alors disponibles : 'Exporter cylindre', 'Exporter sphère', 'Exporter QuicktimeVR'.
Les 2 premières nous intéressent particulièrement. Faites alors une exportation en cylindre et une autre en sphère.

Exporteur panorama

Pour le rendu de type cubique, il faut utiliser une autre méthode que j'ai trouvé ici
Commencez par créer une boite au milieu de votre scène. Puis allez dans l'éditeur de matériau , sélectionnez un matériau vide et choisissez la texture réflexion/réfraction dans l'emplacement 'réflexion' (Cliquez sur le bouton 'Aucun' pour choisir la texture).

Dans les paramètres réflexion/réfraction, choisissez l'option 'Du fichier' avec une taille de 1024. Indiquez aussi un nom de préfixe de fichier ('rendu_cubique' par ex,) en cliquant sur l'emplacement 'Vers Fichier:'

Enfin cliquez sur le bouton 'Choisir Objet et rendu textures' afin d'obtenir le rendu en 6 faces.

Voilà, nous disposons maintenant de nos 3 exemples d'images panoramiques, il ne reste plus qu'à réaliser une visionneuse pour chacune d'elles :)

Les fichiers d'exemples sont téléchargeables ici

III> Réalisation des visionneuses

Afin de réaliser nos différentes visionneuses, nous allons nous servir du moteur 3D Papervision3D qui nous permettra de créer nos sphère, cylindre et cube sur lesquels seront appliquées les textures fraîchement crées.

Pour l'installation des sources, rendez-vous ici ou

Pour chacune des visionneuses, la démarche sera identique :

- Créer le monde 3D
- Ajouter notre objet 3D
- Appliquer l'image panoramique sur cet objet
- Ajouter les comportements de la souris

Visionneuse pour les images de type cylindriques

  1. Création du monde 3D

Créez un nouveau projet ActionScript ou un document Flash selon l'IDE que vous utilisez et donnez lui une taille de 800 * 512. Ajoutez ensuite le code de base afin de créer un monde 3D Grâce à Papervision3D :

Actionscript:
  1. package {
  2.  
  3.     import flash.events.Event;
  4.    
  5.     import org.papervision3d.cameras.CameraType;
  6.     import org.papervision3d.materials.WireframeMaterial;
  7.     import org.papervision3d.objects.primitives.Cylinder;
  8.     import org.papervision3d.view.BasicView;
  9.  
  10.  
  11.     [SWF(width='800',height='512',backgroundColor='0x000000',frameRate='30')]
  12.     public class VisionneuseCylindre extends BasicView
  13.     {
  14.         private var cylinder:Cylinder;
  15.        
  16.         public function VisionneuseCylindre()
  17.         {
  18.             super( 800, 512, true, false, CameraType.FREE );
  19.             startRendering();
  20.         }
  21.        
  22.         override protected function onRenderTick(event:Event=null):void
  23.         {
  24.             super.onRenderTick( event );
  25.         }
  26.     }
  27. }

  1. Ajout du cylindre

Pour ajouter un cylindre, nous allons nous servir de la primitive Cylinder :

Actionscript:
  1. package {
  2.  
  3.     import flash.events.Event;
  4.     import org.papervision3d.cameras.CameraType;
  5.     import org.papervision3d.materials.WireframeMaterial;
  6.     import org.papervision3d.objects.primitives.Cylinder;
  7.     import org.papervision3d.view.BasicView;
  8.  
  9.  
  10.     [SWF(width='800',height='512',backgroundColor='0x000000',frameRate='30')]
  11.     public class VisionneuseCylindre extends BasicView
  12.     {
  13.         private var cylinder:Cylinder;
  14.        
  15.         public function VisionneuseCylindre()
  16.         {
  17.             super( 800, 512, true, false, CameraType.FREE );
  18.             startRendering();
  19.            
  20.             cylinder = new Cylinder( new WireframeMaterial( 0xFF0000 ), 100, 200, 16, 1 );
  21.             scene.addChild( cylinder );
  22.            
  23.             camera.z = -400;
  24.         }
  25.        
  26.         override protected function onRenderTick( event:Event=null ):void
  27.         {
  28.             super.onRenderTick( event );
  29.         }
  30.     }
  31. }

Le premier paramètre permet de spécifier la texture a appliquer à l'objet. J'ai pris ici un rendu en fil de fer (Wireframe). Les 2 paramètres suivants représentent le rayon et la hauteur du cylindre. Les 2 derniers sont le nombre de segments horizontaux et verticaux.

Par défaut l'objet est placé aux coordonnées (0,0,0), tout comme la caméra.

Le cylindre est alors visible au centre du document. Comme la caméra est placée à une distance de -400 , vous devriez apercevoir le cylindre comme sur cet exemple (j'ai ajouté volontairement un légère rotation)

Exemple

  1. Ajout de l'image panoramique au cylindre

Pour appliquer une image comme texture à un objet 3D, il existe 3 solutions qui sont la classe BitmapMaterial, BitmapFileMaterial, BitmapAssetMaterial.

- BitmapMaterial permet d'utiliser une image embarquée dans le swf.
- BitmapFileMaterial permet de charger un fichier externe.
- BitmapAssetMaterial permet d'utiliser une image de la librairie Flash.

Nous allons utiliser ici BitmapFileMaterial pour que les personnes qui n'utilisent pas l'IDE Flash ne soient pas lesés ;)

Créez un dossier 'assets' à la racine de votre projet et déposez l'image panoramique cylindrique.

Actionscript:
  1. import org.papervision3d.materials.BitmapFileMaterial;
  2. ...
  3. private static const IMG_URL:String = "assets/rendu_cylindrique.jpg";
  4. ...
  5. var imgMaterial:BitmapFileMaterial = new BitmapFileMaterial( IMG_URL, false );
  6. imgMaterial.doubleSided = true;
  7. ....

Par défaut la texture est placée à l'exterieur de l'objet, c'est pourquoi on utilise la variable doubleSided pour que cette texture soit visible aussi depuis l'interieur du cylindre. Le 2eme paramètre du constructeur de BitmapFileMaterial spécifie si l'on veut un rendu précis ou non pour le Bitmap. Il peut s'avérer très utile dans certains cas ( éviter les déformations sur une texture ) mais est très gourmand en ressource CPU. Il est désactivé ici.
Il ne faut pas oublier de placer maintenant la caméra au centre du cylindre:

Actionscript:
  1. camera.z = 0;

Et d'ajouter une simple rotation pour le moment :

Actionscript:
  1. override protected function onRenderTick( event:Event=null ):void
  2. {
  3.     camera.rotationY += 1;
  4.     super.onRenderTick( event );
  5. }

On peut alors constater que l'image est inversée par rapport à la réalité. C'est normal puisqu'elle est appliquée sur l'exterieur du cylindre. Pour rétablir la vue originale, il suffit de faire un mirroir sur l'image grâce à un logiciel de retouche photo.

Notons aussi qu'il est aussi possible de placer la caméra juste devant le cylindre et de faire tourner le cylindre plutôt que la caméra. Dans ce cas là, il n'est pas nécessaire de retoucher à l'image panoramique et d'utiliser le mode doubleSided.

  1. Ajout des comportements de la souris

Rien de trop compliqué ici. On fait tourner la caméra selon la position du curseur de la souris dans le container.

Le code source final:

Actionscript:
  1. package {
  2.  
  3.     import flash.events.Event;
  4.     import org.papervision3d.cameras.CameraType;
  5.     import org.papervision3d.materials.BitmapFileMaterial;
  6.     import org.papervision3d.objects.primitives.Cylinder;
  7.     import org.papervision3d.view.BasicView;
  8.  
  9.  
  10.     [SWF( width='800', height='512', backgroundColor='0x000000', frameRate='30' )]
  11.     public class VisionneuseCylindre extends BasicView
  12.     {
  13.         private static const IMG_URL:String = "assets/rendu_cylindrique.jpg";
  14.        
  15.         private var cylinder:Cylinder;
  16.        
  17.         public function VisionneuseCylindre()
  18.         {
  19.             super( 800, 512, true, false, CameraType.FREE );
  20.             startRendering();
  21.            
  22.             var imgMaterial:BitmapFileMaterial = new BitmapFileMaterial( IMG_URL, false );
  23.             imgMaterial.doubleSided = true;
  24.  
  25.             cylinder = new Cylinder( imgMaterial, 100, 200, 16, 16 );
  26.             scene.addChild( cylinder );
  27.            
  28.             camera.z = 0;
  29.         }
  30.        
  31.         override protected function onRenderTick( event:Event=null ):void
  32.         {
  33.             camera.rotationY += ( mouseX - ( stage.width/2 ) ) / 50;
  34.             super.onRenderTick( event );
  35.         }
  36.     }
  37. }

Le résultat final

Visionneuse pour les image de type sphériques

Une grande partie du code reste identique. Il suffit de remplacer le cylindre par une sphère, d'appliquer la bonne texture et de rajouter une rotation de la caméra sur la hauteur.

En jouant sur la taille de la sphère, le focus et le zoom de la caméra, on arrive à obtenir un panoramique sans trop de déformation.

Actionscript:
  1. package {
  2.  
  3.     import flash.events.Event;
  4.     import org.papervision3d.cameras.CameraType;
  5.     import org.papervision3d.materials.BitmapFileMaterial;
  6.     import org.papervision3d.objects.primitives.Sphere;
  7.     import org.papervision3d.view.BasicView;
  8.  
  9.  
  10.     [SWF( width='800', height='512', backgroundColor='0x000000', frameRate='30' )]
  11.     public class VisionneuseSphere extends BasicView
  12.     {
  13.         private static const IMG_URL:String = "assets/rendu_spherique.jpg";
  14.         private static var MAX_X_ROTATION:int = 50;
  15.        
  16.         private var sphere:Sphere;
  17.        
  18.         public function VisionneuseSphere()
  19.         {
  20.             super( 800, 512, true, false, CameraType.FREE );
  21.             startRendering();
  22.            
  23.             var imgMaterial:BitmapFileMaterial = new BitmapFileMaterial( IMG_URL, false );
  24.             imgMaterial.doubleSided = true;
  25.  
  26.             sphere = new Sphere( imgMaterial, 1000, 16, 16 );
  27.             scene.addChild( sphere );
  28.            
  29.             camera.z = 0;
  30.             camera.zoom = 5
  31.             camera.focus = 80;
  32.         }
  33.        
  34.         override protected function onRenderTick( event:Event=null ):void
  35.         {
  36.             camera.rotationY += ( mouseX - ( stage.width/2 ) ) / MAX_X_ROTATION;
  37.             camera.rotationX += ( mouseY - ( stage.height/2 ) ) / MAX_X_ROTATION;
  38.            
  39.             //on limite la rotation verticale
  40.             if( camera.rotationX> MAX_X_ROTATION )
  41.             {
  42.                 camera.rotationX = MAX_X_ROTATION;
  43.             }
  44.             if( camera.rotationX <- MAX_X_ROTATION )
  45.             {
  46.                 camera.rotationX = - MAX_X_ROTATION;
  47.             }
  48.             super.onRenderTick( event );
  49.         }
  50.     }
  51. }

Le résultat

Visionneuse pour les images de type cubiques

Pour cette visionneuse, on a 2 possibilités:

  • Créer 6 plans qu'on dispose de telle sorte qu'ils forment un cube. On applique ensuite la texture correspondante à chacune des faces du cube.
  • Créer un objet de type Cube et lui appliquer une liste de BitmapFileMaterial.

Pour cet exemple, j'ai pris la 2eme option.

Actionscript:
  1. package {
  2.  
  3.     import flash.events.Event;
  4.    
  5.     import org.papervision3d.cameras.CameraType;
  6.     import org.papervision3d.materials.BitmapFileMaterial;
  7.     import org.papervision3d.materials.BitmapMaterial;
  8.     import org.papervision3d.materials.utils.MaterialsList;
  9.     import org.papervision3d.objects.primitives.Cube;
  10.     import org.papervision3d.view.BasicView;
  11.  
  12.  
  13.     [SWF( width='800', height='512', backgroundColor='0x000000', frameRate='30' )]
  14.     public class VisionneuseCube extends BasicView
  15.     {
  16.         private static const IMG_BASE_URL:String = "assets/rendu_cubique_";
  17.         private static var MAX_X_ROTATION:int = 50;
  18.        
  19.         private var cube:Cube
  20.        
  21.         public function VisionneuseCube()
  22.         {
  23.             super( 800, 512, true, false, CameraType.FREE );
  24.             startRendering();
  25.            
  26.             var frontMat:BitmapMaterial = new BitmapFileMaterial( IMG_BASE_URL+"FR.jpg" );
  27.             var backMat:BitmapFileMaterial =  new BitmapFileMaterial( IMG_BASE_URL+"BK.jpg" );
  28.             var leftMat:BitmapFileMaterial = new BitmapFileMaterial( IMG_BASE_URL+"LF.jpg" );
  29.             var rightMat:BitmapFileMaterial = new BitmapFileMaterial( IMG_BASE_URL+"RT.jpg" );
  30.             var upMat:BitmapFileMaterial = new BitmapFileMaterial( IMG_BASE_URL+"UP.jpg" );
  31.             var downMat:BitmapFileMaterial = new BitmapFileMaterial( IMG_BASE_URL+"DN.jpg" );
  32.            
  33.             frontMat.doubleSided = true;
  34.             backMat.doubleSided = true;
  35.             leftMat.doubleSided = true;
  36.             rightMat.doubleSided = true;
  37.             upMat.doubleSided = true;
  38.             downMat.doubleSided = true;
  39.            
  40.            
  41.             var imgMaterialList:MaterialsList = new MaterialsList(
  42.             {
  43.                front: frontMat,
  44.                back: backMat,
  45.                left: leftMat,
  46.                right: rightMat,
  47.                top: upMat,
  48.                bottom: downMat
  49.          });
  50.          
  51.  
  52.             cube = new Cube( imgMaterialList, 1000, 1000, 1000, 16, 16, 16 );
  53.             scene.addChild( cube );
  54.            
  55.             camera.z = 0;
  56.         }
  57.        
  58.         override protected function onRenderTick(event:Event=null):void
  59.         {
  60.             camera.rotationY += ( mouseX - ( stage.width/2 ) ) / MAX_X_ROTATION;
  61.             camera.rotationX += ( mouseY - ( stage.height/2 ) ) / MAX_X_ROTATION;
  62.            
  63.             //on limite la rotation verticale
  64.             if( camera.rotationX> MAX_X_ROTATION )
  65.             {
  66.                 camera.rotationX = MAX_X_ROTATION;
  67.             }
  68.             if( camera.rotationX <- MAX_X_ROTATION )
  69.             {
  70.                 camera.rotationX = - MAX_X_ROTATION;
  71.             }
  72.             super.onRenderTick( event );
  73.         }
  74.     }
  75. }

Le résultat(Le téléchargement des images peut prendre un peu de temps, aucune gestion de préchargement a été intégré pour garder l'exemple simple )

J'espere que ce tutorial vous sera utile. Le prochain article se consacrera à la création de hotspots dans un panorama.


Tags: , ,


Fatal error: Call to undefined function: st_related_posts() in /homez.144/astrois/www/blog/wp-content/themes/simplicitybright/single.php on line 14