Información general sobre transformaciones de modelos 3D

En este tema se describe cómo aplicar las transformaciones a los modelos 3D del sistema de gráficos de Windows Presentation Foundation (WPF). Las transformaciones permiten que el desarrollador cambie la posición y el tamaño de los modelos, así como que los vuelva a orientar sin cambiar los valores base que los definen.

Espacio de coordenadas 3D

El contenido de los gráficos 3D de Windows Presentation Foundation (WPF) se encapsula en un elemento, Viewport3D, que puede participar en la estructura de elementos bidimensionales. El sistema de gráficos trata Viewport3 como un elemento visual bidimensional, al igual que ocurre con muchos otros elementos de Windows Presentation Foundation (WPF). Viewport3D funciona como ventana (una ventanilla) de una escena tridimensional. Más concretamente, es una superficie en la que se proyecta una escena 3D. Aunque puede usar Viewport3D con otros objetos de dibujo 2D en el mismo gráfico de escena, no puede interpenetrar objetos 2D y 3D en un Viewport3D. El elemento Viewport3D contiene el espacio de coordenadas descrito en la siguiente descripción.

El sistema de coordenadas de Windows Presentation Foundation (WPF) para gráficos 2D localiza el origen en la parte superior izquierda de la superficie de representación (que suele ser la pantalla). En el sistema 2D, los valores positivos del eje X se extienden hacia la derecha, y los valores positivos del eje Y se extienden hacia abajo. En el sistema de coordenadas 3D, sin embargo, el origen se encuentra en el centro del área de la pantalla, los valores positivos del eje X se extienden hacia la derecha, los del eje Y, hacia arriba (no hacia abajo) y los del eje Z, hacia el exterior partiendo del origen; es decir, hacia el lector.

Sistemas de coordenadas
Coordinación de la comparación de sistemas

El espacio definido por estos ejes es el marco estático de referencia para los objetos 3D en Windows Presentation Foundation (WPF). Cuando se generan modelos en este espacio y se crean luces y cámaras para verlos, es útil distinguir este marco estático de referencia, o "espacio universal", del marco de referencia local creado para cada modelo al aplicarle transformaciones. Recuerde también que los objetos del espacio universal podrían parecer completamente diferentes, o incluso no verse en absoluto, dependiendo de la configuración de las luces y la cámara, pero que la posición de la cámara no cambia la ubicación de los objetos en el espacio universal.

Transformación de modelos

Al crear modelos, estos tienen una ubicación determinada en la escena. Para mover esos modelos por la escena, girarlos o cambiar su tamaño, no es práctico cambiar los vértices que definen los propios modelos. En lugar de ello, al igual que en 2D, se aplican transformaciones a los modelos.

Cada objeto del modelo tiene una propiedad Transform con la que puede mover, reorientar o redimensionar el modelo. Al aplicar una transformación, en realidad lo que se hace es desplazar todos los puntos del modelo según un vector o valor especificado por la transformación. Es decir, se transforma el espacio de coordenadas en el que se ha definido el modelo ("espacio del modelo"), pero no se cambian los valores que constituyen la geometría del modelo en el sistema de coordenadas de la escena completa ("espacio universal").

Transformaciones de la traslación

Las transformaciones 3D heredan de la clase base abstracta Transform3D; estas incluyen las clases de transformación afín TranslateTransform3D, ScaleTransform3D y RotateTransform3D. El sistema 3D de Windows Presentation Foundation (WPF) también proporciona una clase MatrixTransform3D que permite especificar las mismas transformaciones en operaciones de matrices más precisas.

TranslateTransform3D mueve todos los puntos en Model3D en la dirección del vector desplazado que especifica con las propiedades OffsetX, OffsetY y OffsetZ. Por ejemplo, dado un vértice de un cubo en (2,2,2), un vector de desplazamiento de (0,1.6,1) movería el vértice (2,2,2) a (2,3.6,3). El vértice del cubo sigue siendo (2,2,2) en el espacio del modelo, pero ahora dicho espacio ha cambiado su relación al espacio universal, de tal forma que (2,2,2) en el espacio del modelo es (2,3.6,3) en el espacio universal.

Figura de traslación
Traslación con desplazamiento

En los ejemplos de código siguientes se muestra cómo aplicar una traslación.

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
  <DockPanel>
    <Viewbox>
      <Canvas Width="600" Height="201">

        <!-- The Viewport3D provides a rendering surface for 3-D visual content. -->
        <Viewport3D Name="MyAnimatedObject"
          ClipToBounds="True" Width="600" Height="150"
          Canvas.Left="0" Canvas.Top="10">

          <!-- Defines the camera used to view the 3D object. -->
          <Viewport3D.Camera>
            <PerspectiveCamera x:Name="myPerspectiveCamera" Position="0,0,2" LookDirection="0,0,-1" 
             FieldOfView="60" />
          </Viewport3D.Camera>

          <!-- The ModelVisual3D children contain the 3D models -->
          <Viewport3D.Children>

            <!-- This ModelVisual3D defines the light cast in the scene. Without light, the
                 3D object cannot be seen. -->
            <ModelVisual3D>
              <ModelVisual3D.Content>
                <DirectionalLight Color="#FFFFFF" Direction="-0.612372,-0.5,-0.612372" />
              </ModelVisual3D.Content>
            </ModelVisual3D>
            <ModelVisual3D>
              <ModelVisual3D.Content>
                <GeometryModel3D>

                  <!-- The geometry specifes the shape of the 3D plane. In this case, a flat sheet is created. -->
                  <GeometryModel3D.Geometry>
                    <MeshGeometry3D
                     TriangleIndices="0,1,2 3,4,5 "
                     Normals="0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 "
                     TextureCoordinates="0,0 1,0 1,1 1,1 0,1 0,0 "
                     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>

                  <!-- The material specifies the material applied to the plane. In this case it is a linear gradient.-->
                  <GeometryModel3D.Material>
                    <MaterialGroup>
                      <DiffuseMaterial>
                        <DiffuseMaterial.Brush>
                          <SolidColorBrush Color="Cyan" Opacity="0.3"/>
                        </DiffuseMaterial.Brush>
                      </DiffuseMaterial>
                    </MaterialGroup>
                  </GeometryModel3D.Material>
                  <!-- The Transform specifies how to transform the 3D object. The OffsetX property is animated
                       in the Storyboard below. -->
                  <GeometryModel3D.Transform>
                    <TranslateTransform3D x:Name="myTranslateTransform3D" OffsetX="0" OffsetY="0" OffsetZ="0" />
                  </GeometryModel3D.Transform>
                </GeometryModel3D>
              </ModelVisual3D.Content>
            </ModelVisual3D>
          </Viewport3D.Children>
          <!-- Trigger the TranslateTransform3D animation when the 3D object loads. -->
          <Viewport3D.Triggers>
            <EventTrigger RoutedEvent="Viewport3D.Loaded">
              <BeginStoryboard>
                <Storyboard>

                  <!-- This animation animates the OffsetX property of the TranslateTransform3D. -->
                  <DoubleAnimation
                   Storyboard.TargetName="myTranslateTransform3D" 
                   Storyboard.TargetProperty="OffsetX" 
                   To="-0.8" 
                   AutoReverse="True" RepeatBehavior="Forever" />

                  <!-- If you want to animate OffsetY and/or OffsetZ, create similar DoubleAnimations
                       respectively. -->

                </Storyboard>
              </BeginStoryboard>
            </EventTrigger>
          </Viewport3D.Triggers>
        </Viewport3D>
      </Canvas>
    </Viewbox>
  </DockPanel>
</Page>

Transformaciones de escala

ScaleTransform3D cambia la escala del modelo mediante un vector de escala especificado respecto a un punto central. Especifique una escala uniforme, que escala el modelo mediante el mismo valor en los ejes X, Y y Z, para cambiar proporcionalmente el tamaño del modelo. Por ejemplo, si se establece el valor de las propiedades ScaleX, ScaleY y ScaleZ de la transformación en mitades de 0,5 del tamaño del modelo, al establecer el valor de las mismas propiedades en 2 se duplica su escala en los tres ejes.

ScaleTransform3D uniforme
Ejemplo de ScaleVector

Si se especifica una transformación de escala no uniforme (una transformación de escala cuyos valores X, Y y Z no son iguales), se puede provocar el estiramiento o la contracción del modelo en una o dos dimensiones sin afectar el resto. Por ejemplo, si se establece el valor de ScaleX en 1, de ScaleY en 2 y de ScaleZ en 1, se provocaría la duplicación del alto del modelo transformado pero permanecería igual a lo largo de los ejes X y Z.

De forma predeterminada, ScaleTransform3D provoca la expansión o contracción de los vértices en el origen (0,0,0). Sin embargo, si el modelo que desea transformar no se extrae del origen, el escalado del modelo desde el origen no escalará el modelo "en contexto". En su lugar, cuando los vértices del modelo se multiplican por el vector de escala, la operación de escala tendrá el efecto de traducir el modelo, así como escalarlo.

Tres cubos con escala ajustada y con punto central especificado
Ejemplo de ScaleCenter

Para escalar el modelo "en contexto", especifique el centro real del modelo estableciendo las propiedades CenterX, CenterY y CenterZ de ScaleTransform3D. De esta forma, se asegura de que el sistema de gráficos escala el espacio del modelo y luego lo traslada para centrarse en el objeto Point3D especificado. A la inversa, si ha creado el modelo en el origen y especifica un punto central diferente, espere ver el modelo trasladado fuera del origen.

Transformaciones de giro

Puede girar un modelo 3D de varias maneras diferentes. Una transformación de giro típica especifica un eje y un ángulo de giro alrededor de ese eje. La clase RotateTransform3D permite definir un objeto Rotation3D con su propiedad Rotation. Después especifique las propiedades Axis y Angle en Rotation3D, en este caso un objeto AxisAngleRotation3D, para definir la transformación. En los ejemplos siguientes se gira un modelo 60 grados sobre el eje Y.

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
  <DockPanel>
    <Viewbox>
      <Canvas Width="321" Height="201">

        <!-- The Viewport3D provides a rendering surface for 3-D visual content. -->
        <Viewport3D Name="MyAnimatedObject"
          ClipToBounds="True" Width="150" Height="150"
          Canvas.Left="0" Canvas.Top="10">

          <!-- Defines the camera used to view the 3D object. -->
          <Viewport3D.Camera>
            <PerspectiveCamera x:Name="myPerspectiveCamera" Position="0,0,2" LookDirection="0,0,-1" 
             FieldOfView="60" />
          </Viewport3D.Camera>

          <!-- The ModelVisual3D children contain the 3D models -->
          <Viewport3D.Children>

            <!-- Two ModelVisual3D define the lights cast in the scene. Without light, the
                 3D object cannot be seen. Also, the direction of the lights affect shadowing. -->
            <ModelVisual3D>
              <ModelVisual3D.Content>
                <DirectionalLight Color="#FFFFFF" Direction="-0.612372,-0.5,-0.612372" />
              </ModelVisual3D.Content>
            </ModelVisual3D>
            <ModelVisual3D>
              <ModelVisual3D.Content>
                <DirectionalLight Color="#FFFFFF" Direction="0.612372,-0.5,-0.612372" />
              </ModelVisual3D.Content>
            </ModelVisual3D>
            <ModelVisual3D>
              <ModelVisual3D.Content>
                <GeometryModel3D>

                  <!-- The geometry specifes the shape of the 3D plane. In this case, a flat sheet is created. -->
                  <GeometryModel3D.Geometry>
                    <MeshGeometry3D
                     TriangleIndices="0,1,2 3,4,5 "
                     Normals="0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 "
                     TextureCoordinates="0,0 1,0 1,1 1,1 0,1 0,0 "
                     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>

                  <!-- The material specifies the material applied to the plane. In this case it is a linear gradient.-->
                  <GeometryModel3D.Material>
                    <MaterialGroup>
                      <DiffuseMaterial>
                        <DiffuseMaterial.Brush>
                          <LinearGradientBrush StartPoint="0,0.5" EndPoint="1,0.5">
                            <LinearGradientBrush.GradientStops>
                              <GradientStop Color="Yellow" Offset="0" />
                              <GradientStop Color="Red" Offset="0.25" />
                              <GradientStop Color="Blue" Offset="0.75" />
                              <GradientStop Color="LimeGreen" Offset="1" />
                            </LinearGradientBrush.GradientStops>
                          </LinearGradientBrush>
                        </DiffuseMaterial.Brush>
                      </DiffuseMaterial>
                    </MaterialGroup>
                  </GeometryModel3D.Material>

                  <!-- The Transform specifies how to transform the 3D object. The properties of the
                        Rotation object are animated causing the 3D object to rotate and "wobble" (see Storyboard below).-->
                  <GeometryModel3D.Transform>
                    <RotateTransform3D>
                      <RotateTransform3D.Rotation>
                        <AxisAngleRotation3D x:Name="myAngleRotation" Axis="0,3,0" Angle="40" />
                      </RotateTransform3D.Rotation>
                    </RotateTransform3D>
                  </GeometryModel3D.Transform>
                </GeometryModel3D>
              </ModelVisual3D.Content>
            </ModelVisual3D>
          </Viewport3D.Children>

          <!-- Trigger the rotation animation when the 3D object loads. -->
          <Viewport3D.Triggers>
            <EventTrigger RoutedEvent="Viewport3D.Loaded">
              <BeginStoryboard>
                <Storyboard>

                  <!-- This animation animates the Angle property of the AxisAngleRotation3D
                       making the 3D object rotate from -60 degrees to 60 degrees. -->
                  <DoubleAnimation 
                   Storyboard.TargetName="myAngleRotation" 
                   Storyboard.TargetProperty="Angle" 
                   From="-60" To="60" Duration="0:0:4" AutoReverse="True"  RepeatBehavior="Forever"/>

                  <!-- This animation animates the Axis property of the AxisAngleRotation3D
                       making the 3D wobble as it rotates. -->
                  <Vector3DAnimation 
                   Storyboard.TargetName="myAngleRotation" 
                   Storyboard.TargetProperty="Axis" 
                   From="0,3,0" To="1,0,1" Duration="0:0:4" AutoReverse="True"  RepeatBehavior="Forever"/>

                </Storyboard>
              </BeginStoryboard>
            </EventTrigger>
          </Viewport3D.Triggers>
        </Viewport3D>
      </Canvas>

    </Viewbox>
  </DockPanel>
</Page>

Nota: 3D de Windows Presentation Foundation (WPF) es un sistema diestro, es decir, un valor angular positivo de un giro tiene como resultado un giro en el sentido contrario a las agujas del reloj sobre el eje.

Los giros angulares del eje presuponen el giro sobre el origen si no se especifica ningún valor para las propiedades CenterX, CenterY y CenterZ en RotateTransform3D. Como ocurre con el escalado, es útil recordar que el giro transforma el espacio de coordenadas de todo el modelo. Si el modelo no se creó sobre el origen, o se ha trasladado previamente, el giro podría "pivotar" sobre el origen en lugar de girar en contexto.

Rotación con punto central nuevo
Rotation con nuevo centro especificado

Para girar el modelo "en contexto", especifique el centro real del modelo como el centro de giro. Puesto que la geometría se suele modelar en el origen, la mayor parte de las veces puede obtener el resultado esperado de un conjunto de transformaciones si primero ajusta el tamaño del modelo (lo escala), después establece su orientación (lo gira) y, finalmente, lo mueve a la ubicación deseada (lo traslada).

Rotación de 60 grados en los ejes x e y
Ejemplo de giro

Los giros angulares sobre el eje funcionan bien para las transformaciones estáticas y algunas animaciones. Sin embargo, considere girar un modelo de cubo 60 grados sobre el eje X y luego 45 grados sobre el eje Z. Puede describir esta transformación como dos transformaciones afines discretas o como matriz. Sin embargo, quizá sea difícil animar un giro definido así de forma continua. Aunque las posiciones inicial y final del modelo, calculadas mediante cualquiera de los enfoque son las mismas, varía el cálculo de las posiciones intermedias tomadas por el modelo. Los cuaterniones representan una forma alternativa de calcular la interpolación entre el inicio y el fin de un giro.

Un cuaternión representa un eje en el espacio 3D y un giro alrededor de ese eje. Por ejemplo, un cuaternión podría representar un eje (1,1,2) y un giro de 50 grados. La capacidad de los cuaterniones al definir los giros procede de las dos operaciones que puede realizar en ellos: composición e interpolación. La composición de dos cuaterniones aplicadas a una geometría significa "girar la geometría alrededor de axis2 por rotation2 y girarla alrededor de axis1 por rotation1". Mediante el uso de la composición, puede combinar los dos giros de la geometría para obtener un único cuaternión que representa el resultado. Puesto que la interpolación del cuaternión puede calcular una ruta de acceso continuada y correcta desde un eje y la orientación a otro, puede interpolar desde el cuaternión original al compuesto para lograr una transición continuada de uno a otro, permitiéndole animar la transformación. En los modelos que desee animar, puede especificar un objeto Quaternion de destino para el giro utilizando QuaternionRotation3D para la propiedad Rotation.

Uso de colecciones de transformaciones

Al crear una escena, es normal aplicar más de una transformación a un modelo. Agregue transformaciones a la colección Children de la clase Transform3DGroup para agrupar transformaciones convenientemente con el fin de aplicarlas a diversos modelos de la escena. A menudo es conveniente volver a usar una transformación en varios grupos diferentes, de la misma forma que puede volver a usar un modelo aplicando un conjunto diferente de transformaciones a cada instancia. Observe que el orden en el que las transformaciones se agregan a la colección es importante: las transformaciones de la colección se aplican de la primera a la última.

Animación de transformaciones

La implementación 3D en Windows Presentation Foundation (WPF) utiliza el mismo sistema de control de tiempo y animación que los gráficos 2D. En otras palabras, para animar una escena 3D, se animan las propiedades de sus modelos. Es posible animar directamente las propiedades de los elementos primitivos, pero suele ser más fácil animar las transformaciones que cambian la posición o el aspecto de los modelos. Dado que las transformaciones se pueden aplicar a los objetos Model3DGroup, así como a los modelos individuales, es posible de aplicar un conjunto de animaciones a los elementos secundarios de un Model3Dgroup y otro conjunto de animaciones a un grupo de objetos. Para obtener información general sobre el sistema de control de tiempo y animación de Windows Presentation Foundation (WPF), consulte los temas Información general sobre animaciones e Información general sobre objetos Storyboard.

Para animar un objeto en Windows Presentation Foundation (WPF), se crea una escala de tiempo, se define una animación (que, en realidad, es un cambio de algún valor de propiedad a lo largo del tiempo) y se especifica la propiedad a la que aplicar la animación. Esta propiedad debe ser una propiedad de FrameworkElement. Dado que todos los objetos de una escena 3D son elementos secundarios de Viewport3D, las propiedades de destino de cualquier animación que desea aplicar a la escena son propiedades de propiedades de Viewport3D. Es importante obtener la ruta de acceso de la propiedad de la animación correctamente, ya que la sintaxis puede ser prolija.

Suponga que desea girar un objeto en contexto, pero también aplicar un movimiento oscilante para que se vean más partes del objeto. Podría aplicar RotateTransform3D al modelo y animar el eje de giro de un vector a otro. En el ejemplo de código siguiente se muestra cómo aplicar Vector3DAnimation a la propiedad Axis de la propiedad Rotation3D de la transformación, suponiendo que RotateTransform3D es una de las diversas transformaciones aplicadas al modelo con TransformGroup.

//Define a rotation
RotateTransform3D myRotateTransform = new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 1, 0), 1));
'Define a rotation
Dim myRotateTransform As New RotateTransform3D(New AxisAngleRotation3D(New Vector3D(0, 1, 0), 1))
Vector3DAnimation myVectorAnimation = new Vector3DAnimation(new Vector3D(-1, -1, -1), new Duration(TimeSpan.FromMilliseconds(5000)));
myVectorAnimation.RepeatBehavior = RepeatBehavior.Forever;
Dim myVectorAnimation As New Vector3DAnimation(New Vector3D(-1, -1, -1), New Duration(TimeSpan.FromMilliseconds(5000)))
myVectorAnimation.RepeatBehavior = RepeatBehavior.Forever

Utilice una sintaxis similar para que otras propiedades de la transformación muevan o escalen el objeto. Por ejemplo, podría aplicar Point3DAnimation a la propiedad ScaleCenter en una transformación de escala para que un modelo distorsione su forma continuadamente.

Aunque los ejemplos anteriores transforman las propiedades de GeometryModel3D, también es posible transformar las propiedades de otros modelos de la escena. Animando traslaciones aplicadas a objetos Light, por ejemplo, puede crear luz en movimiento y efectos de sombra que pueden cambiar el aspecto de los modelos espectacularmente.

Puesto que las cámaras también son modelos, igualmente se pueden transformar las propiedades de la cámara. Aunque puede cambiar el aspecto de la escena transformando la ubicación de la cámara o las distancias de los planos (de hecho, transformando toda la proyección de la escena), tenga en cuenta que muchos de los efectos obtenidos de esta forma quizá no tengan tanto "sentido visual" para el lector como las transformaciones aplicadas a la ubicación o posición de los modelos de la escena.

Vea también