• WPF 3D 平移模型+动画


    关于WPF 3D,网上有很多旋转的例子,但是关于平移的例子并不是太多。本文并非WPF 3D扫盲篇,因此需要对WPF 3D有一定了解,至少知道Viewport, PerspectiveCamera, ModelVisual3D等数据结构。需要了解WPF 3D的基础知识,可以参考MSDN: http://msdn.microsoft.com/zh-cn/library/ms747437.aspx

     

    1. 摄像机平移OR物体平移:

    WPF场景主要是由这两部分构成的:摄像机,物体。可以想象一下,自己拿着台摄像机正对着某个物体进行拍摄。

    那么当发生平移的时候有两种方法,第一种是将摄像机平移;第二种是将物体平移。相对来说,摄像机平移实现较复杂,效率较高;物体平移效率较低,实现简单。

    本文实现的是物体平移,如果希望做摄像机平移的朋友可以不往下读了。

    2. 在本项目中平移的操作流程: 

    1. 程序启动时可以看到整个3D场景,类似一个沙盘,此时旋转等操作会围绕沙盘中心;

    2. 双击沙盘某个地方,将沙盘中心移动到双击的地方,此时旋转等操作会围绕新的沙盘中心。

    3. 平移的算法:

    1.获取双击屏幕后鼠标在3D中相对应的点,主要利用了射线和3D碰撞的一个原理。代码上主要应用的就是VisualTreeHelper.HitTest函数,它会将结果传入一个回调函数中,我们这里是HTResultCenter.

    void BridgeVisual_MouseDoubleClick(object sender, MouseButtonEventArgs args)
     

         Point mouseposition = args.GetPosition(ViewPort);

       MoveCenter(mouseposition);

    }

     public void MoveCenter(Point mouseposition)
     {
          PointHitTestParameters pointparams = new PointHitTestParameters(mouseposition);
          VisualTreeHelper.HitTest(ViewPort, null, HTResultCenter, pointparams);

     } 

     private HitTestResultBehavior HTResultCenter(HitTestResult result)
     {
          RayHitTestResult rayResult = result as RayHitTestResult;
          if (rayResult != null)
          {
               //这就是鼠标点击后在3D中的坐标
               var hitPoint = rayResult.PointHit;
               ...

          }

     } 

    2.根据相机位置 + 相机的投射方向 = 获取相机在3D上投影的点,camera.Postion就是摄像机在3D世界中的位置了,camera.LookDirection就是摄像机看的方向。那么两者加起来就可以获取这个摄像机投射过后的位置了。 

      ////相机位置
      var cameraPostion = Camera.Position;
                   
      ////相机看的方向
      var lookDirection = Camera.LookDirection;

      /// 获取相机在3D投影的点 
      var x = cameraPostion.X + lookDirection.X;
      var y = cameraPostion.Y + lookDirection.Y;
      var z = cameraPostion.Z + lookDirection.Z;

    3. 那么利用摄像机投射的位置 - 鼠标双击的位置就可以获取物体应该偏移的量了,WPF中本来就有Transform3D 这个东西进行平移,
    此处应用了动画DoubleAnimation,所以代码有点多。

    DoubleAnimation doubleAnimationX = new DoubleAnimation();
    doubleAnimationX.BeginTime = new TimeSpan(000);
    doubleAnimationX.Duration = TimeSpan.FromMilliseconds(500);
    doubleAnimationX.From = Transform3D.OffsetX;
    doubleAnimationX.To = x - hitPoint.X;

    DoubleAnimation doubleAnimationY = new DoubleAnimation();
    doubleAnimationY.BeginTime = new TimeSpan(000);
    doubleAnimationY.Duration = TimeSpan.FromMilliseconds(500);
    doubleAnimationY.From = _Transform3D.OffsetY;
    doubleAnimationY.To = y - hitPoint.Y;

    DoubleAnimation doubleAnimationZ = new DoubleAnimation();
    doubleAnimationZ.BeginTime = new TimeSpan(000);
    doubleAnimationZ.Duration = TimeSpan.FromMilliseconds(500);
    doubleAnimationZ.From = Transform3D.OffsetZ;
    doubleAnimationZ.To = z - hitPoint.Z;

    Transform3D.BeginAnimation(TranslateTransform3D.OffsetXProperty, doubleAnimationX);
    Transform3D.BeginAnimation(TranslateTransform3D.OffsetYProperty, doubleAnimationY);  

    Transform3D.BeginAnimation(TranslateTransform3D.OffsetZProperty, doubleAnimationZ);  

    4. 最终的效果:

    1.平移前:

     

     2.平移后:

     

  • 相关阅读:
    PAT-字符串处理-A 1001 A+B Format (20分)
    PAT-字符串处理-B 1048 数字加密 (20分)
    数据库-第二章 关系数据库-2.3 关系的完整性
    数据库-第二章 关系数据库-2.2 关系操作
    数据库-第二章 关系数据库-2.1 关系数据结构及形式化定义
    IDLE打开Python报错 api-ms-win-crt-runtimel1-1-0.dll缺失的解决方案
    老毛桃pe安装系统
    LeetCode 213. House Robber II (动态规划)
    LeetCode 198. House Robber(DP)
    LeetCode 211. Add and Search Word
  • 原文地址:https://www.cnblogs.com/enjoyeclipse/p/2695796.html
Copyright © 2020-2023  润新知