Home
Search
 
What's New
Index
Books
Links
Q & A
Newsletter
Banners
 
Feedback
Tip Jar
 
C# Helper...
 
XML RSS Feed
Follow VBHelper on Twitter
 
 
 
MSDN Visual Basic Community
 
 
 
 
 
TitleMake a continuously spinning cube by using XAML code in Visual Basic 2008
DescriptionThis example shows how to make a continuously spinning cube by using XAML code in Visual Basic 2008.
KeywordsVisual Basic 2008, VB 2008, XAML, cube, rotate, spin, VB.NET
CategoriesVB.NET, Graphics, WPF
 
The following text describes key pieces of the XAML code. Download the example and follow along.

The Window.Resources section defines a Storyboard that rotates the GasketModel object to be defined later. It rotates the model 180 degrees after 2 seconds, 259 degrees after 4 seconds, and then repeats forever.

 
<Storyboard x:Key="RotateModel">
    <Rotation3DAnimationUsingKeyFrames BeginTime="00:00:00" RepeatBehavior="Forever"
     Storyboard.TargetName="GasketModel"
     Storyboard.TargetProperty="(Model3D.Transform).(Transform3DGroup.Children)[0].(RotateTransform3D.Rotation)">
        <SplineRotation3DKeyFrame KeyTime="00:00:02">
            <SplineRotation3DKeyFrame.Value>
                <AxisAngleRotation3D Angle="180" Axis="0,1,0"/>
            </SplineRotation3DKeyFrame.Value>
        </SplineRotation3DKeyFrame>
        <SplineRotation3DKeyFrame KeyTime="00:00:04">
            <SplineRotation3DKeyFrame.Value>
                <AxisAngleRotation3D Angle="359" Axis="0,1,0"/>
            </SplineRotation3DKeyFrame.Value>
        </SplineRotation3DKeyFrame>
    </Rotation3DAnimationUsingKeyFrames>
</Storyboard>
 
The Window.Triggers section defines an EventTrigger to start the Storyboard when the window loads.
 
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
    <BeginStoryboard Storyboard="{StaticResource RotateModel}"/>
</EventTrigger>
 
Next the code creates a Viewport3D to hold all of the three-dimensional pieces. It contains a Camera object that determines where the viewpoint is and the direction it is looking.
 
<Viewport3D.Camera>
    <PerspectiveCamera
        Position="2, 2, 4"
        LookDirection="-2, -2, -4"
        UpDirection="0, 1, 0"
        FieldOfView="60"/>
</Viewport3D.Camera>
 
The Viewport's Resources section defines a material that will be used by most of the cube's sides.
 
<Viewport3D.Resources>
    <!-- The material used by most surfaces. -->
    <DiffuseMaterial x:Key="matGreen" Brush="LightGreen"/>
</Viewport3D.Resources>
 
Next the code defines a ModelVisual3D to hold the three-dimensional objects. This object's Contents property holds a Model3DGroup that holds the scene's lights and "physical" objects. The following code fragment shows how this object hierarchy begins. It defines a transformation that the Storyboard can rotate.

It also defines the scene's lights. When much of the scene uses the same material (as in the case here), it can be fairly tricky to define lights that give every part of the scene slightly different colors. If you use different textures (colors, bitmaps, etc.) for the surfaces, then you may only need ambient lighting.

 
<ModelVisual3D>
    <ModelVisual3D.Content>
        <Model3DGroup x:Name="GasketModel">
            <Model3DGroup.Transform>
                <Transform3DGroup>
                    <RotateTransform3D />
                </Transform3DGroup>
            </Model3DGroup.Transform>

            <!-- Lights -->
            <AmbientLight Color="#FF404040"/>
            <DirectionalLight Color="Gray" Direction="-1,-2,0" />
            <DirectionalLight Color="Gray" Direction="0,0,-1" />
            <DirectionalLight Color="Gray" Direction="0,0,2" />
            <DirectionalLight Color="#FF202020" Direction="1,0,0" />
 
The following code shows how the program defines the top of the cube. The GeometryModel3D object's Material makes the top use the light green material defined earlier.

The MeshGeometry3D object represents a three-dimensional object. Its Positions attribute gives the coordinates of the top's corners. The TriangleIndices attribute tells which triples of points should be connected to make triangles in the scene.

 
<!-- Top -->
<GeometryModel3D Material="{StaticResource matGreen}">
    <GeometryModel3D.Geometry>
        <MeshGeometry3D
             Positions="-1,1,1 1,1,1 1,1,-1 -1,1,-1"
             TriangleIndices="0,1,3 1,2,3"/>
    </GeometryModel3D.Geometry>
</GeometryModel3D>
 
Most of the cube's other faces are defined similarly. The front face, however, displays a bitmap rather than a simple color so it is different.

This object uses a GrometryModel3D and MeshGeometry3D similar to the previous faces. It sets the MeshGeometry3D's Positions and TriangleIndices properties as before (although it uses an element syntax instead of an attribute syntax).

The TextureCoordinates property tells which points in the Positions list match up with different parts of the bitmap. In texture coordinates, (0, 0) is the upper left corner with X increasing to the right and Y increasing down.

The GeometryModel3D.Material defines the object's material. This example uses an ImageBrush that displays the bitmap. You can also use a VisualBrush that would display something drawn with WPF such as a Button or TextBox.

 
<!-- Front -->
<GeometryModel3D>
    <GeometryModel3D.Geometry>
        <MeshGeometry3D>
            <MeshGeometry3D.Positions>
                <Point3D X="-1" Y="1" Z="1"/>
                <Point3D X="-1" Y="-1" Z="1"/>
                <Point3D X="1" Y="-1" Z="1"/>
                <Point3D X="1" Y="1" Z="1"/>
            </MeshGeometry3D.Positions>
            <MeshGeometry3D.TextureCoordinates>
                <Point X="0" Y="0"/>
                <Point X="0" Y="1"/>
                <Point X="1" Y="1"/>
                <Point X="1" Y="0"/>
            </MeshGeometry3D.TextureCoordinates>
            <MeshGeometry3D.TriangleIndices>
                <Int32Collection>
                        0,1,2 2,3,0
                </Int32Collection>
            </MeshGeometry3D.TriangleIndices>
        </MeshGeometry3D>
    </GeometryModel3D.Geometry>

    <GeometryModel3D.Material>
        <MaterialGroup>
            <DiffuseMaterial>
                <DiffuseMaterial.Brush>
                    <ImageBrush ImageSource="Rod.bmp"/>
                </DiffuseMaterial.Brush>
            </DiffuseMaterial>
        </MaterialGroup>
    </GeometryModel3D.Material>
</GeometryModel3D>
 
Those are the key elements. Download the example and experiment with it.

Note that this example builds each face as a separate GeometryModel3D object. You could make them all use a single object but that can be tricky.

The biggest problem is that faces could NOT share points defined in the Positions property. When two surfaces share a point, Direct3D (which does the drawing) averages the surface normals at that point to make the two surfaces join smoothly. This works well for spheres and other shapes where the tiles making up the shape should blend smoothly but it removes the sharp edges between shapes such as cubes where the faces should not join smoothly.

To use a single object for several faces, you would need to repeat the points in the Positions property several times, once for each face that used it. You could do that (and it might even give you better performance) but it would be more confusing.

 
 
Copyright © 1997-2010 Rocky Mountain Computer Consulting, Inc.   All rights reserved.
  Updated