wpf 模拟3D效果(和手机浏览图片效果相似)(附源码)

wpf的3D是一个很有意思的东西,类似于ps的效果,类似于电影动画的效果,因为动画的效果,(对于3D基础的摄像机,光源,之类不介绍,对于依赖属性也不介绍。),个人认为,依赖属性这个东西,有百分之五十是为了3D而存在。
(自己写的类似于demo的东西)
先上图,无图无真相

这是demo的整个效果图,可以用鼠标移动,触摸屏也可以手指滑动,图片会移动,然后移动结束,会有一个回弹的判断。

<Window x:Class="_3Dshow.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Demo" Height="441" Width="702" Background="LightGray"
        xmlns:System="clr-namespace:System;assembly=mscorlib">

    <Grid  PreviewMouseDown="_view_mousedown" PreviewMouseMove="_view_mousemove" PreviewMouseUp="_view_mouseup" >
        <Border Background="LightGray" Padding="2" Margin="0,-41,0,-40">
            <Viewport3D x:Name="_view" >
            </Viewport3D>
        </Border>
    </Grid>
</Window>

xmal,很简单 一个viewport3D,还有就是鼠标事件,这里如果你深入研究,会发现比较有意思的事情,路由事件!
从grid 路由到viewground,如果外面再嵌套一个canvas,会更清晰。
个人认为路由事件比较扯淡的是,我想让grid处理不让viewport3d处理,或者又想让grid处理又想让viewport3d处理,这是很有意思的事情。
好,这里不多啰嗦,上代码

       #region 全局函数
        // Queue<double>[,] sum_queue;
        double[,] sum_queue = new double[5, 2];
        PerspectiveCamera _camera = null;
        bool ismousedown = false;
        // TimeSpan timspan;
        Point startPoint, currentPoint, endPoint;

        string[] fileList;
        double[,] sum_list;
        int _b = 0;
        DispatcherTimer sub_time = new DispatcherTimer();
        DispatcherTimer sub_time1 = new DispatcherTimer();
        private static DependencyProperty TranslatePosProperty = DependencyProperty.Register(
            "TranslatePos", typeof(double), typeof(Window1), new PropertyMetadata((double)0, new PropertyChangedCallback(DragPosChanged)));
        #endregion

一个依赖属性,两个dispatchertimer,一个用于控制拖拽动画,一个用于托抓完毕后的回弹效果,通过animation来改变依赖属性,进一步达到控制整个页面的效果。
依赖属性的回测事件(我自己把这种回传事件称之为回测事件,个人喜好)

        #region temp
        double _pos = 0;

        void PosChanged(double pos)
        {

            double delta = pos - _pos;
            _pos = pos;
            GetTran(delta);
        }
        #endregion

 



下面是核心代码,我用一个数组存放了所有的图片,图片的位置,图片的偏转角度,图片的缩放大小,图片在左边还是在右边的一个标识位,最后通过设置Transform 来改变图片,其实不能说是图片了,因为他是一个个元素,viewport的元素,这些元素自身有Transform 这个属性,所以直接用这个设置,我还没有找到用动画或者故事板控制的方法。

        private void GetTran(double sum)
        {

            for (int i = 0; i < _view.Children.Count; i++)
            {
                #region point move
                #region 调整位置

                sum_list[i, 1] += sum / 270;

                //angel
                if (sum > 0)
                {
                    if (sum_list[i, 4] == -2)
                    {
                        sum_list[i, 3] += sum / 2000;
                    }
                    else if (sum_list[i, 4] == 0)
                    {
                        sum_list[i, 3] -= sum / 2000;
                    }
                    else if (sum_list[i, 4] == 2)
                    {
                        sum_list[i, 3] -= sum / 2000;
                    }

                }
                else
                {
                    if (sum_list[i, 4] == -2)
                    {
                        sum_list[i, 3] += sum / 2000;
                    }
                    else if (sum_list[i, 4] == 0)
                    {
                        sum_list[i, 3] += sum / 2000;
                    }
                    else if (sum_list[i, 4] == 2)
                    {
                        sum_list[i, 3] -= sum / 2000;
                    }

                }


                if (sum > 0)
                {
                    if (sum_list[i, 2] == 0)
                    {
                        sum_list[i, 4] = 2;
                    }
                    sum_list[i, 2] -= sum / 10;
                    if (sum_list[i, 2] == 0)
                    {
                        sum_list[i, 4] = 0;
                    }

                }
                else if (sum < 0)
                {
                    if (sum_list[i, 2] == 0)
                    {
                        sum_list[i, 4] = -2;
                    }
                    sum_list[i, 2] -= sum / 10;
                    if (sum_list[i, 2] == 0)
                    {
                        sum_list[i, 4] = 0;
                    }

                }

                #endregion
                Transform3DGroup tg = new Transform3DGroup();
                tg.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 1, 0), sum_list[i, 2])));
                tg.Children.Add(new ScaleTransform3D(sum_list[i, 3], sum_list[i, 3], sum_list[i, 3]));
                tg.Children.Add(new TranslateTransform3D(sum_list[i, 1], 0, sum_list[i, 0]));

                _view.Children[i].Transform = tg;
                #endregion
            }
            Volidating();
        }

最后会有一个校验,校验是让设置每个图片是否超标,以及设置他们到和初始相比较的状态

 private void Volidating()
        {
            for (int i = 0; i < _view.Children.Count; i++)
            {
                if (sum_list[i, 3] >= 1)
                {
                    sum_list[i, 1] = 0;
                    sum_list[i, 3] = 1;
                    sum_list[i, 2] = 0;
                    sum_list[i, 4] = 0;
                    int sum = 1;
                    for (int j = i - 1; j >= 0; j--)
                    {
                        sum_list[j, 3] = 1 - (0.2) * sum;

                        if (sum_list[j, 3] <= 0)
                        {
                            sum_list[j, 3] = 0;
                        }
                        sum_list[j, 2] = 40 * sum;
                        sum_list[j, 1] = -1.5 * sum;
                        sum++;
                    }
                    sum = 1;
                    for (int j = i + 1; j < _view.Children.Count; j++)
                    {
                        sum_list[j, 3] = 1 - (0.2) * sum;

                        if (sum_list[j, 3] <= 0)
                        {
                            sum_list[j, 3] = 0;
                        }
                        sum_list[j, 2] = 40 * sum * (-1);
                        sum_list[j, 1] = 1.5 * sum;
                        sum++;
                    }

                    break;
                }
            }
        }



当鼠标点击时候,我记录下一个坐标,鼠标移动时,我记录下一个坐标,鼠标起来时,我记录一个坐标,鼠标移动时,触发第一个timer,鼠标起来时,触发第二个timer。
这些就是基本思路,写的很随性,思维不缜密,10年11月时候花了一周时间写的,我并不是说我怎么怎么样,nb或者sb,只是有些怀念。
那时候研究wpf,一心要涉足这个方向,对于动画一知半解,wpf相对于winform是一个全新的东西,现在看这些代码,或许觉得摇头或者觉得垃圾,但是很怀念那时候还年轻的时候,用最笨的方法实现想要的东西,为此而加班至深夜。
有时候为了找一些问题,google出来,千篇一律,copy是常见,稍微带源码的都要注册,积分,很不喜欢把程序商品化,共享讨论才能有改进,所以就把之前的代码发来讨论一下,如有兴趣,可以继续改进。
(我们是拉风的程序员,不是屌丝)
谨祝福'那时候终日不知疲倦,反复坐在电脑旁测试,看着自己写出的东西,在心里自己对自己说:看,这是我写出来的东西。'又奔波不已的所有程序员。
源码:
files.cnblogs.com/fish124423/3Dshow.rar

posted @ 2012-08-09 13:35  爱喝可乐  阅读(4510)  评论(2编辑  收藏  举报