13,046,773 members (65,230 online)
alternative version

#### Stats

155.1K views
54 bookmarked
Posted 20 Oct 2004

# 3D in XAML

, 20 Oct 2004
 Rate this:
A guide to using 3D tags in Mobiform and Longhorn XAML.

## 3D Basics

This section will explain the basics to understanding the concepts involved in creating a 3D scene in XAML.

### Coordinate system

By this point, you should be familiar with using 2D coordinates to place XAML object. Placing an object is very similar but requires an extra value, and rather than using whole numbers, all values can be floating point numbers (uses decimal places).

Below is a representation of a 2D Cartesian coordinate system, which can be used to define any point in 2D. Next to that is a 3D coordinate system, the line at an angle labeled Z generally represents depth, or distance from your point of view.

That’s the standard way to visualize things in the two coordinate systems. It's generally accepted in 2D computer graphics that 0,0 represents the top left of the screen. While that could be the case, in 3D it rarely is, where 0,0,0 is displayed in the screen depends on completely where the camera is (your point of view). Luckily, in XAML, there is an easy way to position an entire scene as you would any other 2D control, the `ViewPort3D`.

### Setting up a scene

The very first thing you need to setup a 3D scene is to define the `ViewPort3D`, this will position your scene on the canvas.

```<ViewPort3D Canvas.Top="50" Canvas.Left="50" Width="300" Height="300">
#Scene definition
</Viewport>```

The next thing you absolutely must have is a camera. Without a camera to represent your point of view (POV), you won't be seeing much. This would fit into the above code in the scene definition section.

```<ViewPort3D.Camera>
<PerspectiveCamera

Position="-250,250,200"

LookAtPoint="0,0,0"

Up="0,1,0"

FieldOfView="40"

NearPlaneDistance="1"

FarPlaneDistance="500"

/>
</ViewPort3D.Camera>```

This needs a little bit of explanation, but it's easiest to think of in terms of an eye. The first three sets of numbers position and orient the eye, `Position` gives the world position of where the eye will be, next is the `LookAtPoint` which describes the point in space the eye is looking at. The first two alone describe a lot but there is not enough to describe the full orientation, it might help to think of `Up` as a direction for a head tilt. The `FieldOfView` is the angle in degrees describing your range of view, think of it as projecting a cone out from the eye, anything in that cone can be seen.

The `NearPlaneDistance` and `FarPlaneDistance` together describe your depth range of view. If you measure the distance from the eye to any object, and that distance outside the near and far plane, you will not see that object. The near and far planes are fairly significant because they affect more than just if you can see an object, they affect how accurate the Depth Buffer in DirectX will be. So, avoid the urge to just set the far plane to 1 zillion so you see everything. The Depth Buffer has limited precision, so if there is too much space to cover, you will notice rendering anomalies.

A camera is no good if you don’t have any objects to look at. You need some models, but to have models, you first need a model collection. Model collections contain the models as well as lights.

```<ViewPort3D>
#Scene definition
<ViewPort3D.Models>
<Model3DCollection>
#models and Lights go in here
</Model3DCollection>
</ViewPort3D.Models>
</ViewPort3D>```

### Defining lights

A well lit scene always looks better. Without any lights, there is a default ambient light color but you really want to add some lights to create atmosphere. There are 4 basic types of lights.

• Ambient

An omnipresent light (requires no position) that will affect all objects and all sides of the objects equally.

`AmbientLight Color="#404040"/>`
• Directional

Another omnipresent light, this will affect all objects in a scene but will light the object based on its direction. Any part of an object facing towards the direction of the light will be fully lit, facing away will be unlit.

`<DirectionalLight Color="#C0C0C0" Direction="-0.5,-0.25,-1"/>`
• Point

Emits light from a single point equally in all directions. It requires a position and color and falloff values.

*not implemented.

• Spot

Emits light at a target; requires a position, orientation direction, a color, a inner and outer cone size, and some falloff values.

*not implemented.

### Creating objects

There are a few ways you can get an object into a scene.

• Import an X-file

Probably the easiest way assuming you have a .x file available. The downside to doing this is that the file must exist and be accessible to the viewer.

```<MeshPrimitive3D>
<MeshPrimitive3D.Mesh>
<Mesh3D XFile3DSource="TorusKnot.x"/>
</MeshPrimitive3D.Mesh>
</MeshPrimitive3D>```
• Define the mesh in XAML

This is a little more complicated, you have to define the mesh points, indices for triangles, and point normals. Unlike the X-file source, this doesn’t require any outside files.

```<MeshPrimitive3D>
<MeshPrimitive3D.Mesh>
<Mesh3D

Normals="0,-1,0 0,1,0 0,0,-1 1,0,0 0,0,1 -1,0,0 0,-1,0 0,1,0 ...
Positions="-5,0,-5 5,0,-5 -5,0,5 5,0,5 -5,10,-5 5,10,-5 ...

TriangleIndices="0,3,2 3,0,1 4,7,5 7,4,6 8,9,10 9,8,11 ...
/>
</MeshPrimitive3D.Mesh>
</MeshPrimitive3D>```

* Fortunately there is a tool on the Internet that can convert an X-file to a XAML definition: MSDN.

• Define a reference mesh

Similar to a XAML defined mesh, this is defined globally so it can be reused. Reusable definitions are defined in `Canvas.Resources` and can be used and reused in any Mesh3D. Note the `xmlns:def="Definition"` defined in the `Canvas` tag.

```<Canvas xmlns="http://schemas.microsoft.com/2003/xaml" xmlns:def="Definition">
<Canvas.Resources>
<Mesh3D def:Name="Box"

Normals="0,-1,0 0,1,0 0,0,-1 1,0,0 0,0,1 -1,0,0 0,-1,0 0,1,0 0,0,-1 ...
Positions="-5,0,-5 5,0,-5 -5,0,5 5,0,5 -5,10,-5 5,10,-5 -5,10,5 5,10,5 ...

TriangleIndices="0,3,2 3,0,1 4,7,5 7,4,6 8,9,10 9,8,11 1,7,12 7,1,13...
/>
</Canvas.Resources>…```

Used later in a model collection:

`<MeshPrimitive3D Mesh="{Box}"/>`

### Defining materials

If you have opted to define your mesh object in XAML or you linked to an X-file with no material information, your model will most likely end up black. Defining a solid color brush is fairly simple, it just needs a color.

```<MeshPrimitive3D.Material>
<BrushMaterial Brush="green"/>
</MeshPrimitive3D.Material>```

And here’s a more complete sample animating the solid brush color:

```<MeshPrimitive3D Mesh="{Box}">
<MeshPrimitive3D.Material>
<BrushMaterial>
<BrushMaterial.Brush>
<SolidColorBrush>
<SolidColorBrush.ColorAnimations>
<ColorAnimation

From="Green"

To="Red"

Begin="0.5"

Duration="1"

AutoReverse="True">
</SolidColorBrush.ColorAnimations>
</SolidColorBrush>
</BrushMaterial.Brush>
</BrushMaterial>
</MeshPrimitive3D.Material>```

Aside from solid colors, you might want to texture your object with a texture. You can specify an image file, the size, and the opacity.

```<BrushMaterial.Brush>
<ImageBrush

ImageSource="TextureName.jpg"

ViewPort="0 0 1024 1024"

Opacity="1.0"

/>
</BrushMaterial.Brush>```

### Hit testing

Hit testing on 3D objects is fairly easy to implement, at the moment only click is supported.

```…
<MeshPrimitive3D Click="OnClick">
<MeshPrimitive3D.Material>
…```

### Camera controllers

Camera controllers are handy if you want to be able to navigate a 3D scene manually. The downside here is, this is not an Avalon support tag and will not work in Longhorn.

There are two types of camera controllers:

• Free

This movement mode is unlimited and allows the user to move anywhere and in any direction.

• Left click drag to change heading.
• W,S to move forward and back.
• A,D to move left and right.
• Q,E to move up and down.
```<PerspectiveCamera

Position="-250,0,0"

LookAtPoint="0,0,0"

Up="0,1,0" NearPlaneDistance="1"

FarPlaneDistance="500"

FieldOfView="40"

CameraController="Free"/>
</ViewPort3D.Camera>```
• Targeted

A target camera allows the user to orbit around a particular point as well as move in and out. The keys are the same as the free camera mode but movement is limited to around the target.

```<PerspectiveCamera

Position="-250,0,0"

LookAtPoint="0,0,0"

Up="0,1,0" NearPlaneDistance="1"

FarPlaneDistance="500"

FieldOfView="40"

CameraController="Target"/>
</ViewPort3D.Camera>```

## Transforms

At this point, you should be able to make a scene with a camera, add some objects, and light them all up. If you’ve tried it, you may have noticed all your objects start at 0,0,0 and stay there. Transforms are going to allow to define how you want objects in the scene placed, oriented, sized, as well as animated.

Much like the models, transforms require a collection. All transforms must be listed within the collection, the collection itself is usually inside a mesh primitive.

```<MeshPrimitive3D Mesh="{Box}">
<MeshPrimitive3D.Transform>
<Transform3DCollection>
# transforms go here
</Transform3DCollection>
</MeshPrimitive3D.Transform>
</MeshPrimitive3D>```

### Translation

`<TranslateTransform3D Offset="50 0 0" />`

A translation transform is used to move an object around in the world. It basically adds the listed X,Y,Z values to every point in the mesh, essentially moving the object.

### Scale

`<ScaleTransform3D ScaleVector="2 2 2" ScaleCenter"0,0,0"/>`

A scale transform is used to make an object bigger or smaller by moving all points in a mesh in or out from the supplied center point. Each value in the `ScaleVector` will expand or contract the distance of any point from the center point on the associated axis. Applying a uniform scale (`ScaleVector`s X, Y and Z values are all the same) will proportionally change the size of the object.

For example, if you are scaling a cube that is centered around 0,0,0 and you scale it by 2,1,1, all points will move to twice the distance from the center on the X axis, essentially making the box twice as wide. Since the scale values multiply the distance, any scale value less than 1 will shrink the object on that axis. If the supplied `ScaleVector` for the last example was 0.5,1,1, the box would be half its original width.

If the supplied center point is not in the center of the mesh or it is not centered around 0,0,0, the scale may appear to stretch the mesh more in one direction than another. Additionally, if the center point is completely outside the model, scaling may appear to move the object.

### Rotation

`<RotateTransform3D Axis="0 1 0" Angle="45" Center="0,0,0"/>`

A rotation transform is used to rotate all points in a mesh around a particular point. A single rotation is limited to rotation on a single axis, but multiple rotations can be applied to achieve different results, which will be covered later. Like scaling, it will need a center point to rotate the points around by the angle specified in degrees. In the above XAML code, the axis is pointing up, so any rotation will make it to rotate much like a top. In this case, it will be 45 degrees, imagine a cube sitting on a desk that you turn 45 degrees.

If the center point you are rotating on is not centered, the object will appear to spin around that point.

### Defining Animation

*you should be familiar with XAML 2D animation tags before continuing.

When defining 3D animation, there are three main types of animated data: `Point3DAnimation`, `Vector3DAnimation` and `QuaternionAnimation`. Each of these must be wrapped in their appropriate collection tags, `Point3DAnimationCollection`, `Vector3DAnimationCollection` and `QuaternionAnimation`. Point3D and Vector3D are essentially the same, both are X,Y,X positions, except the difference is in the math terminology where Point represents a point in space whereas Vector represents a direction and/or magnitude.

That was the lowest level, each transform has one or more of these available to animate:

#### Translation:

Translate exposes only one animation container, `OffsetAnimations`.

```<TranslateTransform3D Offset="-1 0 0" >
<TranslateTransform3D.OffsetAnimations>
<Vector3DAnimationCollection>
<Vector3DAnimation From="-1,0,0" To="1,0,0"

Duration="3" RepeatCount="1" />
</Vector3DAnimationCollection>
</TranslateTransform3D.OffsetAnimations>
</TranslateTransform3D>```

#### Scale:

Scale exposes two animation containers: `ScaleVectorAnimations` and `ScaleCenterAnimations`.

```<ScaleTransform3D ScaleVector="1 1 1">
<ScaleTransform3D.ScaleVectorAnimations>
<Vector3DAnimationCollection>
<Vector3DAnimation From="1,1,1" To="2,2,2" Duration="10"/>
</Vector3DAnimationCollection>
</ScaleTransform3D.ScaleVectorAnimations>
<ScaleTransform3D. ScaleCenterAnimations >
<Point3DAnimationCollection>
<Point3DAnimation From="0,0,0" To="20,0,0" Duration="5"/>
</Point3DAnimationCollection>
</ScaleTransform3D. ScaleCenterAnimations >

</ScaleTransform3D>```

#### Rotation:

Rotation exposes two animation containers: `QuaternionRotationAnimations` and `CenterAnimations`. For some reason, the only way you can animate an object's rotation is by using a quaternion, which is most cumbersome if you are using a text editor. Until an editor is made, it would be useful to have a tool to help generate quaternions for animation. Explaining Quaternions goes way beyond the scope of this doc, hopefully some samples will help.

A couple of things to remember here… First is that, a quaternion will take the shortest route to a new orientation. If you want to re-orient it to 3590 on the X-axis, the quaternion will move -10 and not +3590. Also, there is no concept of winding, so if you want an object to rotate multiple times, you have to add multiple tags. The following sample will rotate an object completely around, twice:

```<Transform3DCollection>
<RotateTransform3D QuaternionRotation="0,0,0,1" Angle="60">
<RotateTransform3D.QuaternionRotationAnimations>
<QuaternionAnimationCollection>
<QuaternionAnimation

From="0,0,0,1" To="0,-1,0,0"

Begin="0"

Duration="3"

RepeatDuration="1"

AutoReverse="false" />
<QuaternionAnimation

From="0,-1,0,0"

To="0,0,0,-1"

Begin="3"

Duration="3"

RepeatDuration="1"

AutoReverse="false" />
</QuaternionAnimationCollection>
<QuaternionAnimationCollection>
<QuaternionAnimation

From="0,0,0,1" To="0,-1,0,0"

Begin="6"

Duration="3"

RepeatDuration="1"

AutoReverse="false" />
<QuaternionAnimation

From="0,-1,0,0"

To="0,0,0,-1"

Begin="9"

Duration="3"

RepeatDuration="1"

AutoReverse="false" />
</QuaternionAnimationCollection>
</RotateTransform3D.QuaternionRotationAnimations>
</RotateTransform3D>
</Transform3DCollection>```

### The Transform Collection

MSDN.

By now, you have probably noticed the `TransformCollection` tag quite a bit and not given it much thought, other than that it wraps up some transforms. That’s true, but when it comes to a transform collection, order is important. A translation, then a rotation, will have a different result than a rotation followed by a translation. If that doesn’t immediately make sense to you, I suggest a lot of experimentation to get a feel for how combining a transform has different affects to the outcome. To learn more about transform order and its effects, I would suggest this link. It’s 2D and programmer oriented, but there is an application you can play with to combine transforms in interesting ways.

Otherwise, here are a couple of examples of mixing transforms:

#### Example A:

The first image applies a rotate then translate, which rotates the object 45 degrees then moves it to the right (positive X). The second image moves the box, then rotates it. Since it's some distance from the rotation origin, it will spin 450 around the origin.

#### Example B:

The first image applies a translate, then scale, which will enlarge the box, then move it. The second image will move the box, then scale it using the origin at the center point. Notice how it moves the box further from the origin.

## 2D in 3D

### Explained

One way to really speed up XAML rendering is to render entirely in DirectX without using any GDI calls. Unfortunately, any third-party developer who does not have access to Windows source code has no chance of implementing XAML exactly like Avalon. There are alternative solutions however; one of them being to convert all would-be GDI drawings into triangles for rendering by the 3D pipeline. This process is referred to as triangulation or triangulating from now on. The process of triangulating 2D drawing calls can be complex, and in some cases, slightly slower than GDI. The payoff is when the 2D geometry that has been constructed is not physically changing but is animating a lot using standard transforms. This keeps the graphics process almost entirely on the video card, so the slowness of rendering in 2D (mainly waiting for the image(s) to get to the video card) is mostly avoided. The downside is that the triangulated representation may not look exactly the same as its 2D counterpart, but if speed is your goal, then this may not be an issue.

At the moment, the Mobiform fully DirectX rendering mode is 98% complete. While there are noticeable differences between the same GDI drawing and the DirectX drawing, you can already see the speed difference. In time, the triangulation and rendering should be almost indistinguishable from GDI drawing, and be tremendously faster.

### Effective usage

The key to getting the speed increase is to reduce the amount of time spent constructing the triangulated geometry from the GDI drawing. A hugely complex drawing can be slow, but once it’s triangulated, it can be extremely fast. Using transforms to move and rotate a drawing is preferable to animating the properties of a 2D XAML object. For example, you could create a sphere and animate its position, or you could wrap it in a `TransformCollection` and move it using a translation.

### ToDo

• As I mentioned above, using a transform to animate a 2D object helps speed, but might not always be practical. Some work has to be done to internally reduce triangulation when a XAML property has changed but doesn’t physically change the shape. Currently, anytime a property is changed, it is re-triangulated, this is especially slow on text.
• Anti-Aliasing (smooth edges). This is the greatest visible difference between GDI and DirectX rendering pipelines. GDI+ is extremely effective at anti-aliasing whereas DirectX is notoriously bad, especially on plain untextured geometry. Aside from being bad at it, good anti-aliasing in DirectX is not yet widely supported. There are a few options though, and with time and progress in this area, the rendering will soon look very much the same.
• Shapes with holes. Currently, any 2D shapes with holes in it (any text, butterfly.xaml sample) are considerably slowed down by the process of cutting out holes.
• Optimize triangulation. Although the general rule is to avoid this, it has to be done at some point. There’s always room to make it just a little faster.
• New text system. Since it is so slow to triangulate and it usually ends up re-triangulating the same characters repeatedly and entirely, new text system should be made to mimic GDI+ in DirectX.

## Conclusion

Hopefully, this has given you a good overview for 3D in XAML and you are ready to start experimenting in Mobiform and or Longhorn. Although the 3D API for Avalon is still early in its development (and will most likely change heavily on the next pre-release), the basics have been covered here, and should at the very least, give you a head start on the next release. It can only get better from here on in.

Jason Wylie. E-mail. Website.

A list of licenses authors might use can be found here

## Share

No Biography provided

## You may also be interested in...

 First Prev Next
 Translate it in C# LitsaMavro16-Jul-15 10:50 LitsaMavro 16-Jul-15 10:50
 Point3DAnimationUsingPath davidsackstein21-Jun-09 13:09 davidsackstein 21-Jun-09 13:09
 VB.Net code cristi2go29-Jun-08 7:04 cristi2go 29-Jun-08 7:04
 Can this be done in WPF anand_nair200521-Jun-07 4:41 anand_nair2005 21-Jun-07 4:41
 Great Article VickyC#24-Apr-06 16:17 VickyC# 24-Apr-06 16:17
 Re: Great Article Livid27-Apr-06 5:33 Livid 27-Apr-06 5:33
 Re: Great Article VickyC#27-Apr-06 17:13 VickyC# 27-Apr-06 17:13
 Re: Great Article barkest10-Jul-06 1:22 barkest 10-Jul-06 1:22
 Re: Great Article barkest10-Jul-06 1:24 barkest 10-Jul-06 1:24
 Ad for poor mobiform xaml engine? Frank Hileman1-Nov-04 3:58 Frank Hileman 1-Nov-04 3:58
 Re: Ad for poor mobiform xaml engine? Livid1-Nov-04 6:24 Livid 1-Nov-04 6:24
 Re: Ad for poor mobiform xaml engine? Frank Hileman1-Nov-04 7:29 Frank Hileman 1-Nov-04 7:29
 Re: Ad for poor mobiform xaml engine? Livid1-Nov-04 8:17 Livid 1-Nov-04 8:17
 Formatting Colin Angus Mackay21-Oct-04 3:01 Colin Angus Mackay 21-Oct-04 3:01
 Re: Formatting Livid21-Oct-04 9:08 Livid 21-Oct-04 9:08
 Re: Formatting Colin Angus Mackay21-Oct-04 11:30 Colin Angus Mackay 21-Oct-04 11:30
 Testing YoSilver20-Oct-04 18:59 YoSilver 20-Oct-04 18:59
 Re: Testing Livid21-Oct-04 9:09 Livid 21-Oct-04 9:09
 Re: Testing YoSilver21-Oct-04 19:07 YoSilver 21-Oct-04 19:07
 Pictures? seanwright20-Oct-04 10:18 seanwright 20-Oct-04 10:18
 Re: Pictures? Livid20-Oct-04 10:19 Livid 20-Oct-04 10:19
 Last Visit: 31-Dec-99 18:00     Last Update: 23-Jul-17 21:12 Refresh 1