viernes, 4 de septiembre de 2009

Silverlight 3D

Es frecuente que, al plantear nuevos modelos de presentación de información, e incluso nuevos modelos de interacción, aparezca la necesidad de contar con objetos o componentes 3D en nuestras interfaces.

Al hablar de 3D, es necesario precisar a qué tipo de 3D nos referimos. En adelante, nos referiremos como “3D simulado” al conjunto de técnicas visuales para simular tres dimensiones, y como “3D real” al conjunto de herramientas/técnicas que dan soporte para:

- Gestión del espacio en tres dimensiones (x, y, z)

- Creación y edición modelos tridimensionales

- Aplicación de transformaciones 3D (movimiento, escalado, rotación)

- Disposición de cámaras

- Iluminación 3D

Silverlight, al no disponer de, por ejemplo, la librería System.Windows.Media3D de WPF, no da soporte para 3D. Pese a ello, existen varios modos de disponer de elementos 3D en nuestras interfaces.



Parallax (3D simulado)
El Parallax es una simulación de 3D basada en dos aspectos: la diferencia relativa de tamaño y la diferencia relativa de movimiento entre los elementos que están cerca y los que están lejos.




Car.cs



public class Car

{

private int xPosition;

private int yPosition;

private int zPosition;

}



CarCollection.cs



public class CarCollection

{

private List cars = null;



public List Cars

{

get { return cars; }

set { cars = value; }

}

}



CarShow.xaml







CarShow.xaml.cs

private void FillCanvasWithCars()

{

Random rand = new Random();



//Por cada Car crearemos una imagen del coche y la ubicaremos en el Canvas 'cnvCars'



for (int i = 0; i < Carcollection.Cars.Count; i++)

{



//Creamos la imagen



Image car = new Image();

car.Source = new BitmapImage(new Uri("../images/car.png",UriKind.Relative));



//Calculamos, en función de lo lejos que esté, cuánto tenemos que reducirla



double scaleFactor = 1;

if(Carcollection.Cars[i].Zposition>0)

scaleFactor = carOriginalSize / Carcollection.Cars[i].Zposition;



//Creamos la transformación de escalado



ScaleTransform scaleCar = new ScaleTransform();

scaleCar.ScaleX = scaleFactor;

scaleCar.ScaleY = scaleFactor;



//Creamos la transformación de traslación



TranslateTransform translateCar = new TranslateTransform();

translateCar.X = rand.NextDouble() * this.cnvCars.ActualWidth;

translateCar.Y = rand.NextDouble() * this.cnvCars.ActualHeight;



//Aplicaremos las transformaciones a partir del centro del objeto



car.RenderTransformOrigin = new Point(0.5, 0.5);



//Aplicamos las transformaciones al objeto



TransformGroup transformaciones = new TransformGroup();

//Primero siempre la de escalado

transformaciones.Children.Add(scaleCar);

//Y por último siempre la de traslación

transformaciones.Children.Add(translateCar);



car.RenderTransform = transformaciones;



}

}




2.5D (Híbrido)
Comúnmente, se conoce como 2.5D a aquellas aplicaciones que no ofrecen soporte para 3D real, pero que permiten proyección de componentes/elementos sobre cualquier plano. Es decir, que permiten realizar efectos de perspectiva sobre sus componentes.

Silverlight 2 no permite aplicar efectos de proyección en ninguno de sus componentes. Aunque se puede llegar a emular en el caso de imágenes.

La técnica para conseguirlo pasa por crear una malla 2D mediante triángulos – paths triangulares - y desarrollar manualmente su comportamiento gestionando el movimiento de cada uno de los puntos en caso de aplicarle proyección.




Completado éste primer paso, es necesario descomponer la imagen según las posiciones de los vértices de la malla, de lo que resultarán N imágenes que usaremos como de cada uno de los paths de la malla 2D.




Uno de los puntos interesantes de Silverlight 3 (y que ya está disponible en la versión Silverlight 3 Beta) es la capacidad de realizar proyecciones de controles sobre cualquier plano 3D mediante la propiedad .Projection.

O, en otras palabras, la capacidad de realizar cualquier tipo de perspectiva sobre cualquier objeto (imágenes, vídeo, botones, cuadros de texto, etc.). Lo que permite, por ejemplo, crear páginas enteras como un componente 3D.






MainPage.xaml








CenterOfRotationX="0"

CenterOfRotationY="0.5"

CenterOfRotationZ="0"

RotationY="45"/>


















































































Margin="40,0,0,0" MaxWidth="250" Stretch="Uniform"/>








Swift3D (3D simulado)
Swift 3D es un software de edición 3D creado por ElectricRain (http://www.erain.com/) que, pese a no ser comparable – a nivel de posibilidades - con ninguna de las grandes aplicaciones disponibles actualmente en el mercado (caso de 3D Studio MAX, Maya, etc.) sí dispone de una herramienta muy interesante. Swift3D permite exportar a XAML(2D) cualquier escena y animación que haya sido creada en su interior.











Hasta la versión 4, el XAML exportado por Swift3D era sólo válido para WPF, pero a partir de la versión 5 se ofrece la posibilidad de escoger quien “reproducirá” la animación, si WPF o Silverlight, y el código XAML generado dependerá de ello.

Kit3D (3D real)
Kit3D es un motor gráfico 3D desarrollado específicamente para Silverlight por Mark Dawson (http://www.markdawson.org/Kit3D/), y cuyo objetivo es dotar a esta herramienta de las mismas capacidades que ofrece System.Windows.Media.Media3D a WPF, de modo que el resultado de aplicaciones Silverlight desarrolladas con Kit3D sean comparables a las producidas mediante WPF3D.

Sería, comparativamente, el equivalente a Papervision3D (http://www.papervision3d.org/) o a Astro (http://labs.adobe.com/technologies/flashplayer10/) en el caso de Flash.

Kit3D permite, al igual que WPF, definir Viewports3D y disponer objetos (incluso con color o textura), cámaras, y luces en su interior, aplicar transformaciones 3D sobre objetos, o definir y gestionar el espacio 3D.







Pero, a diferencia de WPF, no puede hacerse mediante código XAML, sino que todo debe generarse mediante código behind. De modo que el código XAML sólo albergará el contenedor (habitualmente, un Canvas).

Crear una malla dinámicamente, sin embargo, puede llegar a ser un proceso complejo. Una malla se constituye a partir de un conjunto de puntos 3D, y de cómo de relacionan entre sí, por lo que para definir una malla 3D es necesario conocer (o calcular):

- la posición (en 3D) de cada uno de los vértices que conformarán la malla.

- cuáles son los dos vértices con qué se relaciona cada vértice para formar un triángulo (en cualquier sistema de edición 3D las mallas se definen a partir de polígonos. En el caso de Kit3D, éstos son triángulos).

- el vector normal a la superficie visible del triángulo (para determinar cuál es la cara “arriba”, y cuál es la de “abajo”).







MainPage.xaml










MainPage.cs (parte 1 – añadimos la referencia a Kit3d.dll y la incluímos en el código)



using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using Kit3D.Windows.Controls;
using Kit3D.Windows.Media;
using Kit3D.Windows.Media.Media3D;



namespace EjemploCubo.Controles3D
{
public partial class OurCube : UserControl
{



MainPage.cs (parte 2 – definimos el viewport, creamos el objeto, y añadimos una cámara perspectiva)



private Viewport3D viewport;
RotateTransform3D Rotate;



public OurCube()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(Our_Cube_Loaded);
}

void Our_Cube_Loaded(object sender, RoutedEventArgs e)
{
ModelVisual3D Visual = new ModelVisual3D();
GeometryModel3D MyCube = new GeometryModel3D();
MyCube.Geometry = CreateCubeMesh();
MyCube.Material = new DiffuseMaterial(new

Kit3DBrush(new SolidColorBrush(Colors.Gray)));

Visual.Content = MyCube;

Transform3DGroup Transform = new Transform3DGroup();
Transform.Children.Add(new ScaleTransform3D(3, 3, 3));

Rotate = new RotateTransform3D();
Rotate.Rotation = new AxisAngleRotation3D();
Transform.Children.Add(Rotate);
MyCube.Transform = Transform;

viewport = new Viewport3D();

viewport.Camera = new PerspectiveCamera(

new Point3D(-5, 15, 25),
new Vector3D(5, -15, -25),
new Vector3D(0, 1, 0),
45);
viewport.Children.Add(Visual);
viewport.HorizontalAlignment = HorizontalAlignment.Stretch;
viewport.VerticalAlignment = VerticalAlignment.Stretch;



this.LayoutRoot.Children.Add(viewport);

}



MainPage.cs (parte 3 – la función que crea la malla 3D del cubo)

private MeshGeometry3D CreateCubeMesh()
{
MeshGeometry3D mesh = new MeshGeometry3D();



//Definimos la posición de cada uno de los puntos 3D
mesh.Positions = new Point3DCollection
{
new Point3D(-0.5,0.5,0.5),
new Point3D(0.5,0.5,0.5),
new Point3D(-0.5,-0.5,0.5),
new Point3D(0.5,-0.5,0.5),
new Point3D(0.5,0.5,-0.5),
new Point3D(-0.5, 0.5, -0.5),
new Point3D(0.5,-0.5,-0.5),
new Point3D(-0.5,-0.5,-0.5),

new Point3D(-0.5,0.5,-0.5),
new Point3D(-0.5,0.5,0.5),
new Point3D(-0.5,-0.5,-0.5),
new Point3D(-0.5,-0.5,0.5),
new Point3D(0.5,0.5,0.5),
new Point3D(0.5,0.5,-0.5),
new Point3D(0.5,-0.5,0.5),
new Point3D(0.5,-0.5,-0.5),

new Point3D(-0.5,0.5,-0.5),
new Point3D(0.5,0.5,-0.5),
new Point3D(-0.5,0.5,0.5),
new Point3D(0.5,0.5,0.5),
new Point3D(0.5,-0.5,-0.5),
new Point3D(-0.5,-0.5,-0.5),
new Point3D(0.5,-0.5,0.5),
new Point3D(-0.5,-0.5,0.5)
};



//Definimos la asociación de los puntos 3D entre ellos

mesh.TriangleIndices = new Int32Collection
{
0, 2, 1, 1, 2, 3,
4, 6, 5, 5, 6, 7,
8, 10, 9, 9, 10, 11,
12, 14, 13, 13, 14, 15,
16, 18, 17, 17, 18, 19,
20, 22, 21, 21, 22, 23
};

return mesh;
}






Aunque teóricamente, mediante éste sistema, la representación de cualquier malla es posible, la complejidad de su creación mediante código crece exponencialmente a medida que la malla se aleja de una primitiva (cubos, esferas, toroides, etc.) o de un objeto simple, por lo que es difícil concebir mallas 3D que representen, por ejemplo, figuras reales o personas.

El rendimiento de Kit3D, al igual que pasa con Papervision3D en el caso de Flash, no es notorio. De momento es inviable plantear interfaces con más de 40.000 polígonos, iluminación, y cámaras en movimiento, pues todo el procesado corre a cargo de CPU (Kit3D como Silverlight 2, no aprovecha GPU), por lo que su uso general debe limitarse a escenas con presencia puntual de objetos 3D.



Conclusiones
Durante éstos últimos años hemos visto como la interacción entre usuario y máquina ha cambiado enormemente con la llegada de las denominadas NUI (Natural User Interface).

La aparición de dispositivos como el iPhone o la Microsoft Surface, y de sistemas que ya gestionen interacciones táctiles, como Windows 7, responde a la necesidad de interactuar con las interfaces de un modo distinto. Un modo de interacción basado en objetos, y no en gráficos, ni en texto.

Es por ello que el objeto 3D empieza a cobrar relevancia en los sistemas de presentación, pues es la forma de presentación más común en el mundo real, y todo hace prever que lo será en breve también en los nuevos modelos de presentación e interacción.

Los métodos, técnicas, y tecnologías descritas anteriormente no dejan de ser una primera aproximación a éste planteamiento. Un primer paso al que, sin duda, seguirán muchos




No hay comentarios: