Dans mon précédent tutoriel Shoot Out Stars avec le moteur de particules Stardust, j'avais expliqué le flux de travail de base de Stardust. Cette fois, nous allons aller plus loin et examiner quelques techniques permettant de créer de véritables effets de particules 3D.!
Nous allons commencer par une démonstration de l'utilisation du moteur 3D natif de Stardust. Ensuite, je vais vous montrer comment amener Stardust à travailler avec Papervision3D. nous allons créer des effets de particules 3D avec les classes Particles et DisplayObject3D de Papervision3D.
Nous allons reprendre là où nous nous étions arrêtés dans le premier tutoriel. La dernière fois, nous avons créé des particules en forme d'étoile et de cercle partant d'un point, atteignant une taille maximale puis se réduisant à zéro, tout en progressant progressivement plus lentement (effet d'amortissement). Cette fois, nous ferons la même chose, mais en 3D. Au lieu que les particules se déplacent en cercle, elles se déplacent en sphère.
Comme auparavant, créez d'abord un nouveau document Flash aux dimensions de 640x400, une cadence d'images de 60 images par seconde et un arrière-plan sombre (j'ai utilisé un dégradé de bleu foncé).
Dessinez une étoile et un cercle blanc, puis convertissez-les en symboles, séparément. Ce sont les deux symboles que nous utiliserons plus tard sous forme de particules. Nommez le symbole étoile "Star" et le symbole circulaire "Circle", exportés pour ActionScript avec les mêmes noms de classe..
(Si vous n'êtes pas vraiment un artiste, vous pouvez télécharger la source en haut de la page et utiliser mes symboles de la bibliothèque de ma FLA.)
Cliquez sur Fenêtre> Composants pour afficher le panneau Composants, puis faites glisser un bouton du dossier Interface utilisateur sur la scène. Définissez le libellé sur "Pause" et nommez-le "pause_btn". Nous allons utiliser ce bouton pour mettre en pause les effets de particules 3D, permettant ainsi aux utilisateurs de faire pivoter la caméra afin d'obtenir un meilleur aperçu de l'environnement 3D..
Créez une nouvelle classe de documents et nommez-la StarParticles3D.
package import flash.display.Sprite; Classe publique StarParticles3D étend Sprite fonction publique StarParticles ()
Vous ne savez pas comment utiliser une classe de document? Lire cette astuce.
Les trois principaux packages de Stardust sont:
Dans le didacticiel précédent, nous avons utilisé des initialiseurs et des actions des packages common et twoD. Dans ce tutoriel, nous utiliserons toujours des éléments du package commun, mais pas du package twoD. Au lieu de cela, nous allons utiliser des éléments du paquet threeD.
La structure de classe du package threeD est à peu près identique à celle du package twoD, à la différence que les éléments ont une dimension supplémentaire. Un élément 3D possède le même nom que son homologue 2D, mais son nom se termine par "3D". Par exemple, le Move3D L'action dans le package 3D met à jour les positions des particules dans l'espace 3D en fonction des vitesses, tout comme son homologue 2D dans le package 2D, Bouge toi action.
Créez un nouveau fichier AS appelé StarEmitter.as; à l'intérieur, créer une nouvelle classe StarEmitter, qui étend la classe Emitter3D:
package import idv.cjcat.stardust.threeD.emitters.Emitter3D; // n'oublie pas d'importer ceci! classe publique StarEmitter étend Emitter3D fonction publique StarEmitter (clock: Clock) // passe l'objet clock au constructeur de la superclasse super (clock);
Rappelez-vous le paramètre d'horloge? Il sert à contrôler le taux de création de particules. Nous devons l'inclure dans la fonction constructeur pour pouvoir lui passer une horloge plus tard..
Puisque nous autorisons les utilisateurs à mettre en pause les effets de particules, nous allons regrouper toutes les actions dans un seul objet CompositeAction, qui est essentiellement un groupe d’actions. En désactivant cette action composite unique, nous pouvons "désactiver" toutes les actions sous-jacentes. Déclarez une variable pour une action composite dans la classe emitter. Nous accéderons à cette variable dans la classe de document, elle doit donc être publique:
public var pausibleActions: CompositeAction;
Déclarez les constantes qui seront utilisées comme paramètres de particule dans la classe d'émetteur. Nous avons déjà expliqué le but de ces constantes dans le didacticiel précédent. La plupart des noms sont explicites. Ceux-ci vont à l'intérieur de la classe mais en dehors de la fonction constructeur. N'hésitez pas à revenir ici plus tard et à modifier les chiffres pour voir les effets.
Const statique privée LIFE_AVG: Number = 30; Const statique privée LIFE_VAR: Number = 10; Constante statique privée SCALE_AVG: Number = 1; Constante statique privée SCALE_VAR: Number = 0.4; Const statique privée GROWING_TIME: Number = 5; Const statique privée SHRINKING_TIME: Number = 10; Constante statique privée SPEED_AVG: Number = 30; Constante statique privée SPEED_VAR: Number = 10; Constante statique privée OMEGA_AVG: Number = 0; Constante statique privée OMEGA_VAR: Number = 5; Constante statique privée DAMPING: Number = 0.1;
Dans le précédent tutoriel, j'ai montré comment utiliser SwitchInitializer pour créer des particules avec différents objets d'affichage. J'utilisais l'initialiseur DisplayObjectClass, qui initialise l'apparence des particules avec des objets d'affichage. C'était pour les effets de particules 2D; nous allons utiliser ici son pendant 3D, l’initialiseur DisplayObject3D.
Ajoutez le code suivant à la fonction constructeur de l'émetteur:
// commutateurs d'initialisation pour les particules en étoile et en cercle var doc1: DisplayObjectClass3D = new DisplayObjectClass3D (Star); var doc2: DisplayObjectClass3D = new DisplayObjectClass3D (Circle); var si: SwitchInitializer = new SwitchInitializer ([doc1, doc2], [1, 1]); addInitializer (si);
Identique au tutoriel précédent. ajoutez les autres initialiseurs indiqués ci-dessous. Notez que certains portent des noms similaires à ceux du tutoriel précédent, mais se terminent par "3D".
Ce code va dans la fonction constructeur de StarEmitter:
addInitializer (nouvelle vie (nouvelle UniformRandom (LIFE_AVG, LIFE_VAR))); addInitializer (nouvelle échelle (nouvelle unité UniformRandom (SCALE_AVG, SCALE_VAR))); addInitializer (new Position3D (new SinglePoint3D ())); addInitializer (nouveau Velocity3D (nouveau SphereShell (0, 0, 0, SPEED_AVG, SPEED_VAR))); addInitializer (nouvelle Rotation3D (null, null, nouvelle UniformRandom (0, 180))); addInitializer (nouvelle Omega3D (null, null, nouvelle UniformRandom (OMEGA_AVG, OMEGA_VAR)));
Créez une action composite et ajoutez-lui des actions. Ajoutez ensuite cette action composite à l’émetteur; cela fera que les particules effectuent les actions. Vous avez vu ces actions dans le didacticiel précédent (certaines d'entre elles en version 2D), je ne les expliquerai donc pas de nouveau. Encore une fois, ce code va dans la fonction constructeur de StarEmitter:
pausibleActions = new CompositeAction (); pausibleActions.addAction (new Age ()); pausibleActions.addAction (new DeathLife ()); pausibleActions.addAction (nouveau Move3D ()); pausibleActions.addAction (new Spin3D ()); pausibleActions.addAction (nouveau Damping3D (DAMPING)); pausibleActions.addAction (nouvelle échelleCurve (GROWING_TIME, SHRINKING_TIME)); addAction (pausibleActions);
D'accord, nous en avons fini avec l'émetteur. Il est maintenant temps de construire notre classe de documents.
Commencez par déclarer les constantes pour le rayon de la caméra en orbite, la distance de la caméra par rapport à l'origine et le taux de l'émetteur:
Const statique privée CAMERA_RADIUS: Number = 250; Const statique privée PARTICLE_RATE: Number = 0.5;
(Comme auparavant, les constants vont à l'intérieur de la classe mais à l'extérieur de la fonction constructeur.)
Ensuite, déclarez les variables pour un émetteur, une horloge fixe et un DisplayObjectRenderer3D (au même endroit que les consts):
Emetteur var privé: StarEmitter; horloge var privée: SteadyClock; convertisseur de rendu privé: DisplayObjectRenderer3D;
Dans le constructeur, initialisez l’horloge, l’émetteur et le rendu. Définissez également la position et la direction de la caméra initiale, en faisant en sorte qu’elle regarde l’origine:
// crée l'horloge et l'émetteur clock = new SteadyClock (PARTICLE_RATE); émetteur = nouveau StarEmitter (horloge); // nous pouvons le faire parce que nous avons donné un paramètre d'horloge au constructeur de StarEmitter // créer le rendu et son conteneur sprite var conteneur: Sprite = new Sprite (); conteneur.x = 320, conteneur.y = 200; renderer = new DisplayObjectRenderer3D (conteneur); renderer.addEmitter (émetteur); // ajoute le conteneur à la scène addChild (conteneur); // ajoute le bouton de pause à nouveau pour qu'il soit au-dessus du conteneur addChild (pause_btn); // définit la position et la direction initiales de la caméra renderer.camera.position.set (0, 0, -CAMERA_RADIUS); renderer.camera.direction.set (0, 0, CAMERA_RADIUS);
Créez une fonction de gestionnaire dans la classe de document pour gérer l'événement click du bouton de pause:
fonction privée togglePause (e: MouseEvent): void if (e.target.label == "Pause") e.target.label = "Reprendre"; clock.ticksPerCall = 0; // arrête l'horloge emitter.pausibleActions.active = false; // désactivation des actions de l'émetteur else e.target.label = "Pause"; clock.ticksPerCall = PARTICLE_RATE; // redémarre l'horloge emitter.pausibleActions.active = true; // réactiver les actions de l'émetteur
… Puis enregistrez l'auditeur pour le bouton de pause, dans la fonction constructeur:
pause_btn.addEventListener (MouseEvent.CLICK, togglePause);
Créez un gestionnaire pour l'événement ENTER_FRAME. Ceci est notre boucle principale. Il met à jour la position de la caméra en appelant la méthode updateCamera () (que nous coderons dans une minute) et appelle la méthode step () de l'émetteur, qui maintient les effets de particules en cours d'exécution:
fonction privée mainLoop (e: Event): void updateCamera (); emitter.step ();
Encore une fois, enregistrez un auditeur dans le constructeur:
addEventListener (Event.ENTER_FRAME, mainLoop);
Définissez maintenant la méthode updateCamera () appelée à l'étape précédente. Ceci est utilisé pour déplacer la caméra dans un espace 3D en fonction de la position de la souris. (Si vous souhaitez plus d'informations sur son fonctionnement, consultez cet article de Wikipedia.)
Les nombres magiques utilisés pour générer thêta et phi ne sont que le résultat d'essais et d'erreurs; n'hésitez pas à essayer vos propres équations.
fonction privée updateCamera (): void var theta: Number = 0.02 * (mouseX - 320); var phi: Number = 0.02 * (mouseY - 200); phi = StardustMath.clamp (phi, -StardustMath.HALF_PI, StardustMath.HALF_PI); var x: Number = CAMERA_RADIUS * Math.cos (thêta) * Math.cos (phi); var y: Number = CAMERA_RADIUS * Math.sin (phi); var z: Number = CAMERA_RADIUS * Math.sin (thêta) * Math.cos (phi); renderer.camera.position.set (x, y, z); renderer.camera.direction.set (-x, -y, -z);
Notez que j'ai utilisé la méthode StardustMath.clamp (); cela garantit que la valeur de phi est maintenue entre la moitié PI positive et négative.
Ok, nous avons fini! C'est tout ce dont nous avons besoin pour qu'un émetteur 3D fonctionne avec le moteur 3D natif de Stardust. Regardons le résultat. Vous pouvez cliquer sur le bouton de pause pour suspendre l'effet de particules et déplacer la souris pour mettre la caméra en orbite:
Démo Voir en ligneSi vous souhaitez voir le code source complet, consultez le dossier intitulé "01 - Stardust Native 3D Engine" dans Source..
Passer du moteur 3D natif de Stardust à Papervision3D est simple. Nous devrons simplement utiliser un moteur de rendu et un initialiseur d'objet d'affichage différents.
(Vous n'avez jamais utilisé Papervision3D auparavant? Consultez le didacticiel de ce débutant.)
Premièrement, nous allons utiliser la classe Particles de Papervision3D. Vous pourriez ne pas être au courant de cela; Je vais vous montrer plus tard comment utiliser la classe DisplayObject3D la plus courante..
Modifiez le code suivant dans la classe emitter:
var doc1: DisplayObjectClass3D = new DisplayObjectClass3D (Star); var doc2: DisplayObjectClass3D = new DisplayObjectClass3D (Circle);
pour ça:
var mat1: MovieParticleMaterial = new MovieParticleMaterial (new Star ()); var mat2: MovieParticleMaterial = new MovieParticleMaterial (new Circle ()); var doc1: PV3DParticle = new PV3DParticle ([mat1]); var doc2: PV3DParticle = new PV3DParticle ([mat2]);
Comme vous le savez peut-être déjà, la classe MovieParticleMaterial nous permet d'utiliser des objets d'affichage comme apparence de particules dans Papervision3D. Nous créons une instance Star and Circle à utiliser comme matériau particulaire. L'initialiseur PV3DParticle prend la place de l'initialiseur DisplayObjectClass3D; son constructeur accepte un tableau de paramètres, qui seront tous ajoutés à un objet Particles.
C’est tout ce que nous avons à faire en ce qui concerne l’émetteur. Ensuite, nous allons modifier la classe de document.
Le conteneur cible de notre rendu n'est plus un objet Sprite. Au lieu de cela, nous allons créer des particules dans un objet Particules. Nous devrons changer le type de rendu de DisplayObjectRenderer3D à PV3DParticleRenderer.
Déclarez les variables suivantes pour les objets liés à Papervision3D:
scène var privée: SceneObject3D; Particules de var privées: Particules; caméra var privée: Camera3D; origine de la variable privée: DisplayObject3D; private var renderEngine: BasicRenderEngine; fenêtre d'affichage privée: Viewport3D;
Le code dans le constructeur de la classe de document est maintenant:
initPV3D (); //c'est nouveau! clock = new SteadyClock (PARTICLE_RATE); émetteur = nouveau StarEmitter (horloge); renderer = new PV3DParticleRenderer (particules); //c'est nouveau! renderer.addEmitter (émetteur); pause_btn.addEventListener (MouseEvent.CLICK, togglePause); addEventListener (Event.ENTER_FRAME, mainLoop);
La méthode initPV3D () configure l'environnement Papervision3D. Voici le code:
fonction privée initPV3D (): void // crée la scène scene = new SceneObject3D (); // crée l'objet particules Partules = new Particles (); // crée la caméra et initialise sa position camera = new Camera3D (); camera.position.x = 0; camera.position.y = 0; camera.position.z = -CAMERA_RADIUS; // crée un DO3D représentant l'origine origine = new DisplayObject3D (); origine.x = origine.y = origine.z = 0; // pointe la caméra vers l'origine camera.target = origin; scene.addChild (origine); scene.addChild (particules); // crée le moteur de rendu et la fenêtre renderEngine = new BasicRenderEngine (); viewport = new Viewport3D (640, 400); // ajoute la fenêtre à la scène addChild (fenêtre); // ajoute à nouveau le bouton de pause afin qu'il se trouve en haut de la fenêtre de la fenêtre de visualisation addChild (pause_btn);
Maintenant, Stardust ne met à jour que les propriétés des objets 3D; Le moteur de rendu de Papervision3D assume la responsabilité du rendu. Voici à quoi ressemble notre nouvelle boucle principale:
fonction privée mainLoop (e: Event): void updateCamera (); emitter.step (); renderEngine.renderScene (scène, caméra, fenêtre d'affichage); //c'est nouveau!
Maintenant que nous utilisons la caméra de Papervision3D, nous devrons également modifier la méthode updateCamera ():
fonction privée updateCamera (): void var theta: Number = 0.02 * (mouseX - 320); var phi: Number = 0.02 * (mouseY - 200); phi = StardustMath.clamp (phi, -StardustMath.HALF_PI, StardustMath.HALF_PI); var x: Number = CAMERA_RADIUS * Math.cos (thêta) * Math.cos (phi); var y: Number = -CAMERA_RADIUS * Math.sin (phi); // remarque que ceci est maintenant négatif var z: Number = CAMERA_RADIUS * Math.sin (thêta) * Math.cos (phi); camera.x = x; // nous mettons à jour chacune des propriétés x, y, z de la caméra de PV3D séparément camera.y = y; camera.z = z;
D'accord, nous sommes passés avec succès du moteur 3D natif de Stardust à Papervision3D. Voyons maintenant le résultat. Notez l'effet de pixellisation sur les particules. En effet, Papervision3D dessine d’abord des objets vectoriels dans des bitmaps avant de les utiliser comme matériaux particulaires.
Démo Voir en ligneVous trouverez tout le code source correspondant dans le dossier "02 - Papervision3D Particles"..
Jusqu'à présent, nous avons travaillé avec des "panneaux d'affichage 2D" - des objets plats, comme du papier. Il est possible de créer de "vrais" objets de particules 3D, tels que les objets DisplayObject3D de Papervision3D. Nous allons simplement devoir utiliser un autre initialiseur. Passons maintenant à la dernière partie de ce tutoriel. Nous allons créer des particules cubiques rouges et bleues.
Nous allons changer l'initialiseur concernant l'apparence des particules pour la dernière fois.
Avant cela, déclarez une variable LightObject3D dans la classe de l'émetteur. Nous allons utiliser FlatShadeMaterial pour les objets DisplayObject3D, qui nécessitent une source de lumière. De plus, déclarez les constantes suivantes - nous les utiliserons comme paramètres pour FlastShadeMaterial et pour déterminer la taille des cubes:
var var public: LightObject3D; Constante statique privée LIGHT_COLOR_1: uint = 0xCC3300; Constante statique privée LIGHT_COLOR_2: uint = 0x006699; Const statique privée AMBIENT_COLOR_1: uint = 0x881100; Const statique privée AMBIENT_COLOR_2: uint = 0x002244; Constante statique privée CUBE_SIZE: Number = 15;
Maintenant changez le code suivant dans la classe emitter:
var mat1: MovieParticleMaterial = new MovieParticleMaterial (new Star ()); var mat2: MovieParticleMaterial = new MovieParticleMaterial (new Circle ()); var doc1: PV3DParticle = new PV3DParticle ([mat1]); var doc2: PV3DParticle = new PV3DParticle ([mat2]);
pour ça:
light = new LightObject3D (); var mat1: FlatShadeMaterial = new FlatShadeMaterial (light, LIGHT_COLOR_1, AMBIENT_COLOR_1); var mat2: FlatShadeMaterial = new FlatShadeMaterial (light, LIGHT_COLOR_2, AMBIENT_COLOR_2); var matList1: MaterialsList = new MaterialsList (all: mat1); var matList2: MaterialsList = new MaterialsList (all: mat2); var params1: Array = [matList1, CUBE_SIZE, CUBE_SIZE, CUBE_SIZE]; var params2: Array = [matList2, CUBE_SIZE, CUBE_SIZE, CUBE_SIZE]; var doc1: PV3DDisplayObject3DClass = new PV3DDisplayObject3DClass (Cube, params1); var doc2: PV3DDisplayObject3DClass = new PV3DDisplayObject3DClass (Cube, params2);
La nouvelle apparence de la particule sera initialisée sous forme de cubes 3D rouges et bleus. Le premier paramètre de constructeur pour l'initialiseur PV3DDisplayObject3DClass est la classe que nous souhaitons instancier pour les particules (ici, c'est la classe Cube) et le second paramètre est un tableau de paramètres de constructeur pour cette classe Cube..
Auparavant, comme nous travaillions avec des "panneaux d'affichage 2D", seule la rotation autour de l'axe Z importait. Maintenant que nous travaillons avec de vrais objets 3D, nous devons passer trois références d'objet aléatoire aux constructeurs Rotation3D et Omega3D, une pour chaque axe..
Modifiez le code suivant dans la classe emitter:
addInitializer (nouvelle Rotation3D (null, null, nouvelle UniformRandom (0, 180))); addInitializer (nouvelle Omega3D (null, null, nouvelle UniformRandom (OMEGA_AVG, OMEGA_VAR)));
pour ça:
var rotationRandom: UniformRandom = new UniformRandom (0, 180); var omegaRandom: UniformRandom = new UniformRandom (OMEGA_AVG, OMEGA_VAR); addInitializer (nouveau Rotation3D (rotationRandom, rotationRandom, rotationRandom)); addInitializer (nouvel Omega3D (omegaRandom, omegaRandom, omegaRandom));
Cette fois, au lieu d'utiliser un objet Particules comme conteneur de particules, nous utilisons un DisplayObject3D comme conteneur. Déclarez une variable pour ce conteneur dans la classe de document:
conteneur var privé: DisplayObject3D;
En outre, nous aurons besoin d'un autre type de moteur de rendu pour créer des particules dans le nouveau conteneur. Changez le type de rendu de PV3DParticleRenderer en PV3DDisplayObject3DRenderer. Le code dans le constructeur de la classe de document devrait maintenant ressembler à ceci:
initPV3D (); clock = new SteadyClock (PARTICLE_RATE); émetteur = nouveau StarEmitter (horloge); renderer = new PV3DDisplayObject3DRenderer (conteneur); // cela a changé! renderer.addEmitter (émetteur); pause_btn.addEventListener (MouseEvent.CLICK, togglePause); addEventListener (Event.ENTER_FRAME, mainLoop);
Dans la fonction initPV3D (), nous devons maintenant initialiser la variable conteneur et l'ajouter à la scène. Ajoutez ces deux lignes à la fin de cette fonction:
conteneur = new DisplayObject3D (); scene.addChild (conteneur);
Dans la méthode updateCamera (), nous souhaitons que la lumière suive la caméra, nous aurons donc l’illusion que la lumière "sort" toujours de nos yeux. Changer le code suivant:
camera.x = x; camera.y = y; camera.z = z;
pour ça:
emitter.light.x = camera.x = x; emitter.light.y = camera.y = y; emitter.light.z = camera.z = z;
Maintenant, la source de lumière est toujours au même point que la caméra.
Oui, nous avons enfin terminé ce tutoriel. Pas plus de codage. Jetons un coup d'oeil à notre résultat final, avec des cubes 3D fantaisistes rouges et bleus!
Démo Voir en ligneLe code source de cela se trouve dans le dossier "Papervision3D DisplayObject3D".
Le processus de création d'effets de particules 3D avec Stardust est pratiquement le même que celui utilisé pour les effets 2D. Vous venez de choisir un ensemble différent d'initialiseurs, d'actions et de rendus. Stardust prend également en charge d’autres moteurs 3D, notamment ZedBox et ND3D. L'utilisation est presque la même. Vous devrez simplement utiliser un ensemble différent d'initialiseurs et de rendus. Vous pouvez même étendre les classes Initializer, Action et Renderer pour qu'elles fonctionnent avec les moteurs 3D de votre choix.!
Maintenant que vous avez les bases, pourquoi ne pas revenir aux consts créés à l’étape 6 et jouer avec eux pour voir les effets?
J'espère que ce tutoriel vous aidera à mieux comprendre Stardust et à vous familiariser avec le flux de travail de Stardust et à vous y familiariser davantage. Merci d'avoir lu!