Perspective : relative WPF 3D transformsPerspective : relative WPF 3D transforms
By default, the position, the scale factor and the rotation angle of a WPF 3D model have to be defined by a transform (or a Transform3DGroup object which gathers several transforms).
Indeed, transforms are supported by the graphics processor (GPU). Without them, the positioning and sizing calculations would use the CPU, which could cause performance problems (displacement of large models in particular).
That's why classes inherited from Visual3D (including those of Perspective) do not expose property indicating their position.
But it may surprise at first. And this may be inconvenient for some scenarios, eg when one wishes to apply successively (and relatively) several transforms. Indeed, only one transform (or one group of transforms) is applicable at a given time, and relatively to the initial coordinates.
To address this problem, I developed the RelativeTransformer class in the Perspective.Wpf3D namespace of the Perspective 2 beta Library, which can be downloaded here .
This class has methods that allow to apply successive displacements, rotations and scalings to a Visual3D object. This class remembers for the current position and the transform matrix of the Visual3D. Some attached Properties (Position, Matrix) provide access to these informations. The resulting transform is available through the MatrixTransform attached property.
Take the example of a basic Perspective model : a Box3D defined in XAML as follows :
...
<Window.Resources>
<SpecularMaterial x:Key="Specular" SpecularPower="100.0" Brush="White"/>
<MaterialGroup x:Key="GlossyMaterial">
<DiffuseMaterial Brush="Goldenrod"/>
<StaticResource ResourceKey="Specular"/>
</MaterialGroup>
...
</Window.Resources>
...
<p:Workshop3D>
<p:XyzAxis3D Length="4.0"/>
<p:Box3D x:Name="box" Material="{StaticResource GlossyMaterial}" />
</p:Workshop3D>
...
Moving
The MoveTo method of the RelativeTransformer class moves the Visual3D to a specific position, here a Box3D to the coordinates (0,1,0) :
public partial class Window1 : Window
{
RelativeTransformer _transformer = new RelativeTransformer();
...
private void t1_Click(object sender, RoutedEventArgs e)
{
_transformer.MoveTo(box, 0, 1, 0);
}
...
}
The MoveTo method can be called multiple times. Each time, the resultant position is stored in the Position property.
The Translate method moves the Visual3D specifying a vector or a shift of coordinates on the current position, as here (2 on the X axis, -1 on the Y axis):
_transformer.Translate(box, 2, -1, 0);

The MoveTo and Translate methods modify the current position, available in the Position attached property.
Rotations
The RotateX method of the RelativeTransformer class applies a rotation around the x-axis.
_transformer.RotateX(box, 45);

A second call applies the rotation in relative to the previous one :

Similarly, the Rotate RotateY and RotateZ methods apply a rotation around the y- and z-axis. And the RotateXYZ and RotateZYX methods apply a rotation on the 3 axis, in the order indicated by the name of the method.
Scaling
The Scale method of the RelativeTransformer class applies a scale factor to a Visual3D :
_transformer.Scale(box, 0.5);

A second call applies a scaling in relative to the previous one :

Compatibility with initial transforms
If transforms have been previously applied, they are retained. The internal matrix transform managed by RelativeTransformer is automatically combined with the initial transforms.
<Window.Resources>
...
<ScaleTransform3D
x:Key="ModelTransform"
ScaleX="1.0" ScaleY="2.0" ScaleZ="1.0" />
</Window.Resources>
...
<p:Workshop3D>
...
<p:Box3D
x:Name="box"
Material="{StaticResource GlossyMaterial}"
Transform="{StaticResource ModelTransform}"/>
</p:Workshop3D>
_transformer.MoveTo(box, 0, 1, 0);
_transformer.Translate(box, 2, -1, 0);
_transformer.RotateX(box, 45);
_transformer.Scale(box, 0.5);

About this article
Author : Olivier Dewit
History :