Conceptos básicos de programación 3d en WPF

Published 29 January 08 07:42 PM | mmonterroca

 

En este articulo conoceremos los conceptos básico de programación en tercera dimensión para Windows Presentation Foundation

 

Durante muchos años el escribir programas que generasen modelos en 3D estaba limitado a aquellas personas que supieran tecnologías como OpenGL o DirectX y lenguajes no siempre muy sencillos de usar como C++. En WPF se inicia un nuevo panorama en la programación de modelos tridimensionales de que con relativa facilidad es posible crear modelos en 3D utilizando clases predefinidas que trae el .NET Framework desde luego pudiendo ser uso de los lenguajes de programación como C# y VB o o bien utilizando el XAML.

El sistema de gráficos de tercera dimensión de Windows Presentation Foundation se encuentra completamente integrado al sistema de graficos 2D y todos los elementos y primitivas visuales que son válidos en el entorno 2D también serán válidos en el trabajo en tercera dimensión, por ejemplo sabemos que para generar un gradiente utilizamos el elemento <LinearGradientBrush> . De la misma manera podemos utilizar la misma técnica para generar una textura que tiene cualquier objeto generado en tercera dimensión con el mismo método sin necesidad de aprender algo nuevo.

Esto representa una gran ventaja para los desarrolladores toda vez que no es necesario aprender un lenguaje diferente u objetos distintos para manejo de gráficos de tercera dimensión si no que es posible reutilizar todo el conocimiento adquirido con el dibujo 2D y simplemente aprender a algunos conceptos nuevos propios del modelo de 3D.

Generando un objeto 3D con WPF

1) El elemento ViewPort3D nos brinda la capacidad de dibujar una escena tridimensional en una superficie de dos dimensiones.

Este elemento expone la colección Children que es una colección de objetos ModelVisual3D dentro de los cuales implementaremos nuestras escenas tridimensionales. El código requerido es el siguiente

XAML:

<Viewport3D ClipToBounds="True" Width="150" Height="150">
 
<Viewport3D.Children>
 
<ModelVisual3D>
 
</ModelVisual3D> 
 
</Viewport3D.Children>
 
</Viewport3D>
 

2) Dentro del elemento ModelVisual3D podemos especificar cualquier dibujo que deseemos. Sin embargo a diferencia de los gráficos en dos dimensiones donde existen primitivas predefinidas para dibujar objetos como elipses o rectángulos, en el mundo de 3D únicamente contamos con una clase denominada MeshGeometry3D en la cual es posible especificar un conjunto de vértices de triángulos mediante la propiedad Positions. Esto se debe a que cualquier dibujo tridimensional es posible describirlo con triángulos. Recordemos lo que sucede en los juegos de video: cuando hacemos un acercamiento fuerte alguna escena tridimensional podemos apreciar que las puntas y contornos de los objetos se tornan triangulares, esto se debe a que muchos objetos de los videojuegos, al igual que en WPF, son conjuntos de triángulos, que mediante su composición dan la sensación de un objeto tridimensional.

Nota: En el caso de WPF en .NET 3.5 se agrega un nuevo elemento llamado Viewport2DVisual3D que permite de una manera más sencilla generar una vista tridimensional a partir de la descripción de un objeto 2D.

Regresando a nuestro ejemplo una vez que hemos definido nuestra superficie de dibujo procederemos a utilizar la propiedad ModelVisual3D.Content para dentro de la misma especificar un MeshGeometry3D, en este caso con las posiciones establecidas estaremos generando un cuadrado

XAML

<ModelVisual3D.Content>
 
<GeometryModel3D>
 
<GeometryModel3D.Geometry>
 
<MeshGeometry3D
 
Positions="-0.5,-0.5,0.5 0.5,-0.5,0.5 0.5,0.5,0.5 0.5,0.5,0.5 -0.5,0.5,0.5 -0.5,-0.5,0.5 " />
 
</GeometryModel3D.Geometry>
 
</GeometryModel3D> 
 
</ModelVisual3D.Content>

3) A diferencia de lo que sucede con los objetos 2D donde el concepto de luz no existe, en 3D es indispensable especificar una fuente de luz debido a que si no existe ésta simplemente nuestro objeto no será visible de la misma manera que sucede en la misma vida real. Esto significa debemos de especificar el lugar que estará irradiando la luz y el tipo de material del cual se compone nuestro objeto es decir si éste es reflejante o no.

WPF especifica tres tipos de materiales el SpecularMaterial que refleja la luz de tal manera que el objeto parece brillar, el EmissiveMaterial que refleja la luz y el DiffuseMaterial que no refleja la luz.

En nuestro ejemplo utilizaremos el material DiffuseMaterial. Para especificar el tipo de material del cual se compone nuestro Mesh hacemos uso del siguiente código dentro de GeometryModel3D:

XAML

<GeometryModel3D.Material>
 
<DiffuseMaterial Brush="Red" ></DiffuseMaterial>
 
</GeometryModel3D.Material>

4) Dentro del mundo de tercera dimensión los objetos cambian de apariencia desde el punto de vista de quien observa al objeto. En WPF especificamos este punto de vista haciendo uso de los objetos que heredan de ProjectionCamera.

Controlamos a nuestras cámaras como si en verdad la cámara estuviera posicionada en el espacio, la propiedad Position es del tipo Point3D y especifica las coordenadas en la cual se encuentra la cámara.

XAML:

<Viewport3D.Camera>
 
<PerspectiveCamera Position="0,0,2"/>
 
</Viewport3D.Camera>

Si nosotros ejecutamos el código que llevamos hasta el momento veremos lo siguiente.

 

Aquí antes que nada podemos ver que se generó un cuadrado derivado de los vértices que se le especificaron al elemento MeshGeometry3D. Como aún no hacemos ninguna transformación de nuestro objeto no podemos ver la profundidad que tiene. Añadiremos una transformación posteriormente. Otro aspecto que podemos resaltar es que a pesar de que el material especificado con DiffuseMaterial fue de color Red estamos viendo que nuestro programa muestra el cuadrado en color negro. Esto se debe a que aún no hemos especificado la manera en la cual llega la luz al objeto, estos pasos los haremos a continuación.

5) Para agregar una fuente de luz a nuestra escena, dentro de ViewPort3D.Children especificaremos el siguiente código

XAML:

<ModelVisual3D>
 
<ModelVisual3D.Content>
 
<DirectionalLight Color="White" Direction="-0.5,-0.1,-0.5" />
 
</ModelVisual3D.Content>
 
</ModelVisual3D> 

6) Al ejecutar el código del listado previo podemos ver que ahora nuestro objeto está reflejando la luz y por lo tanto mostrando el color que se le especificó previamente.

7) Procederemos ahora generar una transformación dentro del elemento GeometryModel3D que nos permitirá ver a nuestro objeto en profundidad y de esta manera percibir el efecto de tercera dimensión. Para realizar este objetivo es necesario hacer uso de la clase RotateTransform3D que funciona de una manera similar a su equivalente bidimensional, pero a diferencia del segundo, en el primero hacemos uso de 3 dimensiones para rotar al elemento deseado. A continuación se muestra el uso de este objeto

XAML:

<GeometryModel3D.Transform>
 
<RotateTransform3D>
 
<RotateTransform3D.Rotation>
 
<AxisAngleRotation3D Axis="0,3,0" Angle="40" />
 
</RotateTransform3D.Rotation>
 
</RotateTransform3D>
 
</GeometryModel3D.Transform> 

8) Para finalizar nuestro ejemplo animaremos la propiedad Angle de la transformación. La sintaxis para hacer animación en elementos 3D es exactamente la misma que para los objetos bidimensionales. (ver capítulo “Animación”). Con esta animación veremos que el objeto está moviéndose de una manera circular.

El código requerido es el siguiente:

XAML

<Viewport3D.Triggers>
 
<EventTrigger RoutedEvent="Viewport3D.Loaded">
 
<BeginStoryboard>
 
<Storyboard>
 
<DoubleAnimation From="1" To="360" Duration="0:0:03" AccelerationRatio="1" RepeatBehavior="Forever" 
 
Storyboard.TargetProperty="(Viewport3D.Children)[1].(ModelVisual3D.Content).(GeometryModel3D.Transform).(RotateTransform3D.Rotation).(AxisAngleRotation3D.Angle)"></DoubleAnimation>
 
</Storyboard>
 
</BeginStoryboard>
 
</EventTrigger>
 
</Viewport3D.Triggers>
 

El código completo de todo el ejemplo es el siguiente:

XAML

<Grid>
 
<Viewport3D ClipToBounds="True" Width="150" Height="150">
 
<Viewport3D.Camera>
 
<PerspectiveCamera Position="0,0,2"/>
 
</Viewport3D.Camera>
 
<Viewport3D.Children>
 
<ModelVisual3D>
 
<ModelVisual3D.Content>
 
<DirectionalLight Color="White" Direction="-0.5,-0.1,-0.5" />
 
</ModelVisual3D.Content>
 
</ModelVisual3D> 
 
<ModelVisual3D>
 
<ModelVisual3D.Content>
 
<GeometryModel3D>
 
<GeometryModel3D.Geometry>
 
<MeshGeometry3D
 
Positions="-0.5,-0.5,0.5 0.5,-0.5,0.5 0.5,0.5,0.5 0.5,0.5,0.5 -0.5,0.5,0.5 -0.5,-0.5,0.5 " />
 
</GeometryModel3D.Geometry>
 
<GeometryModel3D.Material>
 
<DiffuseMaterial Brush="Red" ></DiffuseMaterial>
 
</GeometryModel3D.Material>
 
<GeometryModel3D.Transform>
 
<RotateTransform3D>
 
<RotateTransform3D.Rotation>
 
<AxisAngleRotation3D Axis="0,3,0" Angle="40" />
 
</RotateTransform3D.Rotation>
 
</RotateTransform3D>
 
</GeometryModel3D.Transform> 
 
</GeometryModel3D> 
 
</ModelVisual3D.Content>
 
</ModelVisual3D> 
 
</Viewport3D.Children>
 
<Viewport3D.Triggers>
 
<EventTrigger RoutedEvent="Viewport3D.Loaded">
 
<BeginStoryboard>
 
<Storyboard>
 
<DoubleAnimation From="1" To="360" Duration="0:0:03" AccelerationRatio="1" RepeatBehavior="Forever" 
 
Storyboard.TargetProperty="(Viewport3D.Children)[1].(ModelVisual3D.Content).(GeometryModel3D.Transform).(RotateTransform3D.Rotation).(AxisAngleRotation3D.Angle)"></DoubleAnimation>
 
</Storyboard>
 
</BeginStoryboard>
 
</EventTrigger>
 
</Viewport3D.Triggers> 
 
</Viewport3D>
 
</Grid>
 

 

Articulo Publicado en http://desarrollador.redusers.com/

Filed under: , ,

Comments

# Jabi said on February 16, 2009 05:17 AM:

Tiene muy buena pinta!!! la verdad es q te introduce bastanete bien al funciomiento. gracias

Leave a Comment

(required) 
(required) 
(optional)
(required) 

Protected by FormShield
Refresh
Listen
Please enter the characters shown on the image


Code: