Perspective : Easy 3D programming with WPF

tangibleassistantSoftware and s/w Development

Dec 3, 2013 (3 years and 8 months ago)

114 views


Perspective : Easy 3D programming with
WPF

A few years ago, I was impressed by the ease of 3D programming with
VPython

. This
library made it possible to build in language Python 3D models starting from basic (cube,
cylinder, sphere, etc.) or composite (arrow) geometrical objects, and to anime them. The
default visualization window allowed to move the camera around the sc
ene, and to zoom.
Thus it was easy to get with a few lines of code a very spectacular application. VPython was
very much used to illustrate physical models.
Example

.

WPF uses D
irect3D technology to provide creation services for 2D user interface but also for
3D scenes. You can find many references about this subject like this
tutorial

, who describes
the differen
t steps of the creation of a cube. Even if WPF is much easier to program than
Direct3D, we are still far from the VPython productivity. WPF misses high
-
level classes for
the 3D programming (cube, cylinder, sphere, etc.). Several authors make this constatat
ion and
give some solutions (of which however none goes as far as VPython) :



Generating a sphere
-
mesh in XAML




Ge
nerating 3d discs, cubes, spheres, etc. in WPF




Extending Visual3D
-

Sphere, Cone, and Cylinder

In the .NET 3.5 framework, the 3D evolves

. In particular, the
UIElement3D

class brings a
functional level which makes it possible to develop more easily inter
active 3D models. Its
functional level is close to that of UIElement in the 2D WPF world.

Since 2006, I developed a class library, Perspective, which offers WPF functionalities and
productivity close to those of VPython while integrating .NET 3.5 developme
nts and
technological innovations such as interactive 3D controls. Perspective project is hosted on
Codeplex

.

The continuation of the article applies to the current version of Perspective, which requires

.NET 3.5 and Visual Studio 2008.

Wpf3D Basics

Getting and installing Perspective

3D WPF programming basics are not explained here, but the text contains some links towards
the
SDK documentation

.

To use the Wpf3D classes in a Xaml

file, you have to define 2 XML namespaces referring the
Perspective assemblies :

<Page x:Class="PerspectiveDemo.UI.Pages.pWpf3D.Box3D"


xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"


xmlns:x="http://schemas.microsoft.com/winfx/2
006/xaml"


xmlns:p="http://www.codeplex.com/perspective"

...

Basically, a 3D scene is displayed in a
Viewport3D

object. Then we have to configure the
camera

and
lights

. In order to be able to move the point of view and to turn around the
model, it is possible to apply rotations to the camera (RotateTransform3D) around the X, Y
and Z axis . A scaling (ScaleTransform3D) may be applied to simulate a zoom effect. These
tra
nsformations may be bound to sliders.

In practice, it is tedious and repetitive. Perspective is consistent with this approach, but
provides, since version 0.9, the Workshop3D element which includes a Viewport3D, a
camera, lighting and a system of zoom and
displacement of view.

<Page ...>


<p:Workshop3D>


...


</p:Workshop3D>

</Page>

We can now instanciate our first visual Wpf3D object : the coordinate system (XyzAxis3D
class) which will visually help us to position our 3D elements :

<p:Workshop3D
>


<p:XyzAxis3D />

</p:Workshop3D>

If we execute now the application, we can see the coordinate system.


Online demo

The camera can be
controlled by mouse (with joysticks) or by keyboard (when the
Workshop3D is focused) :



Plus and Minus keys act on the zoom factor.



Numeric keypad arrow key act on the camera position (on a XZ plane)



When the Ctrl key is pressed, they move the orientation of the camera according to a
vertical plane (Up and Down arrows) or horizontal plane (Left and Right arrows).



When the Shift key is pressed, they turn the camera around the origin according to a
vert
ical plane (Up and Down arrows or position joystick's buttons) or horizontal plane
(Left and Right arrows or position joystick's buttons).



The key 5 or Ctrl
-
Plus of the numeric keypad elevate the position of the camera. Keys
Ctrl
-
5 or Ctrl
-
Minus reduce th
e height of the camera position.


The main properties of XyzAxis3D are : Radius, radius of each body axe, Length, size of
each axis, and Signed which dislays the negative axis.

<p:XyzAxis3D Length="5" Signed="True"/>


We can now begin to create our model
s. Let's start with a cube using the Box3D class:

<p:Workshop3D>


<p:XyzAxis3D Length="3.0"/>


<p:Box3D />

</p:Workshop3D>


Online demo

Each
Wpf3D object has a default material, which can be modified using the Material
property.

Our cube is positioned at the origin of the coordinate system, and the edges size is of 1 unit.
While reading the documentation, it may seem surprising that no property

enables us to
modify the position and the size of the cube. But that is completely normal. WPF uses the
graphics processor (GPU) which supports instructions to transform the position or the aspect
of the models. Modifying the position and the size of the
cube in our code would use the
main processor (CPU) instead of the GPU. To respect the WPF logic, we will use
3D
transformations

and assign them to the Transform property (always with th
e possibility of
defining the transformation in the resources centralized zone) :

...

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"


xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">


<Transform3DGroup x
:Key="ModelTransform">

<TranslateTransform3D OffsetX="1.0" OffsetY="
-
1.0" OffsetZ="0.5" />

<ScaleTransform3D ScaleX="1.0" ScaleY="1.0" ScaleZ="3.0" />

</Transform3DGroup> ... </ResourceDictionary> ... <Page.Resources> <ResourceDictionary
Source="Wpf3DResou
rces.xaml" /> </Page.Resources> <p:Workshop3D> <p:XyzAxis3D
Length="5.0"/> <p:Box3D Transform="{StaticResource ModelTransform}"/>
</p:Workshop3D> ...


Online demo

This principle applies to all the basic models delivered in Perspective. Their basic dimension
is the unit, and they are based on the

origin of the coordinate system (the point of coordinates
0.0, 0.0, 0.0).

Interactivity

Because the Perspective 3D objects are inheriting from UIElement3D, they support keyboard
and mouse interactions, and they have the corresponding events. The followin
g example
shows how to trigger a rotation of the 3D model when the mouse is over it, through the use of
the events MouseEnter and MouseLeave :

<p:Workshop3D>


<p:Box3D


MouseEnter="Box3D_MouseEnter"


MouseLeave="Box3D_MouseLeave">


<p:Box3D.Transform >


<RotateTransform3D CenterX="0.5" CenterZ="0.5">


<RotateTransform3D.Rotation>


<AxisAngleRotation3D


x:Name="boxRotation"


Axis="0.0, 1.0, 0.0"/>


</RotateTransform3D.Rotation>


</RotateTransform3D>


</p:Box3D.Transform>


</p:Box3D>

</p:Workshop3D>

private void Box3D_MouseEnter(object sender,
System.Windows.Input.Mous
eEventArgs e)

{


// Initialization of the animation object : on 360 degrees after the
current angle


DoubleAnimation da = new DoubleAnimation(boxRotation.Angle + 360.0, new
Duration(TimeSpan.FromSeconds(5.0)));


da.RepeatBehavior = RepeatBehavior.
Forever;


// Trigger the animation on the boxRotation's Angle property


boxRotation.ApplyAnimationClock(AxisAngleRotation3D.AngleProperty,
da.CreateClock());

}

private void Box3D_MouseLeave(object sender,
System.Windows.Input.MouseEventArgs e)

{


// current angle memorization


double currentAngle = boxRotation.Angle;


// Stops the animation


boxRotation.ApplyAnimationClock(AxisAngleRotation3D.AngleProperty,
null);


// Reassignment of the angle (which otherwise resumes its initial
value)


boxRotation.Angle = currentAngle;

}

Online demo

Flat models

The Square3D class defines... a 2D square !

<p:Square3D />


Online demo

The BackMaterial property has the same role than the Material property but for the back face.

On 3D not
-
flat models, the BackMaterial is v
isible when the material is translucent (Opacity
< 1.0).

Polygon
-
based models

Polygon3D defines a flat polygon. The SideCount property defines a regular polygon of a
given side count.

<p:Polygon3D SideCount="6" />


The polygon fits in a circle of radius 1 in the X, Y plan. The polygon vertices are calculated
by dividing the circumference by the SideCount value. By default, the 1st point is at 1,0,0.
The InitialAngle property makes it possible to move this point accor
ding to the angle of the
segment that it forms with the origin compared to the X axis. Example for an angle of 30
degrees :

<p:Polygon3D SideCount="6" InitialAngle="30.0"/>


The RoundingRate makes it possible to round the polygon vertices. The value must

be
comprised between 0.0 and 0.5. It represents a side proportion submitted to the rounding for
the 2 sides of a vertex. Thus a value of 0.5 generates a perfect circle. Example with a value of
0.15 :

<p:Polygon3D SideCount="6" InitialAngle="30.0"
RoundingRate="0.15"/>


Online demo

The bar3D class défines a bar with a polygonal section. The section has the same
characteristics than a Polygon3
D : side count, initial angle and rounding rate. For a better
emphasizing of the rounding, we use a glossy material (using SpecularMaterial) and move the
model compared to the light position.

<ResourceDictionary ...>


<SpecularMaterial x:Key="Specular"

SpecularPower="100.0"
Brush="White"/>


<MaterialGroup x:Key="GlossyMaterial">


<DiffuseMaterial Brush="Goldenrod"/>


<StaticResource ResourceKey="Specular"/>


</MaterialGroup>

</ResourceDictionary>

...

<p:Bar3D SideCount="6"
InitialAngle="30.0" RoundingRate="0.15"


Transform="{StaticResource ModelTransform}"


Material="{StaticResource GlossyMaterial}" />


Online demo

To build a cylinder with a radius of 1.0, you can grow the SideCount property :

<p:Bar3D SideCount="100" Material="{StaticResource glossyMaterial}" />


Online demo

Conical3D is a cone with a polygonal base, and works as Bar3D .

<p:Conical3D SideCount="6" InitialAngle="30.0" RoundingRate="0.15"


Transform="{StaticResource ModelTransform}"


Material="{StaticResource GlossyMaterial}" />


Online demo

Finally Ring3D is a ring with a polygonal section. It has additional properties to indicate its
radius and its segment count.

<p:Ring3D


Radius="10.0" SegmentCount="100"


SideCount="6" InitialAngle="30.0" RoundingRate="0.15"


Material="{StaticResource GlossyMaterial}" />


Onli
ne demo

Spherical models

The Spherical3D class defines a sphere with a radius of 1 unit. The smoothness of the
spherical aspect is defined using the ParallelCount property.

The meridian count is twice the parallel count.

<p:Spherical3D ParallelCount="100"

Material="{StaticResource
GlossyMaterial}"/>


Online demo

It is easy to transform the sphere into an ellipsoid using a tranform object.

<p
:Spherical3D ParallelCount="100"


Material="{StaticResource GlossyMaterial}"


Transform="{StaticResource ModelTransform}"/>


Onli
ne demo

Polyhedrons

Just for fun, the Isocahedron3D class defines a
regular isocahedron

, that is a 20 faces
polyhedron.

<p:Isocahedron3D Material="{StaticResource GlossyMaterial
}" />


Online demo

If we truncate its vertices, we get a
truncated isocahedron
... represented by the
TruncatedIsocahedron3D class.

<p
:Isocahedron3D Truncated="True" Material="{StaticResource
GlossyMaterial}" />


Online demo

Anyway, you see what I mean...
A very poor
translation from my french article !

The
Football3D class genesis began at a certain evening of July 2006. I am however not
impassioned by football (soccer). But after often seeing 3D animated credits at the TV, I
wanted to prove that WPF can do that. Here

we define a background with a new color and
without a displayed coordinate system, and we can animate the whole with a
3D WPF
animation

!
Play video

<p:Football3D />


Online demo

During the update of this article, in november

2007, I was thinking to build a rugby balloon.
But no... :
-
(

3D pie charts

The PieSlice3D class makes it possible to build beautiful pie charts. Each PieSlice3D
represents a portion, and has the properties InitialAngle and AngleValue. The IsExploded

property is used to highlight a portion. By default, the pie is built around the Z axis. For a
"flat" presentation, it is necessary to apply a transformation (as in the example below):

...

<Transform3DGroup x:Key="PieTransform">


<RotateTransform3D>



<RotateTransform3D.Rotation>


<AxisAngleRotation3D


Angle="
-
90"


Axis="1,0,0" />


</RotateTransform3D.Rotation>


</RotateTransform3D>


<ScaleTransform3D ScaleY="0.2"/>

</Transform3DGroup>

...

<p:Workshop
3D>


<p:PieSlice3D


AngleValue="45"


IsExploded="True"


Material="{StaticResource GlossyMaterial}"


Transform="{StaticResource PieTransform}"/>


<p:PieSlice3D


InitialAngle="45" AngleValue="135"


Material="{StaticResource GlossyRed}"


Transform="{StaticResource PieTransform}"/>


<p:PieSlice3D


InitialAngle="180" AngleValue="80"


Material="{StaticResource GlossyBlue}"


Transform="{StaticResource PieTransform
}"/>


<p:PieSlice3D


InitialAngle="260" AngleValue="100"


Material="{StaticResource GlossyGreen}"


Transform="{StaticResource PieTransform}"/>

</p:Workshop3D>


Online demo

Thanks to Philippe Jovelin for his contribution.

Texture

It is possible to display an image on a Square3D, by using an ImageBrush or a VisualBrush in
the Material definition.

<p:Square3D >


<p:
Square3D.Material>


<DiffuseMaterial>


<DiffuseMaterial.Brush>


<ImageBrush


ImageSource="http://www.odewit.net/Perspective/Images/Tree.jpg"


TileMode="None"


Stre
tch="Fill"/>


</DiffuseMaterial.Brush>


</DiffuseMaterial>


</p:Square3D.Material>

</p:Square3D>



If the BackMaterial

property is empty, the back face uses the default material.

You can apply a VisualBrush, an ImageBrush or a DrawingBrush on Square3D, Polygon3D,
Box3D, Bar3D, Conical3D and Spherical3D.






Composite models

The Wpf3D objects can be gathered in a
ModelVisual3D

or in a
ContainerUIElement3D

to
form a composite model, such as this gyroscope (animated when you click on it) :

<p:Gyroscope3D />


Online demo

The Perspective library is extensible, and it is easy to define in .NET code (C# or Visual
Basic) some new composite model classes. After XyzAxis3D and Football3D, the Arrow3D
class is another example :

<p:Arrow3D Material="{StaticResource GlossyMaterial}
" />



Online demo