Comunidad de diseño web y desarrollo en internet online

Detectar lados visibles en una figura 3D con ActionScript 3

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

  1. 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.
  2. 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

¿Sabes SQL? ¿No-SQL? Aprende MySQL, PostgreSQL, MongoDB, Redis y más con el Curso Profesional de Bases de Datos que empieza el martes, en vivo.

Publica tu comentario

o puedes...

¿Estás registrado en Cristalab y quieres
publicar tu URL y avatar?

¿No estás registrado aún pero quieres hacerlo antes de publicar tu comentario?

Registrate