最近在看一些关于wpf 3d的效果,研究了一些代码特效,现在和广大博友共享一下.
首先用到的是MeshGeometry3D,msdn上介绍:用于生成三维形状的三角形基元。
主要有4个依赖属性:NormalsProperty,PositionsProperty,TextureCoordinatesProperty,
TriangleIndicesProperty。4中属性具体含义大家可以直接参考msdn上。
具体代码如下:
MeshGeometry3D meshGeometry3D = new MeshGeometry3D(); Point3DCollection positions = new Point3DCollection(); positions.Add(new Point3D(0, 0, 1)); positions.Add(new Point3D(0, 0, 0)); positions.Add(new Point3D(1, 0, 0)); positions.Add(new Point3D(1, 0, 1)); positions.Add(new Point3D(0, 1, 1)); positions.Add(new Point3D(0, 1, 0)); positions.Add(new Point3D(1, 1, 0)); positions.Add(new Point3D(1, 1, 1)); positions.Freeze(); Int32Collection triangleIndices = new Int32Collection(); triangleIndices.Add(0); triangleIndices.Add(1); triangleIndices.Add(2); triangleIndices.Add(2); triangleIndices.Add(3); triangleIndices.Add(0); triangleIndices.Add(4); triangleIndices.Add(7); triangleIndices.Add(6); triangleIndices.Add(6); triangleIndices.Add(5); triangleIndices.Add(4); triangleIndices.Add(0); triangleIndices.Add(3); triangleIndices.Add(7); triangleIndices.Add(7); triangleIndices.Add(4); triangleIndices.Add(0); triangleIndices.Add(1); triangleIndices.Add(5); triangleIndices.Add(6); triangleIndices.Add(6); triangleIndices.Add(2); triangleIndices.Add(1); triangleIndices.Add(3); triangleIndices.Add(2); triangleIndices.Add(6); triangleIndices.Add(6); triangleIndices.Add(7); triangleIndices.Add(3); triangleIndices.Add(0); triangleIndices.Add(4); triangleIndices.Add(5); triangleIndices.Add(5); triangleIndices.Add(7); triangleIndices.Add(0); triangleIndices.Freeze(); // finally set the data meshGeometry3D.TriangleIndices = triangleIndices; meshGeometry3D.Positions = positions;
然后定义GeometryModel3D,代码:
// create the geometry model GeometryModel3D geom3D = new GeometryModel3D(); geom3D.Geometry = meshGeometry3D; Color color = WpfUtil.HsbToRgb(index / (float)count, .9f, 1f); SolidColorBrush solidColorBrush = new SolidColorBrush(color); solidColorBrush.Freeze(); geom3D.Material = new DiffuseMaterial(solidColorBrush);
然后将GeometryModel3D归入Model3DGroup中,代码:
Model3DGroup group = new Model3DGroup(); group.Children.Add(geom3D); ModelVisual3D model = new ModelVisual3D(); model.Content = group; DirectionalLight dl = new DirectionalLight(); dl.Color = Colors.White; dl.Direction = new Vector3D(-1, -1, -3); group.Children.Add(dl); AmbientLight al = new AmbientLight(); al.Color = (Color)ColorConverter.ConvertFromString("#555555"); group.Children.Add(al);
xaml如下:
<ModelVisual3D> <ModelVisual3D.Content> <Model3DGroup> <DirectionalLight Direction="1 0 -2" Color="White"/> <GeometryModel3D> <GeometryModel3D.Geometry> <!--Positions获取或设置 meshgeometry3d 的顶点位置的集合 TextureCoordinates获取或设置 meshgeometry3d 的纹理坐标的集合 TriangleIndices获取或设置 meshgeometry3d 的三角形索引的集合--> <MeshGeometry3D Positions="-1 1 0, 0 1 1, -1 0 0, 0 0 1, 0 1 1, 1 1 0, 0 0 1, 1 0 0" TriangleIndices="2 1 0, 2 3 1, 6 5 4, 6 7 5"/> </GeometryModel3D.Geometry> <GeometryModel3D.Material> <DiffuseMaterial Brush="Green"/> </GeometryModel3D.Material> </GeometryModel3D> </Model3DGroup> </ModelVisual3D.Content> </ModelVisual3D>
上面已经设置了灯光,接下来要设置摄像机,代码如下:
var camera=new PerspectiveCamera( new Point3D(0,3,3),
new Vector3D(0,-3,-3),
new Vector3D(0,0,1),
45););
xmal:
<Viewport3D.Camera> <!--<PerspectiveCamera Position="0,0,10"/>--> <PerspectiveCamera LookDirection = " 0, -3, -3" UpDirection = " 0, 0, 1" Position = "0, 3, 3" FieldOfView = "45" /> </Viewport3D.Camera>
最后可以把它们一起归入Viewport3D
Viewport3D view3D=new Viewport3D(); view3D.Camera = camera; view3D.Children.Add(group);
当然我们也可以在指定灯光时,只定义DirectionalLight (方向光)
<ModelVisual3D> <ModelVisual3D.Content> <Model3DGroup> <!--<AmbientLight Color="White"/>--> <DirectionalLight Color="#FFFFFF" Direction="0,0,-10" /> <DirectionalLight Color="#FFFFFF" Direction="1,0,0" /> </Model3DGroup> </ModelVisual3D.Content> </ModelVisual3D>
然后自定义3D模型
<local:TreeMap3D x:Name="_treeMap3D" WeightBindingPath="CustomerCount"> <local:TreeMap3D.Transform> <Transform3DGroup> <ScaleTransform3D ScaleX="1.2" ScaleY="1.2" ScaleZ="1.2" /> <RotateTransform3D> <RotateTransform3D.Rotation> <AxisAngleRotation3D Angle="30" Axis="0, 0, 1" /> </RotateTransform3D.Rotation> </RotateTransform3D> <TranslateTransform3D OffsetZ="0.6" OffsetX="-0.3"/> </Transform3DGroup> </local:TreeMap3D.Transform> </local:TreeMap3D>
添加TreeMap3D类
public class TreeMap3D : UIElement3D { private string m_weightBindingPath; private IList m_itemsSource; private TreeMap3DElement m_selectedElement; private int[] m_weightMap; private TreeMap3DElement m_lastClickedElement; private readonly List<TreeMap3DElement> m_elements = new List<TreeMap3DElement>(); } }
定义ItemSource
public IList ItemsSource { get { VerifyAccess(); return m_itemsSource; } set { if (m_itemsSource != value) { VerifyAccess(); refresh(value); m_itemsSource = value; } }
定义其子元素:
private class TreeMap3DElement : UIElement3D { public TreeMap3DElement(int index, int count) { this.Visual3DModel = GenerateTreeMap3DModel(index, count); m_translate = new TranslateTransform3D(); m_scale = new ScaleTransform3D(); Transform3DGroup t3DGroup = new Transform3DGroup(); t3DGroup.Children.Add(m_scale); t3DGroup.Children.Add(m_translate); base.Transform = t3DGroup; } private object m_data; private string m_weightBindingPath; private bool m_isSelected; private double m_scaleZ; private readonly ScaleTransform3D m_scale; private readonly TranslateTransform3D m_translate; }
加入动画设计:
public bool IsSelected { get { return m_isSelected; } set { if (value != m_isSelected) { DoubleAnimation animation = new DoubleAnimation(); if (value) { animation.From = m_scale.ScaleZ; animation.To = m_scaleZ; } else { animation.From = m_scale.ScaleZ; animation.To = 0; } m_isSelected = value; animation.Duration = new Duration(TimeSpan.FromSeconds(0.2)); m_scale.BeginAnimation(ScaleTransform3D.ScaleZProperty, animation); } } }
最后运行如下: