Perspective camera animation on a cube in WPF 3D

I have started WPF 3D at my work. Actually, i wanted  to make roll animation effect using WPF 3D. After some R&D, I came up with roll animation using 2D animation, which I described in my previous blog post. At first, I tried to make roll animation using perspective camera rotation.  For that, I have made a sample program, which I am discussing in this blog post. In this sample program, a 3D cube rotates along the y-axis. The animation looks like the following:

fun_373AEFA5

To rotate a 3D figure, you have to change the projection point. As camera is used for projection in WPF 3D, here a camera is being moved around the 3D figure to achieve rotate animation in y-direction.

How are images painted on cube surface?

You can make an image brush for any image and a visual brush from any visual. We have no special brushes for 3D graphics and we have to use two-dimensional brushes to paint the surfaces of three-dimensional figures. Material is created from brush. Texture coordinates are used to map which part of the material shows up on which part of the surfaces of three-dimensional figures.

Each GeometryModel3D consists of one MeshGeometry3D and one object of type Material, so we can use only one brush for one MeshGeometry3D figure. To use different brushes for different faces of cube, i have splited the figure into multiple GeometryModel3D objects.

The used c# code for this animation is in the following

   1: public partial class Window1 : Window
   2:   {
   3:       DispatcherTimer _timer = null;
   4:       PerspectiveCamera _perspectiveCamera = null;
   5:       double _angle = 0;        
   6:  
   7:       public Window1()
   8:       {
   9:           this.InitializeComponent();
  10:           this.Loaded += new RoutedEventHandler(Window1_Loaded);
  11:       }
  12:  
  13:       void Window1_Loaded(object sender, RoutedEventArgs e)
  14:       {
  15:           GenerateViewPort();
  16:       }       
  17:  
  18:       private void GenerateViewPort()
  19:       {
  20:           MakeCamera();
  21:  
  22:           Viewport3D Viewport3D1 = new Viewport3D();
  23:           Viewport3D1.Camera = _perspectiveCamera;
  24:           grdAniContainer.Children.Add(Viewport3D1);
  25:           Viewport3D1.Loaded += new RoutedEventHandler(Viewport3D1_Loaded);
  26:  
  27:           ModelVisual3D ModelVisual3D1 = new ModelVisual3D();
  28:           Viewport3D1.Children.Add(ModelVisual3D1);
  29:  
  30:  
  31:           Model3DGroup Model3DGroup1 = new Model3DGroup();
  32:           ModelVisual3D1.Content = Model3DGroup1;
  33:  
  34:           AmbientLight AmbientLight1 = new AmbientLight();
  35:           AmbientLight1.Color = Colors.Gray;
  36:           Model3DGroup1.Children.Add(AmbientLight1);
  37:  
  38:           DirectionalLight DirectionalLight1 = new DirectionalLight();
  39:           DirectionalLight1.Color = Colors.Gray;
  40:           DirectionalLight1.Direction = ((Vector3D)new Vector3DConverter().ConvertFromString("-1,-3,-2"));
  41:           Model3DGroup1.Children.Add(DirectionalLight1);
  42:  
  43:           DirectionalLight1 = new DirectionalLight();
  44:           DirectionalLight1.Color = Colors.Gray;
  45:           DirectionalLight1.Direction = ((Vector3D)new Vector3DConverter().ConvertFromString("1,-2,3"));
  46:           Model3DGroup1.Children.Add(DirectionalLight1);
  47:  
  48:           Model3DGroup Model3DGroup2 = new Model3DGroup();
  49:           Model3DGroup1.Children.Add(Model3DGroup2);
  50:  
  51:           GeometryModel3D GeometryModel3D1 = new GeometryModel3D();
  52:           Model3DGroup2.Children.Add(GeometryModel3D1);
  53:  
  54:  
  55:           MeshGeometry3D MeshGeometry3D1 = new MeshGeometry3D();
  56:           MeshGeometry3D1.Positions = ((Point3DCollection)new Point3DCollectionConverter().ConvertFromString("-1,-1,-1 1,-1,-1 1,-1,1 -1,-1,1"));
  57:           MeshGeometry3D1.TriangleIndices = ((Int32Collection)new Int32CollectionConverter().ConvertFromString("0,1,2 0,2,3"));
  58:           MeshGeometry3D1.TextureCoordinates = ((PointCollection)new PointCollectionConverter().ConvertFromString("0,0 0,1 1,1 1,0"));
  59:           GeometryModel3D1.Geometry = MeshGeometry3D1;
  60:  
  61:          
  62:           DiffuseMaterial DiffuseMaterial1 = new DiffuseMaterial();
  63:           GeometryModel3D1.Material = DiffuseMaterial1;
  64:  
  65:  
  66:           ImageBrush ImageBrush1 = new ImageBrush();
  67:           ImageBrush1.ImageSource = loadBitmap(Fun.Resource1.DSC06460);
  68:           DiffuseMaterial1.Brush = ImageBrush1;
  69:  
  70:           GeometryModel3D GeometryModel3D2 = new GeometryModel3D();
  71:           Model3DGroup2.Children.Add(GeometryModel3D2);
  72:  
  73:  
  74:           MeshGeometry3D1 = new MeshGeometry3D();
  75:           MeshGeometry3D1.Positions = ((Point3DCollection)new Point3DCollectionConverter().ConvertFromString("1,1,1 1,1,-1 -1,1,-1 -1,1,1"));
  76:           MeshGeometry3D1.TriangleIndices = ((Int32Collection)new Int32CollectionConverter().ConvertFromString("0,1,2 0,2,3"));
  77:           MeshGeometry3D1.TextureCoordinates = ((PointCollection)new PointCollectionConverter().ConvertFromString("0,0 0,1 1,1 1,0"));
  78:           GeometryModel3D2.Geometry = MeshGeometry3D1;
  79:  
  80:  
  81:           DiffuseMaterial DiffuseMaterial2 = new DiffuseMaterial();
  82:           GeometryModel3D2.Material = DiffuseMaterial2;
  83:  
  84:  
  85:           ImageBrush1 = new ImageBrush();
  86:           ImageBrush1.ImageSource = loadBitmap(Fun.Resource1.DSC06461);
  87:           DiffuseMaterial2.Brush = ImageBrush1;
  88:  
  89:           GeometryModel3D GeometryModel3D3 = new GeometryModel3D();
  90:           Model3DGroup2.Children.Add(GeometryModel3D3);
  91:  
  92:  
  93:           MeshGeometry3D1 = new MeshGeometry3D();
  94:           MeshGeometry3D1.Positions = ((Point3DCollection)new Point3DCollectionConverter().ConvertFromString("-1,1,-1 -1,-1,-1 -1,-1,1 -1,1,1"));
  95:           MeshGeometry3D1.TriangleIndices = ((Int32Collection)new Int32CollectionConverter().ConvertFromString("0,1,2 0,2,3"));
  96:           MeshGeometry3D1.TextureCoordinates = ((PointCollection)new PointCollectionConverter().ConvertFromString("0,0 0,1 1,1 1,0"));
  97:           GeometryModel3D3.Geometry = MeshGeometry3D1;
  98:  
  99:  
 100:           DiffuseMaterial DiffuseMaterial3 = new DiffuseMaterial();
 101:           GeometryModel3D3.Material = DiffuseMaterial3;
 102:  
 103:  
 104:           ImageBrush1 = new ImageBrush();
 105:           ImageBrush1.ImageSource = loadBitmap(Fun.Resource1.DSC06462);
 106:           DiffuseMaterial3.Brush = ImageBrush1;
 107:  
 108:           GeometryModel3D GeometryModel3D4 = new GeometryModel3D();
 109:           Model3DGroup2.Children.Add(GeometryModel3D4);
 110:  
 111:  
 112:           MeshGeometry3D1 = new MeshGeometry3D();
 113:           MeshGeometry3D1.Positions = ((Point3DCollection)new Point3DCollectionConverter().ConvertFromString("1,1,1 1,-1,1 1,-1,-1 1,1,-1"));
 114:           MeshGeometry3D1.TriangleIndices = ((Int32Collection)new Int32CollectionConverter().ConvertFromString("0,1,2 0,2,3"));
 115:           MeshGeometry3D1.TextureCoordinates = ((PointCollection)new PointCollectionConverter().ConvertFromString("0,0 0,1 1,1 1,0"));
 116:           GeometryModel3D4.Geometry = MeshGeometry3D1;
 117:  
 118:  
 119:           DiffuseMaterial DiffuseMaterial4 = new DiffuseMaterial();
 120:           GeometryModel3D4.Material = DiffuseMaterial4;
 121:  
 122:  
 123:           ImageBrush1 = new ImageBrush();
 124:           ImageBrush1.ImageSource = loadBitmap(Fun.Resource1.DSC06463);
 125:           DiffuseMaterial4.Brush = ImageBrush1;
 126:  
 127:           GeometryModel3D GeometryModel3D5 = new GeometryModel3D();
 128:           Model3DGroup2.Children.Add(GeometryModel3D5);
 129:  
 130:  
 131:           MeshGeometry3D1 = new MeshGeometry3D();
 132:           MeshGeometry3D1.Positions = ((Point3DCollection)new Point3DCollectionConverter().ConvertFromString("1,1,-1 1,-1,-1 -1,-1,-1 -1,1,-1"));
 133:           MeshGeometry3D1.TriangleIndices = ((Int32Collection)new Int32CollectionConverter().ConvertFromString("0,1,2 0,2,3"));
 134:           MeshGeometry3D1.TextureCoordinates = ((PointCollection)new PointCollectionConverter().ConvertFromString("0,0 0,1 1,1 1,0"));
 135:           GeometryModel3D5.Geometry = MeshGeometry3D1;
 136:  
 137:  
 138:           DiffuseMaterial DiffuseMaterial5 = new DiffuseMaterial();
 139:           GeometryModel3D5.Material = DiffuseMaterial5;
 140:  
 141:  
 142:           ImageBrush1 = new ImageBrush();
 143:           ImageBrush1.ImageSource = loadBitmap(Fun.Resource1.DSC06460);
 144:           DiffuseMaterial5.Brush = ImageBrush1;
 145:  
 146:           GeometryModel3D GeometryModel3D6 = new GeometryModel3D();
 147:           Model3DGroup2.Children.Add(GeometryModel3D6);
 148:  
 149:  
 150:           MeshGeometry3D1 = new MeshGeometry3D();
 151:           MeshGeometry3D1.Positions = ((Point3DCollection)new Point3DCollectionConverter().ConvertFromString("-1,1,1 -1,-1,1 1,-1,1 1,1,1"));
 152:           MeshGeometry3D1.TriangleIndices = ((Int32Collection)new Int32CollectionConverter().ConvertFromString("0,1,2 0,2,3"));
 153:           MeshGeometry3D1.TextureCoordinates = ((PointCollection)new PointCollectionConverter().ConvertFromString("0,0 0,1 1,1 1,0"));
 154:           GeometryModel3D6.Geometry = MeshGeometry3D1;
 155:  
 156:           DiffuseMaterial DiffuseMaterial6 = new DiffuseMaterial();
 157:           GeometryModel3D6.Material = DiffuseMaterial6;           
 158:  
 159:           VisualBrush VisualBrush1 = new VisualBrush();
 160:           DiffuseMaterial6.Brush = VisualBrush1;
 161:           Label Label1 = new Label();
 162:           Label1.Content = "Razan";
 163:           Label1.Foreground = new SolidColorBrush(Colors.Orchid);
 164:           Label1.Background = GetRectangleDrawingBrush();
 165:           VisualBrush1.Visual = Label1;            
 166:       }
 167:  
 168:       private void MakeCamera()
 169:       {
 170:           Transform3DGroup transform3DGroup = new Transform3DGroup();
 171:           RotateTransform3D rotateTransform3D_1 = new RotateTransform3D();
 172:           AxisAngleRotation3D axisAngleRotation3D_1 = new AxisAngleRotation3D(new Vector3D(0, 1, 0), 0);
 173:  
 174:  
 175:           transform3DGroup.Children.Add(rotateTransform3D_1);
 176:  
 177:  
 178:           _perspectiveCamera = new PerspectiveCamera();
 179:           _perspectiveCamera.Position = new Point3D(0, 0, 5);
 180:           _perspectiveCamera.LookDirection = new Vector3D(0, 0, -5);
 181:           _perspectiveCamera.UpDirection = new Vector3D(0, 1, 0);
 182:           _perspectiveCamera.FieldOfView = 45;
 183:           _perspectiveCamera.Transform = transform3DGroup;
 184:       }
 185:       private DrawingBrush GetRectangleDrawingBrush()
 186:       {         
 187:  
 188:           DrawingBrush DrawingBrush1 = new DrawingBrush();
 189:           DrawingBrush1.Viewport = ((Rect)new RectConverter().ConvertFromString("0,0,0.25,0.25"));
 190:           DrawingBrush1.TileMode = TileMode.Tile;
 191:            
 192:  
 193:           DrawingGroup DrawingGroup1 = new DrawingGroup();
 194:           DrawingBrush1.Drawing = DrawingGroup1;
 195:  
 196:           GeometryDrawing GeometryDrawing1 = new GeometryDrawing();
 197:           GeometryDrawing1.Brush = ((Brush)new BrushConverter().ConvertFromString("White"));
 198:           DrawingGroup1.Children.Add(GeometryDrawing1);
 199:  
 200:  
 201:           RectangleGeometry RectangleGeometry1 = new RectangleGeometry();
 202:           RectangleGeometry1.Rect = ((Rect)new RectConverter().ConvertFromString("0,0,100,100"));
 203:           GeometryDrawing1.Geometry = RectangleGeometry1;
 204:  
 205:           GeometryDrawing GeometryDrawing2 = new GeometryDrawing();
 206:           DrawingGroup1.Children.Add(GeometryDrawing2);
 207:  
 208:  
 209:           GeometryGroup GeometryGroup1 = new GeometryGroup();
 210:           GeometryDrawing2.Geometry = GeometryGroup1;
 211:  
 212:           RectangleGeometry1 = new RectangleGeometry();
 213:           RectangleGeometry1.Rect = ((Rect)new RectConverter().ConvertFromString("0,0,50,50"));
 214:           GeometryGroup1.Children.Add(RectangleGeometry1);
 215:  
 216:           RectangleGeometry1 = new RectangleGeometry();
 217:           RectangleGeometry1.Rect = ((Rect)new RectConverter().ConvertFromString("50,50,50,50"));
 218:           GeometryGroup1.Children.Add(RectangleGeometry1);
 219:  
 220:  
 221:           LinearGradientBrush LinearGradientBrush1 = new LinearGradientBrush();
 222:           GeometryDrawing2.Brush = LinearGradientBrush1;
 223:  
 224:           GradientStop GradientStop1 = new GradientStop();
 225:           GradientStop1.Offset = 0.0;
 226:           GradientStop1.Color = Colors.Black; 
 227:           LinearGradientBrush1.GradientStops.Add(GradientStop1);
 228:  
 229:           GradientStop1 = new GradientStop();
 230:           GradientStop1.Offset = 1.0;
 231:           GradientStop1.Color = Colors.Gray; 
 232:           LinearGradientBrush1.GradientStops.Add(GradientStop1);
 233:  
 234:           return DrawingBrush1;
 235:  
 236:       }
 237:  
 238:  
 239:       void Viewport3D1_Loaded(object sender, RoutedEventArgs e)
 240:       {
 241:           _timer = new DispatcherTimer();
 242:           _timer.Interval = TimeSpan.FromSeconds(.25);
 243:           _timer.Tick += new EventHandler(_timer_Tick);
 244:           _timer.IsEnabled = true;
 245:       }
 246:       
 247:       void _timer_Tick(object sender, EventArgs e)
 248:       {
 249:           Transform3DGroup transform3DGroup = new Transform3DGroup();
 250:           RotateTransform3D rotateTransform3D_1 = new RotateTransform3D();
 251:           AxisAngleRotation3D axisAngleRotation3D_1 = new AxisAngleRotation3D(new Vector3D(0, 1, 0), _angle );
 252:           rotateTransform3D_1.Rotation = axisAngleRotation3D_1;          
 253:           transform3DGroup.Children.Add(rotateTransform3D_1);             
 254:           _perspectiveCamera.Transform = transform3DGroup;
 255:           _angle = _angle + 2;
 256:       }
 257:       public static BitmapSource loadBitmap(System.Drawing.Bitmap source)
 258:       {
 259:           return System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(source.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty,
 260:               System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
 261:       }
 262:   }

How is this animation achieved?

Here we have used perspective camera for projection. To make this animation, I have rotated perspective camera in y direction. As we know second point of vector 3D indicates y coordinate. So AxisAngleRotation3D(new Vector3D(0, 1, 0), _angle ) directs to rotate the 3D object(here cube) to rotate _angle degree in y-axis. Here at each tick event, we have incremented the value of _angle, so it rotates in y direction. If you would like to rotate in x direction you can use AxisAngleRotation3D(new Vector3D(1, 0, 0), _angle ), then it will rotate in x-direction. Here visual brush is used to paint label UIelement, which contains "Razan".

The used XAML for this is in the following:

   1: <Window
   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:     x:Class="Fun.Window1"
   5:     x:Name="Window"
   6:     Title="Fun"
   7:     Height="400" Width="400">
   8:     <Grid Name="grdAniContainer"></Grid>
   9: </Window>

You can download the sample code from here. Hope this will save some of your time.

1 Comment

Comments have been disabled for this content.