Cree efectos 3D con el motor de partículas Stardust

En mi tutorial anterior, Shoot Out Stars con Stardust Particle Engine, expliqué el flujo de trabajo básico de Stardust. Esta vez, iremos más allá y examinaremos un par de técnicas para crear verdaderos efectos de partículas en 3D.!


Introducción

Comenzaremos con una demostración de cómo usar el motor 3D nativo de Stardust. Luego, le mostraré cómo hacer que Stardust trabaje con Papervision3D; Crearemos efectos de partículas en 3D con la clase de partículas de Papervision3D y la clase de DisplayObject3D..


Previamente…

Vamos a retomar lo que dejamos en el primer tutorial. La última vez, creamos partículas de estrellas y círculos que salían de un punto, crecían a un tamaño máximo y luego se reducían a nada, mientras nos movíamos gradualmente más lento con el tiempo (llamado efecto de amortiguación). Esta vez, haremos lo mismo, pero en 3D. En lugar de que las partículas se muevan en un círculo, se moverán en una esfera.


Paso 1: Crear un nuevo documento de Flash

Al igual que antes, primero cree un nuevo documento Flash con dimensiones de 640x400, una velocidad de fotogramas de 60 fps y un fondo oscuro (utilicé un degradado azul oscuro).


Paso 2: dibujar las partículas

Dibuja una estrella y un círculo blanco, luego conviértelos en símbolos, por separado. Estos son los dos símbolos que usaremos más adelante como partículas. Nombre el símbolo de estrella "Estrella" y el símbolo de círculo "Círculo", exportado para ActionScript con los mismos nombres de clase.

(Si no eres un gran artista, puedes descargar la fuente en la parte superior de la página y usar mis símbolos de la biblioteca de mi FLA).


Paso 3: Crea el botón de pausa

Hacer clic Ventana> Componentes para abrir el Panel de Componentes, luego arrastre un Botón desde la carpeta de Interfaz de Usuario al escenario. Establezca la etiqueta en "Pausa" y llámela "pause_btn". Vamos a utilizar este botón para pausar los efectos de partículas en 3D, lo que permitirá a los usuarios girar la cámara para conocer mejor el entorno 3D..


Paso 4: Crear la clase de documento

Crea una nueva clase de documento y llámala StarParticles3D.

 paquete import flash.display.Sprite; clase pública StarParticles3D extiende Sprite función pública StarParticles () 

¿No está seguro de cómo usar una clase de documento? Lea este consejo rápido.


Inicializadores 3D y Acciones

Los tres paquetes principales en Stardust son:

  • idv.cjcat.stardust.common: contiene elementos generales para efectos de partículas 2D y 3D.
  • idv.cjcat.stardust.twoD: contiene elementos específicos para efectos de partículas 2D.
  • idv.cjcat.stardust.threeD: contiene elementos específicos para efectos de partículas 3D.

En el tutorial anterior, utilizamos inicializadores y acciones de los paquetes comunes y twoD. En este tutorial, seguiremos utilizando elementos del paquete común, pero no del paquete twoD. En su lugar, utilizaremos elementos del paquete threeD..

La estructura de clase del paquete threeD es bastante parecida a la del paquete twoD, excepto que los elementos tienen una dimensión adicional. Un elemento 3D posee el mismo nombre que su homólogo 2D, pero su nombre termina con "3D". Por ejemplo, el Move3D La acción en el paquete 3D actualiza las posiciones de las partículas en el espacio 3D según las velocidades, al igual que su contraparte 2D en el paquete 2D, el Movimiento acción.


Paso 5: Extender el Emisor

Crear un nuevo archivo AS llamado StarEmitter.as; Dentro de ella, crea una nueva clase. StarEmitter, que amplía la clase Emitter3D:

 paquete import idv.cjcat.stardust.threeD.emitters.Emitter3D; // ¡No olvides importar esto! clase pública StarEmitter extiende Emitter3D función pública StarEmitter (reloj: Reloj) // pasa el objeto de reloj al constructor de la superclase super (reloj); 

¿Recuerdas el parámetro Reloj? Se utiliza para controlar la tasa de creación de partículas. Necesitamos incluirlo en la función de constructor, para poder pasarle un Reloj más adelante..

Ya que estamos permitiendo a los usuarios pausar los efectos de partículas, vamos a empaquetar todas las acciones en un solo objeto CompositeAction, que es esencialmente un grupo de acciones. Al desactivar esta acción compuesta única, podemos "desactivar" todas las acciones subyacentes. Declare una variable para una acción compuesta en la clase de emisor. Accederemos a esta variable en la clase de documento, por lo que debe ser pública:

 public var pausibleActions: CompositeAction;

Paso 6: Declara las constantes de partículas

Declare las constantes que se utilizarán como parámetros de partículas en la clase de emisor. Ya hemos cubierto el propósito de estas constantes en el tutorial anterior. La mayoría de los nombres se explican por sí mismos. Estos van dentro de la clase pero fuera de la función constructora. Siéntase libre de volver aquí más tarde y alterar los números para ver los efectos.

 constata estática privada LIFE_AVG: Número = 30; constata estática privada LIFE_VAR: Número = 10; constata estática privada SCALE_AVG: Número = 1; constata estática privada SCALE_VAR: Número = 0.4; constata estática privada GROWING_TIME: Número = 5; constata estática privada SHRINKING_TIME: Número = 10; constata estática privada SPEED_AVG: Número = 30; constata estática privada SPEED_VAR: Number = 10; constata estática privada OMEGA_AVG: Número = 0; constata estática privada OMEGA_VAR: Número = 5; DAMPING estático privado: Número = 0.1;

Paso 7: el inicializador de interruptor para objetos de visualización de partículas

En el tutorial anterior, demostré cómo usar el SwitchInitializer para crear partículas con diferentes objetos de visualización. Estaba usando el inicializador DisplayObjectClass, que inicializa la apariencia de las partículas con objetos de visualización. Eso fue para efectos de partículas 2D; Aquí vamos a usar su contraparte 3D, el inicializador DisplayObject3D..

Agregue el siguiente código a la función constructora del emisor:

 // cambiar inicializadores para partículas de estrella y círculo var doc1: DisplayObjectClass3D = new DisplayObjectClass3D (Star); var doc2: DisplayObjectClass3D = new DisplayObjectClass3D (Circle); var si: SwitchInitializer = new SwitchInitializer ([doc1, doc2], [1, 1]); addInitializer (si);

Paso 8: Agregue los inicializadores restantes

Igual que el tutorial anterior; agregue los otros inicializadores que se muestran a continuación. Tenga en cuenta que algunos de ellos tienen nombres similares a los del tutorial anterior, pero terminan en "3D".

  • El inicializador Position3D inicializa las posiciones de partículas. Al igual que su homólogo 2D, el inicializador de posición, acepta un parámetro de constructor, un objeto de zona. Sin embargo, esta vez no acepta un objeto de Zona, que representa una zona 2D; en su lugar, acepta un objeto Zone3D, que representa una zona en el espacio 3D. La clase SinglePoint3D extiende la clase Zone3D y es la versión 3D de la clase SinglePoint.
  • Lo mismo ocurre con la clase Velocity3D. La clase SphereShell es esencialmente la versión 3D de la clase SectorZone. Aquí establecemos el centro de la esfera de la esfera en (0, 0, 0), el radio promedio en SPEED_AVG y la variación del radio en SPEED_VAR.
  • Los inicializadores de Rotation3D y Omega3D funcionan exactamente igual que sus homólogos 2D, Rotation y Omega. Sin embargo, hay una pequeña diferencia sobre los parámetros del constructor: aceptan tres objetos aleatorios en lugar de uno. Esto se debe a que ahora, en el espacio 3D, hay tres ejes de rotación, por lo que requieren tres valores de rotación aleatorios para estos ejes. En este ejemplo, estamos creando "carteles en 2D" en el espacio 3D (es decir, objetos planos), por lo que solo es evidente la rotación del eje Z; Es por eso que los primeros dos parámetros, objetos aleatorios para los ejes X e Y, se asignan con valores nulos.

Este código va en la función de constructor de StarEmitter:

 addInitializer (new Life (nuevo UniformRandom (LIFE_AVG, LIFE_VAR))); addInitializer (nueva escala (nuevo UniformRandom (SCALE_AVG, SCALE_VAR))); addInitializer (nuevo Position3D (nuevo SinglePoint3D ())); addInitializer (nuevo Velocity3D (nuevo SphereShell (0, 0, 0, SPEED_AVG, SPEED_VAR))); addInitializer (nuevo Rotation3D (nulo, nulo, nuevo UniformRandom (0, 180))); addInitializer (nuevo Omega3D (nulo, nulo, nuevo UniformRandom (OMEGA_AVG, OMEGA_VAR)));

Paso 9: Añadir las acciones

Cree una acción compuesta y agréguele algunas acciones. Luego agregue esta acción compuesta al emisor; Esto hará que las partículas realicen las acciones. Has visto estas acciones en el tutorial anterior (algunas de ellas en versión 2D), así que no las explicaré de nuevo. De nuevo, este código entra en la función de constructor de StarEmitter:

 pausibleActions = new CompositeAction (); pausibleActions.addAction (new Age ()); pausibleActions.addAction (new DeathLife ()); pausibleActions.addAction (new Move3D ()); pausibleActions.addAction (new Spin3D ()); pausibleActions.addAction (nuevo Damping3D (DAMPING)); pausibleActions.addAction (nuevo ScaleCurve (GROWING_TIME, SHRINKING_TIME)); addAction (pausibleActions);

Paso 10: Volver a la clase de documentos

Está bien, hemos terminado con el emisor. Ahora es el momento de construir nuestra clase de documentos.

Primero, declare las constantes para el radio de la cámara en órbita, la distancia de la cámara desde el origen y la velocidad del emisor:

 constata estática privada CAMERA_RADIUS: Número = 250; constata estática privada PARTICLE_RATE: Number = 0.5;

(Como antes, consts va dentro de la clase pero fuera de la función del constructor).

Luego, declare las variables para un emisor, un reloj estable y un DisplayObjectRenderer3D (en el mismo lugar que los consts):

 emisor de var privado: StarEmitter; reloj var privado: SteadyClock; procesador de var privado: DisplayObjectRenderer3D;

En el constructor, inicialice el reloj, el emisor y el renderizador. Además, establece la posición y la dirección de la cámara inicial, haciendo que mire el origen:

 // crear el reloj y el reloj del emisor = nuevo SteadyClock (PARTICLE_RATE); emisor = nuevo StarEmitter (reloj); // podemos hacer esto porque le dimos al constructor de StarEmitter un parámetro de reloj // crear el renderizador y su contenedor sprite var container: Sprite = new Sprite (); container.x = 320, container.y = 200; renderer = new DisplayObjectRenderer3D (contenedor); renderer.addEmitter (emisor); // agregar el contenedor a la etapa addChild (contenedor); // agrega el botón de pausa nuevamente para que esté encima del contenedor addChild (pause_btn); // establece la posición inicial de la cámara y la dirección renderer.camera.position.set (0, 0, -CAMERA_RADIUS); renderer.camera.direction.set (0, 0, CAMERA_RADIUS);

Paso 11: Programar la pausa

Cree una función de controlador en la clase de documento para controlar el evento de clic del botón de pausa:

 función privada togglePause (e: MouseEvent): void if (e.target.label == "Pause") e.target.label = "Resume"; clock.ticksPerCall = 0; // detiene el reloj emitter.pausibleActions.active = false; // desactivar las acciones del emisor else e.target.label = "Pausa"; clock.ticksPerCall = PARTICLE_RATE; // reinicia el reloj emitter.pausibleActions.active = true; // reactivar las acciones del emisor

... luego registre el oyente para el botón de pausa, en la función de constructor:

 pause_btn.addEventListener (MouseEvent.CLICK, togglePause);

Paso 12: El bucle principal

Crea un controlador para el evento ENTER_FRAME. Este es nuestro bucle principal. Actualiza la posición de la cámara llamando al método updateCamera () (que codificaremos en un minuto) y llama al método step () del emisor, que mantiene los efectos de partículas en ejecución:

 Función privada mainLoop (e: Event): void updateCamera (); emitter.step (); 

De nuevo, registre un oyente en el constructor:

 addEventListener (Event.ENTER_FRAME, mainLoop);

Paso 13: Actualizar la posición de la cámara

Ahora defina el método updateCamera () llamado en el paso anterior. Esto se utiliza para mover la cámara en el espacio 3D dependiendo de la posición del ratón. (Si desea más información sobre cómo funciona, consulte este artículo de Wikipedia).

Los números mágicos utilizados para generar theta y phi son solo el resultado de prueba y error; siéntete libre de probar tus propias ecuaciones.

 función privada updateCamera (): void var theta: Number = 0.02 * (mouseX - 320); var phi: Número = 0.02 * (mouseY - 200); phi = StardustMath.clamp (phi, -StardustMath.HALF_PI, StardustMath.HALF_PI); var x: Número = CAMERA_RADIUS * Math.cos (theta) * Math.cos (phi); var y: Número = CAMERA_RADIUS * Math.sin (phi); var z: Number = CAMERA_RADIUS * Math.sin (theta) * Math.cos (phi); renderer.camera.position.set (x, y, z); renderer.camera.direction.set (-x, -y, -z); 

Tenga en cuenta que utilicé el método StardustMath.clamp (); Esto asegura que el valor phi se mantenga entre la mitad positiva y la negativa PI.


Hito: Native Stardust Engine Complete

Está bien, hemos terminado! Eso es todo lo que necesitamos hacer para que un emisor 3D funcione con el motor 3D nativo de Stardust. Veamos el resultado. Puede hacer clic en el botón de pausa para pausar el efecto de partículas, y mover el mouse para orbitar la cámara:

Manifestación Verlo en línea

Si desea ver el código fuente completo, busque en la carpeta llamada "01 - Stardust Native 3D Engine" en la Fuente.


Tiempo para Papervision3D

Cambiar del motor nativo 3D de Stardust a Papervision3D es fácil. Solo tendremos que usar un renderizador diferente y mostrar el inicializador de objetos..

(¿Nunca usaste Papervision3D antes? Mira este tutorial para principiantes.)

Primero usaremos la clase de partículas de Papervision3D. Puede que no estés familiarizado con esto; Te mostraré cómo usar la clase DisplayObject3D más común más adelante.


Paso 14: Cambiar el inicializador de objetos de visualización

Cambie el siguiente código en la clase de emisor:

 var doc1: DisplayObjectClass3D = new DisplayObjectClass3D (Star); var doc2: DisplayObjectClass3D = new DisplayObjectClass3D (Circle);

a esto:

 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]);

Como ya sabrá, la clase MovieParticleMaterial nos permite utilizar objetos de visualización como la apariencia de partículas en Papervision3D. Creamos una instancia de Estrella y Círculo para usarla como material de partículas. El inicializador de artículo PV3DP toma el lugar del inicializador DisplayObjectClass3D; su constructor acepta una matriz de parámetros, que se agregarán a un objeto Particles.

Esto es todo lo que tenemos que hacer con respecto al emisor. A continuación modificaremos la clase de documento..


Paso 15: Configurar el entorno Papervision3D

El contenedor de destino para nuestro renderizador ya no es un objeto Sprite. En su lugar, vamos a crear partículas en un objeto de partículas. Tendremos que cambiar el tipo de renderizador de DisplayObjectRenderer3D a PV3DParticleRenderer.

Declare las siguientes variables para los objetos relacionados con Papervision3D:

 var escena privada: SceneObject3D; particulas de var privado: particulas; cámara privada var: Camera3D; origen var privado: DisplayObject3D; private var renderEngine: BasicRenderEngine; viewport var privado: Viewport3D;

El código en el constructor de la clase de documento es ahora:

 initPV3D (); //¡Esto es nuevo! reloj = nuevo SteadyClock (PARTICLE_RATE); emisor = nuevo StarEmitter (reloj); renderer = new PV3DParticleRenderer (partículas); //¡Esto es nuevo! renderer.addEmitter (emisor); pause_btn.addEventListener (MouseEvent.CLICK, togglePause); addEventListener (Event.ENTER_FRAME, mainLoop);

El método initPV3D () configura el entorno Papervision3D. Aquí está el código:

 función privada initPV3D (): void // create the scene scene = new SceneObject3D (); // crea el objeto Partículas partículas = nuevas Partículas (); // crea la cámara e inicializa su posición camera = new Camera3D (); camera.position.x = 0; camera.position.y = 0; camera.position.z = -CAMERA_RADIUS; // crear un DO3D que represente el origen = origen DisplayObject3D (); origen.x = origen.y = origen.z = 0; // apunta la cámara al origen camera.target = origin; scene.addChild (origen); scene.addChild (partículas); // crear el motor de visualización y la vista renderEngine = new BasicRenderEngine (); viewport = new Viewport3D (640, 400); // agregar la ventana gráfica al escenario addChild (ventana gráfica); // agrega el botón de pausa de nuevo para que esté en la parte superior de la ventana gráfica addChild (pause_btn); 

Paso 16: El nuevo bucle principal

Ahora Stardust solo actualiza las propiedades de los objetos 3D; El motor de render de Papervision3D está asumiendo la responsabilidad de renderizar. Así es como se ve nuestro nuevo bucle principal:

 Función privada mainLoop (e: Event): void updateCamera (); emitter.step (); renderEngine.renderScene (escena, cámara, ventana gráfica); //¡Esto es nuevo! 

Paso 17: Actualizando la cámara

Ahora que estamos usando la cámara de Papervision3D, también tendremos que modificar el método updateCamera ():

 función privada updateCamera (): void var theta: Number = 0.02 * (mouseX - 320); var phi: Número = 0.02 * (mouseY - 200); phi = StardustMath.clamp (phi, -StardustMath.HALF_PI, StardustMath.HALF_PI); var x: Número = CAMERA_RADIUS * Math.cos (theta) * Math.cos (phi); var y: Número = -CAMERA_RADIUS * Math.sin (phi); // note que ahora es negativo var z: Number = CAMERA_RADIUS * Math.sin (theta) * Math.cos (phi); camera.x = x; // actualizamos cada una de las propiedades x, y, z de la cámara de PV3D camera.y = y por separado; camera.z = z; 

Hito: Papervision3D con partículas completadas

Bien, hemos cambiado con éxito del motor 3D nativo de Stardust a Papervision3D. Ahora vamos a ver el resultado. Tenga en cuenta el efecto pixelado en las partículas. Esto se debe a que Papervision3D primero dibuja objetos vectoriales en mapas de bits antes de usarlos como materiales de partículas..

Manifestación Verlo en línea

Puede encontrar todo el código fuente para esto en la carpeta "02 - Papervision3D Particles".


Clase DisplayObject3D de Papervision3D

Hasta ahora, hemos estado trabajando con "vallas publicitarias 2D" - objetos planos, como papel. Es posible crear objetos de partículas 3D "reales", como los objetos DisplayObject3D de Papervision3D. Vamos a tener que usar otro inicializador. Ahora vamos a la parte final de este tutorial. Crearemos partículas de cubo rojo y azul..


Paso 18: Cambiar el inicializador de objeto de pantalla, de nuevo

Vamos a cambiar el inicializador con respecto a la apariencia de las partículas por última vez..

Antes de eso, declare una variable LightObject3D en la clase de emisor. Vamos a utilizar FlatShadeMaterial para los objetos DisplayObject3D, que requieren una fuente de luz. Además, declare las siguientes constantes: las utilizaremos como parámetros para el Material de FlastShade y para determinar los tamaños de los cubos:

 public var light: LightObject3D; const estática privada LIGHT_COLOR_1: uint = 0xCC3300; const estática privada LIGHT_COLOR_2: uint = 0x006699; const estática privada AMBIENT_COLOR_1: uint = 0x881100; const estática privada AMBIENT_COLOR_2: uint = 0x002244; constata estática privada CUBE_SIZE: Número = 15;

Ahora cambia el siguiente código en la clase de emisor:

 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]);

a esto:

 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 nueva apariencia de partículas se inicializará como cubos 3D rojos y azules. El primer parámetro del constructor para el inicializador PV3DDisplayObject3DClass es la clase que deseamos instanciar para las partículas (por lo que aquí, es la clase Cube) y el segundo parámetro es una matriz de parámetros del constructor para esta clase Cube..


Paso 19: Los tres ejes de rotación

Anteriormente, debido a que estábamos trabajando con "carteles en 2D", solo importaba la rotación sobre el eje Z. Ahora que estamos trabajando con verdaderos objetos 3D, necesitamos pasar tres referencias de objetos aleatorios a los constructores de Rotation3D y Omega3D, una para cada eje.

Cambie el siguiente código en la clase de emisor:

 addInitializer (nuevo Rotation3D (nulo, nulo, nuevo UniformRandom (0, 180))); addInitializer (nuevo Omega3D (nulo, nulo, nuevo UniformRandom (OMEGA_AVG, OMEGA_VAR)));

a esto:

 var rotationRandom: UniformRandom = nuevo UniformRandom (0, 180); var omegaRandom: UniformRandom = nuevo UniformRandom (OMEGA_AVG, OMEGA_VAR); addInitializer (nuevo Rotation3D (rotationRandom, rotationRandom, rotationRandom)); addInitializer (nuevo Omega3D (omegaRandom, omegaRandom, omegaRandom));

Paso 20: Modificar la clase de documento

Esta vez, en lugar de usar un objeto Partículas como nuestro contenedor de partículas, estamos usando un DisplayObject3D como el contenedor. Declare una variable para este contenedor en la clase de documento:

 contenedor var privado: DisplayObject3D;

Además, necesitaremos otro tipo de renderizador para crear partículas en el nuevo contenedor. Cambie el tipo de renderizador de PV3DParticleRenderer a PV3DDisplayObject3DRenderer. El código en el constructor de la clase de documento ahora debería verse así:

 initPV3D (); reloj = nuevo SteadyClock (PARTICLE_RATE); emisor = nuevo StarEmitter (reloj); renderer = new PV3DDisplayObject3DRenderer (container); // ¡Esto ha cambiado! renderer.addEmitter (emisor); pause_btn.addEventListener (MouseEvent.CLICK, togglePause); addEventListener (Event.ENTER_FRAME, mainLoop);

Paso 21: Modificar el método initPV3D ()

En la función initPV3D (), ahora necesitamos inicializar la variable de contenedor y agregarla a la escena. Agrega estas dos líneas al final de esa función:

 container = new DisplayObject3D (); scene.addChild (contenedor);

Paso 22: Modificar el método updateCamera ()

En el método updateCamera (), deseamos que la luz siga a la cámara, por lo que tendremos la ilusión de que la luz siempre "sale" de nuestros ojos. Cambia el siguiente código:

 camera.x = x; camera.y = y; camera.z = z;

a esto:

 emitter.light.x = camera.x = x; emitter.light.y = camera.y = y; emitter.light.z = camera.z = z;

Ahora la fuente de luz está siempre en el mismo punto que la cámara..


Hito: Papervision3D con DisplayObject3D completado

Sí, finalmente hemos terminado con este tutorial. No más codificación. Echemos un vistazo a nuestro resultado final, con elegantes cubos 3D rojos y azules!

Manifestación Verlo en línea

El código fuente para esto se puede encontrar en la carpeta "Papervision3D DisplayObject3D".


Conclusión

El flujo de trabajo para crear efectos de partículas en 3D con Stardust es muy similar al de los efectos en 2D. Simplemente elige un conjunto diferente de inicializadores, acciones y renderizadores. Stardust también admite otros motores 3D, incluidos ZedBox y ND3D. El uso es casi el mismo. Solo tendrás que usar un conjunto diferente de inicializadores y renderizadores. Incluso puede extender las clases Inicializador, Acción y Renderizador para trabajar con los motores 3D que desee.!

Ahora tienes lo básico, ¿por qué no volver a las consts creadas en el Paso 6 y jugar con ellas para ver los efectos??

Espero que este tutorial le ayude a entender más a Stardust y lo haga más familiar y cómodo con el flujo de trabajo de Stardust. Gracias por leer!