博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
具有3D旋转效果的图片组的一种实现
阅读量:7141 次
发布时间:2019-06-28

本文共 3165 字,大约阅读时间需要 10 分钟。

hot3.png

       前段时间看到QQ群里面有朋友问一组图片的3D旋转效果怎么做,虽然之前看到过flash版本的这种效果,但是自己却也没有做过这种效果。于是,就想来练习练习,最终的效果是这样的:

 

 

其实,这个东西就是要利用椭圆的标准方程,然后,你通过一个dispatchertimer 每隔一段时间触发一次动作,使得里面的图片沿着椭圆的轨迹改变坐标点,另外可以再改变图片的大小和透明度,使得效果看起来更好点。

 

关于椭圆及其标准方程:

 

      

 

还有一个需要用到的椭圆的性质是,知道椭圆的两个半轴,根据角度求得在椭圆轨迹上的坐标点:

也就是椭圆的参数方程:

 

其中的角度是离心角:

 

 

具备了这些几何知识,接下来的应该很简单了,无非就是利用silverlight中的属性,变幻效果等等,使得每隔一定时间,让你的图片在如上图那样的椭圆轨迹上运动。好了,分析完毕,开始写代码:

首先,在xaml文件中如下写:

 

 
<
Canvas 
x:Name
="MainCanvas"
 Background
="Black"
>
    
</
Canvas
>

 

 

是不是很简单,因为这次把大多数的操作,包括图片的加载都放到隐藏代码中了,这里并没有鄙视xaml的意思,其实我很喜欢xaml声明式的代码,但是标记代码和后台的逻辑代码都是必不可少的,这也是silverlight和WPF的一大特色。只是,这次用到的逻辑比较多,在xmal中去做就不太合适。好了,接下来,看下代码隐藏文件中是怎么回事:

首先在MainPage控件类中定义这么些私有变量:

 

 
private
 
double
 _speed;                                                        
//
图片移动速度
        
private
 List
<
double
>
 _angles;                                                
//
离心角角度集合
        
private
 
const
 
double
 _MAX_SPEED 
=
 
0.009
;                                      
//
定义的最大速度值
        
private
 DispatcherTimer _disp;                                                   
//
定时器
        
private
 List
<
ScaleTransform
>
 scaleTransforms 
=
 
new
 List
<
ScaleTransform
>
();        
//
缩放变换集合

 

 

然后,我们需要一个初始化的函数,包括加载图片啊,设置图片大小,初始离心角角度集合的初始化

 

19085440_dixc.gif 代码
  
public
 
void
 InitContainer()
        {
            _angles 
=
 
new
 List
<
double
>
();
            _speed 
=
 _MAX_SPEED;
            _disp 
=
 
new
 DispatcherTimer();
            _disp.Interval 
=
 TimeSpan.FromMilliseconds(
25
);                              
//
每隔25毫秒,图片移动一次
            _disp.Tick 
+=
 
new
 EventHandler(_disp_Tick);
           
            
for
 (var i 
=
 
0
; i 
<
 
6
; i
++
)
            {
                Canvas ca 
=
 
new
 Canvas();
                BitmapImage bit
=
new
 BitmapImage(
new
 Uri(
@"
Images/
"
+
(i
+
1
)
+
"
.jpg
"
,UriKind.Relative));
                Image img
=
new
 Image();
                img.Width 
=
 
200
;
                img.Height 
=
 
250
;
                img.Source
=
bit;
                ca.Width 
=
 
200
;
                ca.Height 
=
 
250
;
                
//
ca.Background = new SolidColorBrush(Colors.Red);
                ca.Children.Add(img);
                _angles.Add ( (Math.PI 
*
 
2
 
/
 
6
*
 i);
                ScaleTransform sc 
=
 
new
 ScaleTransform();
                scaleTransforms.Add(sc);
                sc.ScaleX 
=
 
1
;
                sc.ScaleY 
=
 
1
;
                sc.CenterX 
=
 
100
;
                sc.CenterY 
=
 
125
;
                ca.RenderTransform 
=
 sc;
                MainCanvas.Children.Add(ca);
            }
            _disp.Start();
        }

 

 

然后再写一个移动图片的函数,主要功能:根据离心角的角度通过椭圆参数方程计算出此刻图片位于椭圆轨迹上的坐标点,然后再进行图片缩放,透明度改变等效果

 

 
public
 
void
 SetMove()
        {
            
double
 RadiusX 
=
 
300
;                                       
//
设定椭圆的长半轴
            
double
 RadiusY 
=
 
80
;                                        
//
设定椭圆的短半轴
            
double
 CenterX 
=
 
550
;                                        
//
设定图片组的中心
            
double
 CenterY 
=
 
220
;                                        
//
设定图片组的中心
            Canvas aCanvas;
            
for
 (
int
 i 
=
 
0
; i 
<
 
6
; i
++
)
            {
               aCanvas 
=
 MainCanvas.Children[i] 
as
 Canvas;
               
double
 NewX 
=
 Math.Cos(_angles[i]) 
*
 RadiusX 
+
 CenterX;                         
//
计算x坐标
               
double
 NewY 
=
 Math.Sin(_angles[i]) 
*
 RadiusY 
+
 CenterY;                         
//
计算y坐标
               aCanvas.SetValue(Canvas.LeftProperty, NewX);                                   
//
对图片集合中的每张图片进行重新定位
               aCanvas.SetValue(Canvas.TopProperty, NewY);
               _angles[i] 
+=
 _speed;                                                          
//
根据速度改变离心角的角度
               aCanvas.SetValue(Canvas.ZIndexProperty, System.Convert.ToInt32(NewY));         
//
设置图片的zIndex属性,防止位于底层的图片遮挡上层的图片
               
double
 opacity 
=
 Math.Sin(_angles[i]) 
+
 
1.5
;                                   
//
改变图片透明度,其实这里是改变画布透明度
               aCanvas.SetValue(Canvas.OpacityProperty, opacity);
               var curr 
=
 scaleTransforms[i];
               var change 
=
 NewY  
/
 (CenterY 
+
 RadiusY 
-
 curr.ScaleY);                        
//
重新计算画布大小
               curr.ScaleX 
=
 change;                                     
               curr.ScaleY 
=
 change;
            }
        
        }

 

最后,把SetMove()函数放到dispatchertimer的tick触发函数中,每隔25ms 调用,更新每张图片的位置和大小及其透明度

 

void
 _disp_Tick(
object
 sender, EventArgs e)
        {
            SetMove();
        }

 

 

这样一个旋转图片组的效果就做好了 :)

 

总结:这次其实没有直接去控制图片的位置,而是把图片放到画布中,通过改变画布的位置而改变图片的位置,这样做的好处是,可复用性更强一些,以后不只是做图片,可以把文本,按钮,或者其它控件甚至视频放到其中,产生这样的效果。当然,更好的做法是自己把它封装成控件,以便以后更方便使用,另外,这个效果目前还是比较基础和粗糙的,还有很多地方可以改进,例如,可以加入鼠标的交互,当鼠标移到上面不同位置产生加速,减速,改变方向,改变椭圆中心等等~

转载于:https://my.oschina.net/u/1446855/blog/643525

你可能感兴趣的文章
一篇好的BUG报告是如何炼成的
查看>>
要做好性能测试,该掌握些什么?
查看>>
今天配置java + selenium 3.0出了很多问题,记录如下
查看>>
xen虚拟化里常用的一些配置
查看>>
在用vi编辑文件时遇到“Terminal too wide”的提示
查看>>
RHEL6和RHEL7的变化
查看>>
VMware 虚拟机设置U盘启动(老毛桃 PE)
查看>>
程序员注意了!这样的公司千万不要去!
查看>>
文件服务器--samba和ftp的搭建
查看>>
我的友情链接
查看>>
ubuntu 14.10桌面登陆失败
查看>>
java并发编程,ThreadLocal源码解析
查看>>
textbox只能输入数字
查看>>
Summer School实验二
查看>>
sed命令的使用及案例
查看>>
GoLang环境配置
查看>>
JAVA构建缓存
查看>>
JS中使用正则表达式
查看>>
我的友情链接
查看>>
VM with share disk configuration
查看>>