WPF中对三维模型的控制

简介: 原文:WPF中对三维模型的控制 (以下选自南开大学出版社出版的《WPF和Silverlight教程》) 3Dmax中的建模模型可以导出为obj文件格式,将此文件导入WPF项目中,由WPF完成对三维造型的贴图和控制设计。
原文: WPF中对三维模型的控制

(以下选自南开大学出版社出版的《WPF和Silverlight教程》)

3Dmax中的建模模型可以导出为obj文件格式,将此文件导入WPF项目中,由WPF完成对三维造型的贴图和控制设计。本例在3Dmax中设计了1个双翼开瓶器模型,将“开瓶器.obj”和贴图材质文件都添加到项目中(“素材”文件夹)。图2-206 的左侧是“开瓶器.obj”文件拖入到【设计面板】后,在【对象和时间线】面板中看到的结构,右侧是贴图后的开瓶器模型,中间是本例完成的对开瓶器部件进行拆卸和装配的控制按钮。下面说明设计过程。

    1obj文件导入后的对象

2-206左侧看到的是obj文件导入后的对象结构,ViewPort3D(命名为viewport3)是三维对象的容器,其中包含相机元素CameraModelVisual3D,默认相机是透视相机PerspectiveCamera(已经命名为ppc);World元素(ModelVisual3D)中包含了环境光子元素AmbientLightContainerModelVisual3D)、方向光子元素DirectionalLightContainerModelVisual3D)和三维造型子元素RootGeometryContainerModelVisual3D),后者又包含了qua023Dmax中的原名)等6ModelVisual3D子元素,每个子元素包含造型元素材质设置DefaultMaterialGeometryModel3D)。

    WPF中对三维模型的控制
图2-206 开瓶器结构、外观和控制按钮

2-1三维造型元素名称(3Dmax中的原名)和开瓶器部件名称对照 

三维造型元素名

开瓶器部件名

三维造型元素名

开瓶器部件名

qua01

左翼

Object

开瓶器座

qua02

右翼

Object03

左翼螺钉

pemo

开瓶器把手

Object04

右翼螺钉

2. 三维造型元素初始位置

 obj文件拖入Window3.xaml【设计面板】后,尽量发大到和设计窗口界面一样大小,这时的大小不一定合适,可以调节的照相机初始位置,如图2-207左图。其中参数是调整后的参数,比如Position,在obj文件刚导入时,XYZ不一定是目前的数值,改变Z参数的数值可以调节三维造型在屏幕中的大小。Direction参数中的XY调节到0,相机面向Z坐标轴的负方向。本例中Far Clipping Plane的参数调节的比较大,当3D对象缩小的很小时还能完整看到造型全貌。

WPF中对三维模型的控制
2-207 照相机初始位置参数设置和World初始变换设置

另外,“World”元素做了位移变换,见图2-207右图,Z坐标使造型大小改变,Y坐标产生上下位移。所有三维造型元素的其他变换参数默认是0,知道这些参数的初始值对后面的故事板设计很重要。

3. 贴图和光线设置

贴图需要的材质图片“金属7.jpg”和“外壳.jpg”已经添加到项目的“素材”文件夹中,将这些图片拖入【设计面板】后生成画刷资源,保存到ResourceDictionary1.xaml资源文件中,用于三维造型元素的材质贴图。“Object”元素(“开瓶器座”)的“DefaultMaterial”贴图使用了“外壳.jpg”生成的画刷资源,“螺钉”没有贴图,采用“白色”材质,其余采用“金属7.jpg 生成的画刷资源,贴图过程略

环境光“AmbientLight”采用定向光,设置为白色,方向光DirectionalLight也采用定向光,设置为白色,调整初始角度可以明亮照射3D对象。

4. 开瓶器旋转故事板设计

示例中设计了1个故事板StoryBoard0(程序中的命名为mystoryboard0),用于实现整个造型的三维空间旋转,如图2-208所示。

WPF中对三维模型的控制
2-208 电动机三维空间旋转故事板设计

故事板StoryBoard0针对三维元素“World”和方向光DirectionalLight设置了动画,故事板中有5个关键帧,“World”围绕Y轴进行旋转变换(参考图2-203),分别是090180270360,时间间隔供8秒。同时,对方向光进行跟踪设置,保证旋转时方向光能够明亮照射到3D对象。图2-206中的“旋转”按钮(名为xuanzhuan)的事件代码就是启动此故事板。WPF中设计故事板时会自动生成事件触发器,自动启动故事板,本例将触发器全部删除,用代码启动后停止。

5. 开瓶器部件拆卸和装配故事板设计

开瓶器部件拆卸共设计了5个故事板,StoryBoard1StoryBoard5(程序中的名称分别是mystoryboard1mystoryboard5),分别顺序用于设计拆卸“左翼螺钉”、“右翼螺钉”、“左翼”、“右翼”、“开瓶器把手”的动画。

开瓶器部件装配也设计了5个故事板,StoryBoard6StoryBoard10(程序中的名称分别是mystoryboard6mystoryboard10),分别顺序用于设计装配“开瓶器把手”、 “右翼” 、“左翼”、“右翼螺钉”和“左翼螺钉”的动画。

拆卸动画和装配过程的动画运动过程是相反的,拆卸动画的终点参数应该是装配动画的起点参数,装配动画的终点参数是拆卸动画的起点参数,动画时间间隔可以一样,运动路径可以有差异,但起点和终点参数必须对应,否则部件就不能还原到原来位置了。动画设计过程是雷同的,图2-209左图是开瓶器所有可拆卸部件全部拆卸后在屏幕中的放置位置布局。

WPF中对三维模型的控制
2-209 开瓶器部件拆卸后放置在屏幕的位置布局和“开瓶器把手”拆卸故事板设计

    下面以“开瓶器把手”为例,说明其拆卸动画和装配动画的设计。

“开瓶器把手”的拆卸动画故事板是StoryBoard5(程序中名为mystoryboard5),设计图如图2-209右下图。拆卸故事板有10个关键帧。“开瓶器把手”的装配动画故事板是StoryBoard6(程序中名为mystoryboard6),设计图如图2-209右上图。装配故事板同样有10个关键帧。对应的变换参数如表2-2

    从表2-2的参数中可以看出拆卸动画的终点参数是装配动画的起点参数,装配动画的终点参数是拆卸动画的起点参数,中间的参数有差异仅仅反映中间运动过程有异,这并不重要。

其他故事版的设计雷同,不再列出。

6. 程序设计

程序设计有下面几点要说明:

第一,图2-206中有4个按钮,其中有1个“复位”按钮,恢复三维对象的原来状态,使用删除多于变换的方法。“旋转”按钮启动的是StoryBoard0故事板。“自动拆卸”按钮单击后将会依次启动故事板StoryBoard1StoryBoard5,“自动装配”按钮单击后将会依次启动故事板StoryBoard6StoryBoard10

第二,故事板的控制没有使用触发器,自动生成的所有触发器均被删除,故事板的控制采用前面介绍过的利用故事板资源设置代码控制故事板。

第三,故事板的依次启动指前一个故事板完成后才能启动后一个故事版,这样在程序上需要设置故事板的Completed事件。

2-2 StoryBoard5StoryBoard6关键帧参数设置

时间

拆卸动画StoryBoard5

装配动画StoryBoard6

位移变换参数

坐标XYZ

旋转变换参数

角度XYZ

位移变换参数

坐标XYZ

旋转变换参数

角度XYZ

0

0,0,0

0,0,0

0,110,0

0,0,0

1

0,10,0

0,90,0

0,90,0

0,0,0

2

0,20,0

0,180,0

0,70,0

0,0,0

3

0,30,0

0,270,0

0,60,0

0,0,0

4

0,40,0

0,360,0

0,50,0

0,0,0

5

0,50,0

0,90,0

0,40,0

0,0,0

6

0,60,0

0,180,0

0,30,0

0,-90,0

7

0,70,0

0,270,0

0,20,0

0,-180,0

8

0,90,0

0,360,0

0,10,0

0,-270,0

9

0,110,0

0,360,0

0,0,0

0,-360,0

下面是程序代码,有相关解释,不再赘述。

public partial class Window3 : Window

    {

        //旋转故事板

        Storyboard mystoryboard0=new Storyboard();

        //拆卸故事板

        Storyboard mystoryboard1=new Storyboard();

        Storyboard mystoryboard2=new Storyboard();

        Storyboard mystoryboard3=new Storyboard();

        Storyboard mystoryboard4=new Storyboard();

        Storyboard mystoryboard5=new Storyboard();

        //装配故事板

        Storyboard mystoryboard6=new Storyboard();

        Storyboard mystoryboard7=new Storyboard();

        Storyboard mystoryboard8=new Storyboard();

        Storyboard mystoryboard9=new Storyboard();

        Storyboard mystoryboard10=new Storyboard();

        //定义鼠标跟随对象,FollowMouse3D是自定义类

        FollowMouse3D fm3d=new FollowMouse3D();

        Point mouseLastPosition;

        //定义变量,记忆相机位置坐标

        double cameraX,cameraY,cameraZ;

        //设置三维变换组变量

        Transform3DGroup GroupTF3D;

        //记忆三维变换组中的子变换数

        int transforms;

        public Window3()

        {

            this.InitializeComponent();

            mystoryboard0=(Storyboard)this.FindResource("Storyboard0");

            mystoryboard1=(Storyboard)this.FindResource("Storyboard1");

            mystoryboard2=(Storyboard)this.FindResource("Storyboard2");

            mystoryboard3=(Storyboard)this.FindResource("Storyboard3");

            mystoryboard4=(Storyboard)this.FindResource("Storyboard4");

            mystoryboard5=(Storyboard)this.FindResource("Storyboard5");

            mystoryboard6=(Storyboard)this.FindResource("Storyboard6");

            mystoryboard7=(Storyboard)this.FindResource("Storyboard7");

            mystoryboard8=(Storyboard)this.FindResource("Storyboard8");

            mystoryboard9=(Storyboard)this.FindResource("Storyboard9");

            mystoryboard10=(Storyboard)this.FindResource("Storyboard10");

            //声明故事板完成事件

            mystoryboard1.Completed+=new System.EventHandler(mystoryboard1_Completed);

            mystoryboard2.Completed+=new System.EventHandler(mystoryboard2_Completed);

            mystoryboard3.Completed+=new System.EventHandler(mystoryboard3_Completed);

            mystoryboard4.Completed+=new System.EventHandler(mystoryboard4_Completed);

            mystoryboard5.Completed+=new System.EventHandler(mystoryboard5_Completed);

            mystoryboard6.Completed+=new System.EventHandler(mystoryboard6_Completed);

            mystoryboard7.Completed+=new System.EventHandler(mystoryboard7_Completed);

            mystoryboard8.Completed+=new System.EventHandler(mystoryboard8_Completed);

            mystoryboard9.Completed+=new System.EventHandler(mystoryboard9_Completed);

            mystoryboard10.Completed+=new System.EventHandler(mystoryboard10_Completed);

            //远景相机初始位置

            cameraX=ppc.Position.X;

            cameraY=ppc.Position.Y;

            cameraZ=ppc.Position.Z;

            //声明或获取当前World的三维变换组(xaml中)Transform3DGroup

            GroupTF3D = World.Transform as Transform3DGroup;

            //记录三维变换组中子变换的总数

            transforms=GroupTF3D.Children.Count;

            //故事板属性设置

            this.mystoryboard0.RepeatBehavior=RepeatBehavior.Forever;

            this.mystoryboard0.FillBehavior=FillBehavior.Stop;

this.mystoryboard0.BeginTime=TimeSpan.FromSeconds(2);

            this.mystoryboard1.BeginTime=TimeSpan.FromSeconds(2);

            this.mystoryboard6.BeginTime=TimeSpan.FromSeconds(2);

            this.mystoryboard0.Begin();

        }

   //复位按钮,调用自定义方法(复位操作)

private void reset_Click(object sender, System.Windows.RoutedEventArgs e)

        {

            Reset();       

        }

     //自定义方法,复位操作

    private void Reset(){

            this.mystoryboard0.Stop();

            //恢复相机初始位置

            ppc.Position = new Point3D(cameraX, cameraY,cameraZ);

            int j=GroupTF3D.Children.Count;

            //保留原来的变换数,其余删除

            if (j>transforms){         

                for (int k=j-1;k>transforms-1;){

                   GroupTF3D.Children.RemoveAt(k);

                   k=GroupTF3D.Children.Count-1;

                }

            }  

        }

    //旋转按钮事件

    private void xuanzhuan_Click(object sender, System.Windows.RoutedEventArgs e)

        {

            this.mystoryboard0.Begin();

        }

    //自动拆卸

    private void button6_Click(object sender, System.Windows.RoutedEventArgs e)

        {

            Reset();

            this.mystoryboard1.Begin();//左翼螺钉拆卸

        }

    private void mystoryboard1_Completed(object sender, System.EventArgs e)

        {

            this.mystoryboard2.Begin();//右翼螺钉拆卸

        }

    private void mystoryboard2_Completed(object sender, System.EventArgs e)

        {

            this.mystoryboard3.Begin();////左翼拆卸

        }

    private void mystoryboard3_Completed(object sender, System.EventArgs e)

        {

            this.mystoryboard4.Begin();//右翼拆卸

        }

    private void mystoryboard4_Completed(object sender, System.EventArgs e)

        {

            this.mystoryboard5.Begin();//开瓶器把手拆卸

        }

    private void mystoryboard5_Completed(object sender, System.EventArgs e)

        {

            this.mystoryboard0.Begin();//拆卸完成启动旋转故事板

        }  

    //自动装配

    private void button7_Click(object sender, System.Windows.RoutedEventArgs e)

        {

            Reset();

            this.mystoryboard6.Begin();//开瓶器把手装配

        }

    private void mystoryboard6_Completed(object sender, System.EventArgs e)

        {

            this.mystoryboard7.Begin();//右翼装配

        }

    private void mystoryboard7_Completed(object sender, System.EventArgs e)

        {

            this.mystoryboard8.Begin();//左翼装配

        }

    private void mystoryboard8_Completed(object sender, System.EventArgs e)

        {

            this.mystoryboard9.Begin();//右翼螺钉装配

        }

    private void mystoryboard9_Completed(object sender, System.EventArgs e)

        {

            this.mystoryboard10.Begin();//左翼螺钉装配

        }

    private void mystoryboard10_Completed(object sender, System.EventArgs e)

        {

            this.mystoryboard0.Begin();//装配完成启动故事板

        }      

     }



 

目录
相关文章
|
Web App开发 监控 前端开发
C# WPF 嵌入网页版WebGL油田三维可视化监控
C# WPF 嵌入网页版WebGL油田三维可视化监控
C# WPF 嵌入网页版WebGL油田三维可视化监控
|
C#
WPF 3D动态加载模型文件
原文:WPF 3D动态加载模型文件 这篇文章需要读者对WPF 3D有一个基本了解,至少看过官方的MSDN例子。 一般来说关于WPF使用3D的例子,都是下面的流程: 1.美工用3DMAX做好模型,生成一个obj文件 2.程序然后打开Blender,将obj拖动到Blender中,生成xaml代码   但是这样做会有至少两个问题: 1. 维护麻烦,因为一旦模型修改,你需要重复上面的步骤,至少要修改xaml的代码。
1463 0
|
C#
WPF 3D模型的一个扩展方法
原文:WPF 3D模型的一个扩展方法 在WPF 3D中,我们常常需要改变一个ModelVisual3D对象的颜色。 先说说ModelVisual3D,本质上3D模型都是由一个个的三角形构成的,并且经过材质进行渲染(DiffuseMaterial) 。
859 0
|
C#
WPF利用HelixToolKit后台导入3D模型
原文:WPF利用HelixToolKit后台导入3D模型 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m0_37591671/article/details/75044423 ...
3196 0
|
C# C++
3ds Max建模,Blend设计,VS2008控制WPF的3D模型例子
原文:3ds Max建模,Blend设计,VS2008控制WPF的3D模型例子 3ds Max建模,Blend设计,VS2008控制WPF的3D模型例子   所用的软件 3ds Max 9.
1196 0
|
C#
用游戏杆控制WPF中三维模型
原文:用游戏杆控制WPF中三维模型 用游戏杆控制WPF中三维模型   今天心情比较好,不写WF的文章了,换个主题.写一个我最最最擅长的内容.   例子下载: http://files.
869 0
|
C# 算法
WPF 3D 平移模型+动画(桥梁检测系统)
原文:WPF 3D 平移模型+动画(桥梁检测系统) 关于WPF 3D,网上有很多旋转的例子,但是关于平移的例子并不是太多。
1397 0
|
算法 C# 图形学
WPF绘制深度不同颜色的3D模型填充图和线框图
原文:WPF绘制深度不同颜色的3D模型填充图和线框图 在机械测量过程中,测量的数据需要进行软件处理。通常测量一个零件之后,需要重建零件的3D模型,便于观察测量结果是否与所测工件一致。
2857 0
|
C# 图形学 传感器
WPF在3D Cad模型中利用TextureCoordinates实现颜色渐变显示偏差值的变化
原文:WPF在3D Cad模型中利用TextureCoordinates实现颜色渐变显示偏差值的变化 注:最近在做3D机械模型重建方面的软件,需要根据光栅传感器采集的数据绘制3D图形,并显示出色差以及填充和线框图。
1022 0
|
C#
WPF三维图形
原文:WPF三维图形 wpf 三维图形基础生成三维图形的基本思想是能得到一个物体的三维立体模型(model)。由于我们的屏幕只有二维,因而我们定义了一个用于给物体拍照的照相机(Camera)。拍到的照片其实是物体到一个平坦表面的投影。
1005 0