Basándome en los tutoriales que fueron publicados recientemente acerca de las muchas opciones en cuanto manejo del método drawTriangles, hago muestra de una tecnica realmente util al momento de trabajar con figuras planas de 3 dimensiones en Action Script 3, que consiste en detectar cual de las dos caras está siendo vista de frente por la pantalla y que cara permanece ocultas detrás de esta.
Path Winding (Indice)
Una manera sencilla para determinar cual cara esta actualmente visible es a través de path winding. Winding se refiere a la dirección, numero de vueltas o forma en la que un polígono fue dibujado basándose en un punto dado, por ende son necesarios al menos 3 puntos para que se trazara un ciclo en algún sentido. Cuando la dirección del trazado es acorde las manecillas del reloj se le denomina positivo y caso contrario, cuando el trazado va en contra a estas se le denomina negativo.
___________
Triángulos trazados acorde y en contra a las manecillas del reloj respectivamente
Ahora, supongamos que hemos trazado un triangulo (originalmente) positivo que gira libremente en tercera dimensión. Una vez dada media vuelta desde nuestro punto de vista aparentara ser negativo, debido a que TODO ocurre a partir de la perspectiva de la pantalla, un objeto 3D visto desde un plano en 2D.

Triangulo positivo que al ser proyectado especular mente aparenta ser negativo
Aprovechando esta información, podemos determinar si la orientación del trazado en un triangulo fue en sentido horario, por lo que podemos hacer un diferencial entre el trazado actual y original para determinar cual es la cara que se estará mostrando:
Código :
function winding(i:Vector.<Number>):Boolean
{
if (i == null || i.length < 6){return undefined;}
var winding:int = (i[0]-i[4])*(i[3]-i[5]) - (i[1]-i[5])*(i[2]-i[4]);
return winding < 0 ? false : winding > 0 ? true : undefined;
}
//
if(winding(vertices)){trace("TriangleCulling.POSITIVE");}else{trace("TriangleCulling.NEGATIVE");}Desliza el cursor y/o da click sobre la tarjeta para ver el resultado
Este es parte del proceso interno que seguramente realiza Flash Player al activar la propiedad culling a través de los métodos graphics.drawTriangles y graphicsTrianglePath.
A través del Vector
Es ahora cuando podemos aplicar esto a un sencillo ejemplo. Navegando por las preguntas en los foros de Kirupa encontré una manera muy lógica para detectar la cara visible a través de rotationZ.Consiste en crear un vector (C) a partir de dos puntos ubicados en un espacio (A y B), junto a nuestro MC a revisar. La magnitud de este nuevo vector es proporcional a la magnitud de los vectores base y el ángulo entre ellos por lo que a medida que estos descienden también lo hará el nuevo vector. Resultando las siguientes formulas para determinar las coordenadas de nuestro vector C:
Código :
Cx = AyBz - AzBy; Cy = AzBx - AxBz; Cz = AxBy - AyBx;El vector C obtenido estará situado entre 2 vectores que sin importar que estén representados en tercera dimensión solo serán apreciados por la pantalla en 2 ejes (x, y). Por ello podemos trabajar con un eje z nulo, ademas de que nos evitara estar determinando mas cálculos.
Código :
//Cx = Ay*(0) - (0)*By = 0; //Cy = (0)*Bx - Ax*(0) = 0; Cz = AxBy - AyBx;Es así como hemos obtenido la magnitud de nuestro nuevo vector C, el cual nos ayudara a determinar cuando nuestra cara este completamente sesgada (Cz = 0) así como también para determinar que cara esta visible frente a la pantalla.
Código :
var magnitud:Number = Cz = AxBy - AyBx;Solamente crearemos 3 puntos fijados dentro de nuestro MC instanciado como "clip" y reemplazaremos A, B y C por cada punto respectivamente:
Código :
P1 = clip.localToGlobal(new Point(0,0)); P2 = clip.localToGlobal(new Point(card.width,0)); P3 = clip.localToGlobal(new Point(0,card.height)); // magnitud = ((P2.x-P1.x)*(P3.y-P1.y) - (P2.y-P1.y)*(P3.x-P1.x));Por ende, cuando magnitud sea igual a cero, sera por que nuestra cara esta completamente sesgada, es decir con ninguna cara completamente visible hacia la pantalla, cuando sea menor a cero estará visible la cara anterior y mayor a cero la cara posterior.
Da click dentro del recuadro para reproducir otra vez
Aplicándolo a la vida real
- Crearemos un MC en nuestra biblioteca con 2 fotogramas, en el primero estará el gráfico de la cara anterior, y en el segundo el gráfico de la cara posterior. Para este ejemplo lo instanciaremos con el nombre de "card" en el panel de propiedades.
- Una vez hecho eso, pegamos el siguiente código en el panel acciones del fotograma principal de nuestra película. La explicación esta comentada:
Código :
// Llamamos el MC "card" de la biblioteca y lo agregamos al escenario var card:MovieClip = new Card(); addChild(card); // Una vez añadido al escenario, lo ubicamos en el centro de la pantalla card.x = stage.stageWidth /2; card.y = stage.stageHeight /2; card.z = 0; // Creamos una variable que nos indicara a que fotograma debe detenerse el MC "card"... var magnitud:Number; // ...y los 3 puntos que nos servirán para detectar que cara debe de estar visible var P1:Point, P2:Point, P3:Point; // Finalmente añadimos el listener para ENTER_FRAME card.addEventListener(Event.ENTER_FRAME, eventHandler); function eventHandler(event:Event):void { switch(event.type) { case Event.ENTER_FRAME: // Hacemos que "card" gire respecto la posicion del mouse card.rotationY += (mouseX-card.rotationY)/5; // <!-- http://www.senocular.com --> P1 = card.localToGlobal(new Point(0,0)); P2 = card.localToGlobal(new Point(100,0)); P3 = card.localToGlobal(new Point(0,100)); magnitud = ((P2.x-P1.x)*(P3.y-P1.y) - (P2.y-P1.y)*(P3.x-P1.x)); // <!-- http://www.senocular.com --> // Que "card" este en el fotograma indicado por "magnitud" card.gotoAndStop(magnitud > 0 ? 2 : 1); } }
Desliza el cursor sobre la tarjeta para ver el resultado

M@U :
Presumido
Pero de verdad que están geniales los tips
M@U :
Sigue así, no pares porfavor, que me muero del gusto... neuronal...
Por shino el 01 de Abril de 2009
- Abren un nuevo archivo de Flash CS4 para trabajar con ActionScript 3.
- Si de plano no les interesa aprender la teoría sino solamente que les funcione el ejemplo abran el panel de acciones y añadan todo el código del ultimo bloque de texto.
- Una vez todo esto creen un Movieclip y vinculen lo desde la biblioteca con el nombre Card.
- Finalmente, prueben la película.
Saludos,Por Geluco el 17 de Abril de 2009
Geluco-blog :
Por maria msw el 31 de Mayo de 2009
Código :
Si la diferencia en "x" del extremo derecho con el centro es negativa el cuadro estará invertido ya que la esquina derecha se encuentra hacia la izquierda, de la misma manera si la diferencia es 0 la cara estará totalmenete sesgada ya que el extremo derecho se encontrará exactamente en el centro.
Pero el cálculo está muy bueno para obetos rotados en múltiples ejes.
Muy buen tip, sigue así que me están encantando
Por denis el 03 de Julio de 2009
http://www.cristalab.com/flash/
Por Denis el 03 de Julio de 2009
Denis -blog :
Por juana el 03 de Septiembre de 2009
Por karla el 03 de Septiembre de 2009
Por robertosebastian92 el 30 de Octubre de 2009
Por jhoram el 09 de Diciembre de 2009
Por zardilior el 07 de Febrero de 2010
Por Dread_Aldo el 11 de Junio de 2010
Por Dread_Aldo el 11 de Junio de 2010
se me olvidaba...
Por juanzear el 26 de Agosto de 2010
1. quiero que el mouse no le de la rotacion a las caras sino que rote al darle click al mc pero no doy como.
2. el mc se puede poner en el escenario en ves de dejarlo en la bibloteca
gracias de antemano si me coalboran con estas dos cosas
Por torrealbaruben el 26 de Agosto de 2010
Por juanzear el 28 de Agosto de 2010
stop();
import com.greensock.*;
import com.greensock.easing.*;
var magnitud:Number;
var P1:Point, P2:Point, P3:Point;
card.addEventListener(Event.ENTER_FRAME, eventHandler);
function eventHandler(event:Event):void
{
switch(event.type)
{
case Event.ENTER_FRAME:
P1 = card.localToGlobal(new Point(0,0));
P2 = card.localToGlobal(new Point(100,0));
P3 = card.localToGlobal(new Point(0,100));
magnitud = ((P2.x-P1.x)*(P3.y-P1.y) - (P2.y-P1.y)*(P3.x-P1.x));
card.gotoAndStop(magnitud > 0 ? 2 : 1);
}
}
card.addEventListener(MouseEvent.CLICK, eventHandler2);
function eventHandler2(event:MouseEvent):void {
this.gotoAndPlay(2)
stop();
switch(event.type)
{
case MouseEvent.CLICK:
TweenMax.to(card, 1, {rotationX:180});
P1 = card.localToGlobal(new Point(0,0));
P2 = card.localToGlobal(new Point(100,0));
P3 = card.localToGlobal(new Point(0,100));
magnitud = ((P2.x-P1.x)*(P3.y-P1.y) - (P2.y-P1.y)*(P3.x-P1.x));
card.gotoAndStop(magnitud > 0 ? 2 : 1);
}
}
Por juanzear el 28 de Agosto de 2010
var magnitud:Number;
var P1:Point, P2:Point, P3:Point;
card.addEventListener(Event.ENTER_FRAME, eventHandler);
function eventHandler(event:Event):void{
switch(event.type) {
case Event.ENTER_FRAME:
P1 = card.localToGlobal(new Point(0,0));
P2 = card.localToGlobal(new Point(0,100));
P3 = card.localToGlobal(new Point(110,0));
magnitud = ((P2.x-P1.x)*(P3.y-P1.y) - (P2.y-P1.y)*(P3.x-P1.x));
card.gotoAndStop(magnitud > 0 ? 2 : 1);
}
}
card.addEventListener(MouseEvent.CLICK, eventHandler2);
function eventHandler2(event:MouseEvent):void {
this.gotoAndPlay(2)
stop();
switch(event.type){
case MouseEvent.CLICK:
var timeline:TimelineLite = new TimelineLite();
timeline.append( new TweenLite(card, 1, {rotationX:"180"}) );
}
}
Por lucass el 21 de Septiembre de 2010