Thursday, January 3, 2008

WPF 3D basics

WPF 3D Basics


Using WPF, you can build complex 3-D scenes out of simple markup. And any computer running Windows XP or Windows Vista can display the 3-D content, even when video card support is lacking.



Even though WPF's model for 3-D drawing is clear and consistent, creating rich 3-D interfaces is still difficult. This article covers the basics of 3D rendering and a few XAML and code snippets that is aimed at making your understanding better.



Rendering a 3-D drawing in WPF involves the following:

A viewport, which is the host for your 3D content
A 3-D object
A light source that illuminates part or all of your 3-D scene
A camera, which provides the vantage point from which you view the 3-D scene

The Viewport

If you want to work with 3-D content, you need a container that can host it. This container is the Viewport3D class, which is found in the System.Windows.Controls namespace. Viewport3D derives from FrameworkElement, and so it can be placed anywhere you'd place a normal element.

The 3D Objects

The viewport can host any 3-D object that derives from Visual3D (from the System. Windows. Media.Media3D namespace). In version 1.0, the WPF library lacks a collection of 3-D shape primitives. If you want a cube, a cylinder, a torus, and so on, you'll need to build it yourself.

Basic 3DGeometry



To build a 3-D object, you need to start by building the geometry. As you've already learned, there's just one class that fills this purpose: MeshGeometry3D.

a MeshGeometry3D object represents a mesh. Computers prefer to build 3-D drawings out of triangles. That's because a triangle is the simplest, most granular way to define a surface. Triangles are simple because every triangle is defined by just three points (the vertexes at the corner). Arcs and curved surfaces are obviously more complex. Triangles are granular because other straight-edged shapes (squares, rectangles, and more complex polygons) can be broken down into a collection of triangles. For better or worse, modern day graphics hardware and graphics programming is built on this core abstraction.

Properties Of MeshGeometry3D Class



Positions
Contains a collection of all the points that define the mesh.

TriangleIndices
Defines the triangles. Each entry in this collection represents a single triangle by referring to three points from the Positions collection.

Normals
Provides a vector for each vertex (each point in the Positions collection). This vector indicates how the point is angled for lighting calculations.
Texture Coordinates
Defines how a 2-D texture is mapped onto your 3-D object when you use a VisualBrush to paint it. The TextureCoordinates collection provides a 2-D point for each 3-D point in the Positions collection.

Xaml Example







This is a simple example which does not use the properties normals and texture co-ordinates and will be painted in solidbrush


Note: In 3D WPF 3D programming , you must list the points in a counterclockwise order around the Z axis.

Geometry Model and Surfaces
Geometry model is something in which you wrap the Geometry 3D mesh that we have create.
The GeometryModel3D class has three properties:
1. Geometry - The Geometry property takes the MeshGeometry3D that defines the shape of your 3-D object.

2. Material and
3.BackMaterial. Material and BackMaterial properties to define the surface out of which your shape is composed. The surface defines the color of the object, it defines how that material responds to light.

Material Classes

WPF library has the following material classes


Diffusive Material : Creates a flat, matte surface. It diffuses light evenly in all directions.
Emissive Material: Creates a glossy, highlighted look (think metal or glass). It reflects light back directly, like a mirror.
Specular Material: Creates a glowing look. It generates its own light (although this light does not reflect off other objects in the scene).
Material Group: combination of more than one material. The materials are then layered overtop of one another in the order they're added to the MaterialGroup

Light Sources and Lighting effects
In order to give a rich appearance to the 3D objects Wpf uses a Lighting Model.In Wpf lighting model Light effects are calculated for objects individually. Light reflected from one object will not reflect off another object. Similarly, an object will not cast a shadow on another object, no matter where it's placed.

Lighting is calculated at the vertices of each triangle and then interpolated over the surface of the triangle. (In other words, WPF determines the light strength at each corner and blends that to fill in the triangle.) As a result of this design, objects that have relatively few triangles may not be illuminated correctly. To achieve better lighting, you'll need to divide your shapes into hundreds or thousands of triangles.

Light Classes


DirectionalLight: Fills the scene with parallel rays of light traveling in the direction you specify.
AmbientLight: Fills the scene with scattered light.
PointLight: Radiates light in all directions, beginning at a single point in space.
SpotLight: Radiates light outward in a cone, starting from a single point.
Here's how you can define a white DirectionalLight:








In this example, the vector that determines the path of the light starts at the origin (0, 0, 0) and goes to
(1,1, 1).

Here's a viewport that includes the triangle and the light source:




















The Camera effect


Before a 3-D scene can be rendered, you need to place a camera at the correct position and orient it in the correct direction. You do this by setting the Viewport3D.Camera property with a Camera object.
In essence, the camera determines how a 3-D scene is projected onto the 2-D surface of a Viewport. WPF includes three camera classes: the commonly used PerspectiveCamera and the more exotic OrthographicCamera and MatrixCamera. The PerspectiveCamera renders the scene so that objects that are farther away appear smaller. This is the behavior that most people expect in a 3-D scene. The OrthographicCamera flattens 3-D objects so that the exact scale is preserved, no matter where a shape is positioned. This looks a bit odd, but it's useful for some types of visualization tools. For example, technical drawing applications often rely on this type of view.

Choosing the right camera is relatively easy, but placing and configuring it is a bit trickier. The first detail is to specify a point in 3-D space where the camera will be positioned by setting its Position property. The second step is to set a 3-D vector in the LookDirection property that indicates how the camera is oriented. In a typical 3-D scene, you'll place the camera slightly off to one corner using the Position property, and then tilt it to survey the view using the LookDirection property.



Note
The position of the camera determines how large your scene appears in the viewport. The closer the camera, the larger the scale. In addition, the viewport is stretched to fit its container and the content inside is scaled accordingly. For example, if you create a viewport that fills a window, you can expand or shrink your scene by resizing the window.
You need to set the Position and LookDirection properties in concert. If you use Position to offset the camera but fail to compensate by turning the camera back in the right direction using LookDirection, you won't see the content you've created in your 3-D scene. To make sure you're correctly oriented, pick a point that you want to see square on from your camera. You can then calculate the look direction using this formula:
CameraLookDirection = CenterPointOfInterest - CameraPosition
In the triangle example, the camera is placed in the top-left corner using a position of (-2, 2, 2). Assuming you want to focus on the origin point (0, 0, 0), which falls in the middle of the triangle's bottom edge, you would use this look direction:
CameraLookDirection = (0, 0, 0) - (-2, 2, 2)
= (2, -2, -2)
This is equivalent to the normalized vector (1, -1, -1) because the direction it describes is the same. As with the Direction property of a DirectionalLight, it's the direction of the vector that's important, not its magnitude.

Example of a simple perspective camera effect
...





















Here's a MeshGeometry3D that creates a cube:















First, the Positions collection defines the corners of the cube. It begins with the four points in the back (where z = 0) and then adds the four in the front (where z = 10). The Triangle-Indices property maps these points to triangles. For example, the first entry in the collection is 0, 2, 1. It creates a triangle from the first point (0, 0, 0) to the second point (0, 0, 10) to the third point (0, 10, 0). This is one of the triangles required for the back side of the square. (The index 1, 2, 3 fills in the other backside triangle.)


Remember, when defining triangles, you must define them in counterclockwise order to make their front side face forward. However, the cube appears to violate that rule. The squares on the front side are defined in counterclockwise order (see the index 4, 5, 6 and 7, 6, 5, for instance), but those on the back side are defined in clockwise order, including the index 0, 2, 1 and 1, 2, 3. This is because the back side of the cube must have its triangle facing backward. To better visualize this, imagine rotating the cube around the Y axis so that the back side is facing forward. Now, the backward-facing triangles will be facing forward, making them completely visible, which is the behavior you want.

Texture Mapping
Texture mapping is giving a texture to the surface of your 3D object in the sense instead of the surface having a solid color you could put a image or visual to the surface of your 3D object
An Example of a cube mesh mapping a texture co-ordinate



























3D Transforms

As with 2-D content, the most powerful and flexible way to change an aspect of your 3-D scene is to use transforms. This is particularly the case with 3-D, as the classes you work with are relatively low-level. For example, if you want to scale a sphere, you need to construct the appropriate geometry and use the ScaleTransform3D to animate it. If you had a 3-D sphere primitive to work with, this might not be necessary because you might be able to animate a higher-level property like Radius.
Transforms are obviously the answer to creating dynamic effects. However, before you can use transforms, you need to decide how you want to apply them. There are several possible approaches:
Modify a transform that's applied to your Model3D. This allows you to change a single aspect of a single 3-D object. You can also use this technique on a Model3DGroup, as it derives from Model3D.
Modify a transform that's applied to your ModelVisual3D. This allows you to change an entire scene.
Modify a transform that's applied to your light. This allows you to change the lighting of your scene (for example, to create a "sunrise" effect).
Modify a transform that's applied to your camera. This allows you to move the camera through your scene.
Transforms are so useful in 3-D drawing that it's a good idea to get into the habit of using a Transform3DGroup whenever you need a transform. That way, you can add additional transforms afterward without being forced to change your animation code. The ZAM 3D modeling program always adds a set of four placeholder transforms to every Model3DGroup, so that the object represented by that group can be manipulated in various ways:


















Notice that this set of transforms includes two TranslateTransform3D objects. That's because translating an object before it's been rotated produces a different result than translating it after it's been rotated, and you may want to use both effects.


Another handy technique is to name your transform objects in XAML using the x:Name attribute. Even though the transform objects don't have a name property, this creates a private member variable you can use to access them more easily without being forced to dig through a deep hierarchy of objects. This is particularly important because complex 3-D scenes often have multiple layers of Model3DGroup objects, as described earlier. Walking down this element tree from the top-level ModelVisual3D is awkward and error-prone.





Rotations



To get a taste of the ways you might use transforms, consider the following markup. It applies a RotateTransform3D, which allows you to rotate a 3-D object around an axis you specify. In this case, the axis of rotation is set to line up exactly with the Y axis in your coordinate system:

















Using this named rotation, you can create a databound Slider that allows the user to spin the cube around its axis:












Just as easily, you can use this rotation in an animation. Here's an animation that spins a torus (a 3-D ring) simultaneously along two different axes. It all starts when a button is clicked:


























Reference: Pro Wpf:Windows Presentation Foundation in .NET 3.0,by Matthew MacDonald,Apress 2007,MSDN


No comments: