Compartir a través de


Introducción a las transformaciones 3D

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

Espacio de coordenadas 3D

El contenido gráfico 3D de Windows Presentation Foundation (WPF) se encapsula en un elemento , Viewport3Dque puede participar en la estructura de elementos bidimensionales. El sistema gráfico trata Viewport3D como un elemento visual bidimensional como muchos otros en Windows Presentation Foundation (WPF). Viewport3D funciona como una ventana (una ventanilla) en una escena tridimensional. Con mayor precisión, es una superficie en la que se proyecta una escena 3D. Aunque puede usar Viewport3D con otros objetos de dibujo 2D en el mismo grafo de escena, no puede interpenetrar objetos 2D y 3D dentro de Viewport3D. En la siguiente explicación, el espacio de coordenadas descrito está incluido en el elemento Viewport3D.

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 (normalmente la pantalla). En el sistema 2D, los valores positivos del eje X continúan hacia la derecha y los valores positivos del eje Y continúan hacia abajo. Sin embargo, en el sistema de coordenadas 3D, el origen se encuentra en el centro de la pantalla, con valores positivos del eje X que continúan hacia la derecha, pero los valores positivos del eje Y continúan hacia arriba, y los valores positivos del eje Z que continúan hacia fuera desde el origen, hacia el visor.

Sistemas de coordenadas
Comparación del sistema de coordenadas

El espacio definido por estos ejes es el marco fijo de referencia para objetos 3D en Windows Presentation Foundation (WPF). A medida que crea modelos en este espacio y crea luces y cámaras para verlas, resulta útil distinguir este marco de referencia estacionario, o "espacio mundial", del marco de referencia local que se crea para cada modelo al aplicar transformaciones. Recuerde también que los objetos del espacio mundial pueden parecer completamente diferentes o no estar visibles en absoluto, dependiendo de la luz y la configuración de la cámara, pero la posición de la cámara no cambia la ubicación de los objetos en el espacio mundial.

Transformación de modelos

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

Cada objeto de modelo tiene una Transform propiedad con la que se puede mover, volver a orientar o cambiar el tamaño del modelo. Al aplicar una transformación, se desplazan eficazmente todos los puntos del modelo por cualquier vector o valor especificado por la transformación. En otras palabras, ha transformado el espacio de coordenadas en el que se define el modelo ("espacio del modelo"), pero no ha cambiado los valores que componen la geometría del modelo en el sistema de coordenadas de toda la escena ("espacio mundial").

Transformaciones de traducción

Las transformaciones 3D heredan de la clase Transform3Dbase abstracta; incluyen las clases TranslateTransform3Dde transformación affine , ScaleTransform3Dy RotateTransform3D. El sistema 3D de Windows Presentation Foundation (WPF) también proporciona una MatrixTransform3D clase que permite especificar las mismas transformaciones en operaciones de matriz más concisas.

TranslateTransform3D mueve todos los puntos en el Model3D en la dirección del vector de desplazamiento que especifique 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 ese 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 que el espacio del modelo ha cambiado su relación con el espacio global para que (2,2,2) en el espacio del modelo sea (2,3.6,3) en el espacio global.

Figura de traducción
Traducción con desplazamiento

En los ejemplos de código siguientes se muestra cómo aplicar una traducció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 escalado

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

Escala Uniforme Transform3D
Ejemplo de ScaleVector

Al especificar una transformación de escala no uniforme (una transformación de escala cuyas dimensiones X, Y y Z no son iguales), puede hacer que un modelo se amplíe o contraiga en una o dos dimensiones sin afectar a los demás. Por ejemplo, si se establece ScaleX en 1, ScaleY en 2 y ScaleZ en 1, el modelo transformado se duplicaría en altura, pero permanecerá sin cambios a lo largo de los ejes X y Z.

De forma predeterminada, ScaleTransform3D hace que los vértices se expandan o contraigan sobre 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 su lugar". 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 escalados con el punto central especificado
Ejemplo del Centro de escalado

Para escalar un modelo "en el lugar", especifique el centro del modelo estableciendo las propiedades CenterX, CenterY y CenterZ de ScaleTransform3D. Esto garantiza que el sistema gráfico escala el espacio del modelo y luego lo traslada para centrarlo en el especificado Point3D. Por el contrario, si ha creado el modelo sobre el origen y especifica un punto central diferente, espere ver el modelo traducido fuera del origen.

Transformaciones de rotación

Puede rotar un modelo en 3D de varias maneras diferentes. Una transformación de rotación típica especifica un eje y un ángulo de rotación alrededor de ese eje. La RotateTransform3D clase permite definir un Rotation3D con su propiedad Rotation. A continuación, especifique las propiedades Axis y Angle en Rotation3D, en este caso AxisAngleRotation3D, para definir la transformación. En los ejemplos siguientes se gira un modelo en 60 grados alrededor del 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:Windows Presentation Foundation (WPF) 3D es un sistema de mano derecha, lo que significa que un valor de ángulo positivo para una rotación da como resultado un giro en sentido contrario a las agujas del reloj sobre el eje.

Las rotaciones con eje y ángulo asume una rotación alrededor del origen si no se especifica un valor para las propiedades CenterX, CenterY y CenterZ en RotateTransform3D. Al igual que con el escalado, resulta útil recordar que la rotación transforma todo el espacio de coordenadas del modelo. Si el modelo no se creó con respecto al origen o ha sido traducido anteriormente, la rotación podría "pivotar" alrededor del origen en lugar de girar en su lugar.

Rotación con un nuevo punto central
Rotación con el nuevo centro especificado

Para girar el modelo "en el lugar", especifique el centro actual del modelo como el punto de rotación. Dado que la geometría se modela normalmente sobre el origen, puede obtener el resultado esperado de un conjunto de transformaciones cambiando primero el tamaño del modelo (escalado), después estableciendo su orientación (girando) y, por último, moviéndolo a la ubicación deseada (traduciéndolo).

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

Los giros de ángulo de eje funcionan bien para las transformaciones estáticas y algunas animaciones. Sin embargo, considere la posibilidad de girar un modelo de cubo de 60 grados alrededor del eje X y, a continuación, 45 grados alrededor del eje Z. Puede describir esta transformación como dos transformaciones afín discretas o como una matriz. Sin embargo, puede ser difícil animar sin problemas una rotación definida de esta manera. Aunque las posiciones iniciales y finales del modelo calculados por cualquiera de los enfoques son las mismas, las posiciones intermedias tomadas por el modelo son inciertas computacionalmente. Los cuaterniones representan una manera alternativa de calcular la interpolación entre el inicio y el final de una rotación.

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. El poder de los cuaterniones en la definición de rotaciones procede de las dos operaciones que puede realizar en ellos: composición e interpolación. La composición de dos cuaterniones aplicados a una geometría significa "girar la geometría alrededor del eje2 mediante rotación2 y, a continuación, girarla alrededor del eje1 por rotación1". Usando la composición, se pueden combinar las dos rotaciones de la geometría en un solo cuaternión que representa el resultado. Dado que la interpolación de cuaterniones puede calcular una trayectoria suave y razonable de un eje y una orientación a otro, puede interpolar desde el cuaternión original hasta el cuaternión compuesto para lograr una transición suave del uno al otro, permitiéndole animar la transformación. Para los modelos que desea animar, puede especificar un destino Quaternion para la rotación usando un QuaternionRotation3D en la propiedad Rotation.

Utilización de colecciones de transformación

Al crear una escena, es habitual aplicar más de una transformación a un modelo. Agregue transformaciones a la Children colección de la Transform3DGroup clase para agrupar transformaciones convenientemente para aplicarlas a varios modelos de la escena. A menudo es conveniente reutilizar una transformación en varios grupos diferentes, en gran medida de la manera en que se puede reutilizar un modelo aplicando un conjunto diferente de transformaciones a cada instancia. Tenga en cuenta que el orden en el que las transformaciones se agregan a la colección es significativa: las transformaciones de la colección se aplican de primera a última.

Animar transformaciones

La implementación 3D de Windows Presentation Foundation (WPF) participa en el mismo sistema de tiempo y animación que los gráficos 2D. En otras palabras, para animar una escena 3D, anima las propiedades de sus modelos. Es posible animar las propiedades de los primitivos directamente, pero normalmente es más fácil animar las transformaciones que cambian la posición o la apariencia de los modelos. Dado que las transformaciones se pueden aplicar a Model3DGroup objetos como a modelos individuales, es posible aplicar un conjunto de animaciones a los hijos de un grupo Model3D y otro conjunto de animaciones a un grupo de objetos. Para obtener información general sobre el sistema de animación y control de tiempo de Windows Presentation Foundation (WPF), consulta Información general sobre animaciones e Información general sobre guiones gráficos.

Para animar un objeto en Windows Presentation Foundation (WPF), cree una escala de tiempo, defina una animación (que es realmente un cambio en algún valor de propiedad con el tiempo) y especifique la propiedad a la que se va a 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 afectadas por cualquier animación que desee aplicar a la escena son propiedades de Viewport3D. Es importante determinar cuidadosamente la ruta de propiedad para la animación, ya que la sintaxis puede ser verbosa.

Supongamos que desea girar un objeto en su lugar, pero también aplicar un movimiento oscilante para exponer más del objeto a la vista. Puede optar por aplicar un RotateTransform3D al modelo y animar el eje de su rotación de un vector a otro. En el ejemplo de código siguiente se muestra cómo aplicar un Vector3DAnimation a la propiedad Axis de la transformación Rotation3D, suponiendo que RotateTransform3D sea una de las varias transformaciones aplicadas al modelo con un 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

Use una sintaxis similar para establecer como destino otras propiedades de transformación para mover o escalar el objeto. Por ejemplo, podría aplicar un Point3DAnimation a la propiedad ScaleCenter en una transformación de escala para hacer que un modelo distorsione suavemente su forma.

Aunque los ejemplos anteriores transforman las propiedades de GeometryModel3D, también es posible transformar las propiedades de otros modelos de la escena. Al animar las traducciones aplicadas a objetos de luz, por ejemplo, puede crear efectos de luz y sombra en movimiento que cambien drásticamente la apariencia de sus modelos.

Dado que las cámaras también son modelos, también es posible transformar las propiedades de la cámara. Aunque puede cambiar ciertamente la apariencia de la escena mediante la transformación de la ubicación de la cámara o las distancias del plano (en efecto, la transformación de toda la proyección de escena), tenga en cuenta que muchos de los efectos que logras de esta manera pueden no tener tanto "sentido visual" al visor como transformaciones aplicadas a la ubicación o posición de los modelos en la escena.

Consulte también