martes, 24 de febrero de 2015

Transformaciones



Node Transform

Para situar, orientar y escalar los objetos según nuestras necesidades dentro del entorno que estemos construyendo, debemos poder aplicar las transformaciones geométricas básicas, que son: traslación, rotación y escalado. También existen variantes de estas pero que no veremos aquí.
Para aplicar transformaciones en VRML se utiliza el node Transform. Este node puede realizar cualquiera de las tres operaciones o las tres a la vez. Para ver cómo funciona iremos analizando ejemplos:

Traslaciones

Ejemplo1: Definiremos una esfera roja en el origen de coordenadas y una esfera verde trasladada 10 unidades en el eje de las X.
 
Shape { # Esfera roja que nos marca el origen de coordenadas
geometry Sphere { radius 2 }
appearance Appearance { material Material { diffuseColor 1 0 0 } }
}
 
Transform {
translation 10 0 0
children [
Shape { # Esfera verde trasladada 10 unidades en el eje X
geometry Sphere { radius 2 }
appearance Appearance { material Material { diffuseColor 0 1 0 } }
}
]
}

Analicemos este código. La primera parte define la esfera roja que nos servirá de referencia para ver claramente que la esfera verde ha sido efectivamente trasladada. Como se puede observar, la esfera roja no sufre ninguna transformación.
La segunda parte es la que realmente nos interesa. Aquí definimos un node Transform. Este tiene un field translation donde se define el desplazamiento que sufrirá el objeto que deseamos trasladar. Así pues se define un desplazamiento de 10 unidades en el eje X, 0 unidades en el eje Y y 0 unidades en el eje Z. Las traslaciones son relativas y por lo tanto se suman a la posición actual de los objetos.
Después del field translation podemos ver el field children. Este field permite dar una lista de objetos que serán afectados por la trasformación definida. En este caso la lista de objetos se limita a uno solo: la esfera verde que queremos situar a 10 unidades del origen en el eje X. (De hecho este node es uno de los nodes agrupadores que mencionábamos en el módulo Nodos, Campos y Eventos I).
(NOTA: Como referencia de tipos de fields, el field children es de tipo MFNode, es decir, de tipo multivaluado por el hecho que puede contener una lista de valores).
Compliquemos un poco más el entorno:
Ejemplo2: Ahora queremos añadir un cono azul sobre nuestra esfera verde.
Para hacer esto debemos trasladar el cono 10 unidades en el eje de las X al igual que la esfera verde, pero además, debemos trasladarlo 3 unidades en el eje de las Y (en concordancia con las medidas de la esfera y el cono).
 
Shape { # Esfera roja que nos marca el origen de coordenadas
geometry Sphere { radius 2 }
appearance Appearance { material Material { diffuseColor 1 0 0 } }
}
 
Transform {
translation 10 0 0
children [
Shape { # Esfera verde trasladada 10 unidades en el eje X
geometry Sphere { radius 2 }
appearance Appearance { material Material { diffuseColor 0 1 0 } }
}
]
}

Transform {
translation 10 3 0
children [
Shape { # Cono azul trasladado 10 unidades en el eje X y 3 en el eje Y
geometry Cone { bottomRadius 2 height 2 }
appearance Appearance { material Material { diffuseColor 0 0 1 } }
               }
        ]
}


Rotaciones

Ejemplo3: Definiremos una caja amarilla en el origen de coordenadas con las caras paralelas a los planos coordenados, y otra caja azul (más estrecha y más alta) rotada 45 grados respecto al eje Y.
 
Shape { # Caja amarilla que nos señala la rotación cero
geometry Box { size 4 2 4 }
appearance Appearance { material Material { diffuseColor 1 1 0 } }
}

Transform {
rotation 0 1 0  0.7854 # 45 grados en radianes
children [
Shape { # Caja azul que es rotada 45 grados respecto al eje Y
geometry Box { size 2 4 2 }
appearance Appearance { material Material { diffuseColor 0 0 1 } }
}
]
}
Analicemos este fragmento de código. La primera parte define la caja amarilla que servirá de referencia para ver claramente que la caja azul ha sido rotada. Como se puede observar, la caja amarilla no sufre ninguna transformación y por lo tanto mantiene sus caras paralelas a los planos coordenados.
En la segunda parte definimos un node Transform. Este tiene un field rotation donde se define la rotación que sufrirá el objeto a modificar. Así pues, una rotación de 45 grados (0.7854 radianes) respecto al eje Y. Esto en VRML se define de una forma poco común.
El field rotation tiene en realidad dos partes. Los tres primeros valores determinan un vector en el espacio 3D que corresponde a la orientación del eje de rotación de nuestra transformación. El eje de rotación coincide con los ejes coordenados cuando:
  • eje rotación = (1 0 0) -> equivale a X
  • eje rotación = (0 1 0) -> equivale a Y
  • eje rotación = (0 0 1) -> equivale a Z
Este sistema de definir un eje de rotación de la transformación es muy flexible y genérico, pero resulta compleja cuando el eje de rotación no es paralelo a un eje coordenado.
La segunda parte es el ángulo de rotación que queremos aplicar (expresado en radianes) respecto al eje definido en la primera parte. Al estar en un sistema de ejes a derechas, los ángulos positivos resultan en rotaciones en sentido antihorario (y los ángulos negativos, en rotaciones en sentido horario).
Después del field translation podemos ver el field children que, como antes, engloba la lista de objetos que serán afectados por la rotación. En este caso, la lista de objetos es, de nuevo, un solo objeto en nuestro ejemplo: la caja azul que deseamos rotar 45 grados respecto al eje Y.
Compliquemos un poco más el entorno:
Ejemplo4: Ahora queremos que la caja azul también rote 45 grados respecto al eje X.
 
Shape { # Caja amarilla que nos marca la rotación cero
geometry Box { size 4 2 4 }
appearance Appearance { material Material { diffuseColor 1 1 0 } }
}
 
Transform {
rotation 1 0 0  0.7854 # Rotación eje X
children [
Transform {
rotation 0 1 0  0.7854 # Rotación eje Y
children [
Shape { # Caja azul
geometry Box { size 2 4 2 }
appearance Appearance { material Material { diffuseColor 0 0 1 } }
                               }
                       ]
               }
 
        ]
}
La comprensión de esta variante se deja al lector.
 

Escalados

Por lo que refiere a los escalados se deben tener en cuenta dos tipos distintos: los escalados uniformes y los no uniformes (aunque los uniformes sean un caso concreto de los no uniformes). Los uniformes agrandan o reducen un objeto en todas las direcciones por igual, mientras que los no uniformes tan solo modifican la talla en una dirección. Por lo tanto los escalados uniformes mantienen las proporciones originales de los objetos, mientras que los no uniformes deforman los objetos.
Ejemplo5: Definiremos un escalado no uniforme sobre un cubo.
En concreto, escalaremos el cubo al doble de su tamaño en la dirección de las X.

Transform {
scale 2 1 1 
children [
Shape { # Cubo naranja
geometry Box { size 1 1 1 }
appearance Appearance { material Material { diffuseColor 1 0.5 0 } }
}
]
}
Analicemos este código. Se define un node Transform que tiene un field scale donde se define el escalado no uniforme que sufrirá el objeto que deseamos modificar. Para definir el escalado, damos el tanto por uno que queremos agrandar/reducir el objeto en cada una de las direcciones que marcan los ejes coordenados.
Como el escalado no uniforme que definimos es de [2 1 1], el cubo de 1 unidad por lado ya no aparece como tal si no que aparece como una caja alargada horizontalmente de exáctamente 2 unidades de ancho, 1 de alto y 1 de fondo.
Si queremos aplicar un escalado uniforme, solo tenemos que poner el mismo valor de escalado para las tres direcciones.

Encadenamiento de Transformaciones

Cuando se desea aplicar más de una transformación a un objeto, no es necesario definir un node Transform para cada una, sinó que podemos definir las tres bajo un mismo node.
Ejemplo6: Definiremos un cubo de 1 unidad y le aplicaremos una traslación de [5 4 0], una rotación de 30 grados respecto el eje X y un escalado de [0.5 0.5 2].
 
Transform {
        translation 5 4 0
        rotation 1 0 0  0.5236 # 30 grados
        scale 0.5 0.5 1
        children [
Shape { # Cubo verde obscuro
geometry Box { size 1 1 1 }
appearance Appearance { material Material { diffuseColor 0 0.5 0.2 } }
}
]
}
Analizando el código vemos que lo que hemos definido no es tan claro como parece ya que no obtenemos el mismo resultado si aplicamos las tres operaciones en ordenes distintos.
Por definición, VRML define un orden de preferencia de operaciones de transformación que es el siguiente:
  1. En primer lugar se aplica el escalado.
  2. En segundo lugar se aplica la rotación.
  3. En tercer lugar se aplica la traslación.
Por lo tanto el código de arriba es totalmente equivalente al siguiente, realizando las transformaciones por separado:
 
Transform {
translation 5 4 0
children [
Transform {
rotation 1 0 0  0.5236 # 30 grados
children [
Transform {
scale 0.5 0.5 1
children [
Shape { # Cubo verde obsuro
geometry Box { size 1 1 1 }
appearance Appearance { material Material { diffuseColor 0 0.5 0.2 } }
                                              }
                                      ]
                               }
                       ]
               }
        ]
}
Como podemos comprobar el resultado es el mismo que antes.
No se debe caer en el error de pensar que esto se lee de arriba a abajo. Este código se lee de dentro hacia fuera y por lo tanto el orden en que se aplican las operaciones es empezando desde el objeto e ir saliendo hacia fuera: cubo > escalado > rotación > traslación.
Para aplicar las transformaciones en el orden que hemos dicho inicialmente deberíamos invertir la secuencia de la siguiente forma:
 
Transform {
scale 0.5 0.5 1
children [
Transform {
rotation 1 0 0  0.5236 # 30 grados
children [
Transform {
translation 5 4 0
children [
Shape { # Cubo verde obscuro
geometry Box { size 1 1 1 }
appearance Appearance { material Material { diffuseColor 0 0.5 0.2 } }
}
]
}
]
}
]
}

Como podemos comprobar el resultado es totalmente distinto a los dos anteriores. De hecho nuestra caja que era un paralelepípedo de ángulos rectos ahora ha quedado deformada pasando a ser un trapezoide.

No hay comentarios:

Publicar un comentario

Gracias por participar en esta página.