您的位置:首页 > 其它

在WPF中使用PlaneProjection模拟动态3D效果

2016-01-25 11:55 381 查看


虽然在WPF中也集成了3D呈现的功能,在简单的3D应用中,有时候并不需要真实光影的3D场景。毕竟使用3D引擎会消耗很多资源,有时候使用各种变换和假的阴影贴图也能设计出既省资源,又有很好用户体验的“伪”3D界面。

  在Silverlight中,因为性能问题,一般并不使用真3D引擎,微软为Silverlight提供了System.Windows.Media.PlaneProjection 类,用投影变换来模拟3D的效果。

  下面让我们看下一个 Microsoft Expression Blend 4 提供的示例 Wall3D (位于帮助>欢迎屏幕>示例)。





 


  大家不要被这个可以流畅滚动的3D图片墙所迷惑,其实这只是一个ListBox控件。MainPage中给ListBox定义了一个ItemsPanelTemplate,使用新的控件来作为ListBox中Items的布局控件,这个

控件就是这个项目最核心的类:CircularPanel3D。


  CircularPanel3D类继承自System.Windows.Controls.Panel,它实现了一种新的布局方式,效果大家在上一张图片中都看到了。这种华丽的效果实际上都是由这个最重要的类中的最重要的方法:

private void Refresh() 完成的。


1 privatevoid Refresh()

2 {

3 //几个计数器,看名字就功能很明了

4  int count =0;

5 int col =0;

6 int row =0;

7 int zLevel =0;



9 //开始遍历子元素

10  foreach (FrameworkElement childElement inthis.Children)

11 {

12 //AngleItem是指单个元素的旋转角度,算法是360除以列数

13 //这个方法的布局方式是先布满一圈,再下一环的,角度总是可以取模的

14 //所以这边直接AngleItem和count相乘了

15 //InitialAngle这个属性是用来确定整个圆环的偏转角度的,每次这个依赖属性变化就会重新计算布局(调用这个方法)

16 double angle = (this.AngleItem * count++) -this.InitialAngle;

17 //下面两个变量用来确定元素在屏幕上的位置,用到了三角函数,数学不好的请问高中数学老师

18 double x =this.Radius * Math.Cos(Math.PI * angle /180);

19 double z =this.Radius * Math.Sin(Math.PI * angle /180);

20 //创建个PlaneProjection对象,并赋值

21 PlaneProjection projection =new PlaneProjection();

22 if (projection !=null)

23 {

24 projection.CenterOfRotationX =0.5;

25 projection.CenterOfRotationY =0.5;

26 projection.CenterOfRotationZ =0.5;

27 projection.RotationY = angle +90;

28 projection.GlobalOffsetX = x;

29 //Distance实际上就是模拟的镜头距离

30 projection.GlobalOffsetZ = z -this.Distance;

31 //-330。。。坑爹的硬编码,实际上就是两行元素的间距,OffsetY是纵向的偏移量,用于调整环在屏幕上的位置

32 projection.GlobalOffsetY = row * (-330) +this.OffsetY;

33 }

34 //实际上是让double数变成int数,但是又不会丧失区别性,下面要用到

35 int depth = (int)(z *100);

36 

37 double pDist = (this.Distance -1000) /2000;

38 double pZ = ((z +1000) /2000) +0.5;

39 

40 //让太远的和太近的变透明

41 double opacity = (pZ - pDist) +0.4;

42 if (opacity >=1)

43 {

44 childElement.Opacity = (2- opacity);

45 }

46 elseif (opacity <0)

47 {

48 childElement.Opacity =0;

49 }

50 else

51 {

52 childElement.Opacity = opacity;

53 }

54 

55 // 嗯这边有原版的英文注释,不解释

56 // Variable zLevel changes value of ZIndex for each item in the ListBox.

57 // This way the reflex of elements at the top will be placed behind the item below it.

58 Canvas.SetZIndex(childElement, depth-(++zLevel*10));

59 

60 //根据Align属性设置对齐方式,不是很重要

61 double alignX =0;

62 double alignY =0;

63 switch (this.Align)

64 {

65 case AlignmentOptions.Left:

66 alignX =0;

67 alignY =0;

68 break;

69 case AlignmentOptions.Center:

70 alignX = childElement.DesiredSize.Width /2;

71 alignY = childElement.DesiredSize.Height /2;

72 break;

73 case AlignmentOptions.Right:

74 alignX = childElement.DesiredSize.Width;

75 alignY = childElement.DesiredSize.Height;

76 break;

77 }

78 //将PlaneProjection对象赋给子元素的Projection属性

79 childElement.Projection = projection;

80 //定位子元素

81 childElement.Arrange(new Rect(this.Width /2- alignX , this.Height /2- alignY, childElement.DesiredSize.Width, childElement.DesiredSize.Height));

82 

83 //换行,又见坑爹的硬编码14。。这个代表有十四列

84 col++;

85 if (col >14)

86 {

87 col =0;

88 row++;

89 }

90 }

91 }

原文地址:http://biancheng.dnbcw.info/net/448246.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息