-
2022-02-15 10:34:34
2D 容器中的三维:
WPF 中的3D 图形内容封装在一个元素中, Viewport3D 该元素可以参与二维元素结构。 在 WPF 中,图形系统将视为二维 Viewport3D 视觉对象,如许多其他元素。 Viewport3D 作为一个窗口(视区)为一个三维场景。 更准确地说,它是一个在其上投影三维场景的图面。
在传统的2D 应用程序中,可以像使用 Viewport3D 网格或画布这样的其他容器元素一样使用。 虽然您可以 Viewport3D 在同一个场景图中使用与其他2d 绘图对象,但您不能渗透中的2d 和3d 对象 Viewport3D 。 本主题将重点介绍如何在中绘制3D 图形 Viewport3D 。三维坐标空间:
2D 图形的 WPF 坐标系统将原点定位在呈现区域的左上角 (通常是) 屏幕。 在二维系统中,正 x 轴值向右移动,正值 y 轴值向下移动。 但是,在3D 坐标系中,原点位于呈现区域的中心,正 x 轴值前进到右侧,而 y 轴上的正值朝上向右,而从原点向外前进到查看器。照相机和投影:
使用2D 的开发人员习惯于将绘图基元定位在二维屏幕上。 创建三维场景时,务必记住,确实要创建3D 对象的2D 表示形式。 由于三维场景看上去不同,具体取决于旁观者视角的观点,你必须指定该点。 Camera类允许您为三维场景指定此视图点。
了解3D 场景如何在二维图面上表示的另一种方法是将场景描述为查看图面上的投影。 ProjectionCamera允许您指定不同的投影及其属性,以更改旁观者视角查看3d 模型的方式。 PerspectiveCamera指定 foreshortens 场景的投影。 换句话说, PerspectiveCamera 提供消失点透视。 可以指定照相机在场景坐标系中的位置、照相机的方向和视野以及用来定义场景中“向上”方向的矢量。 下图说明了的 PerspectiveCamera 投影。
的 NearPlaneDistance 和 FarPlaneDistance 属性 ProjectionCamera 限制了照相机投影范围。 由于照相机可以位于场景中的任何位置,因此照相机实际上可能会位于模型内部或者紧靠模型,这使正确区分对象变得很困难。 NearPlaneDistance 允许您指定与相机之间的最小距离,超过此值后将不会绘制对象。 相反, FarPlaneDistance 使您可以指定与相机之间的距离,超过此距离将不会绘制对象,从而确保太远的对象不能被识别。主要参数
PerspectiveCamera:透视投影相机,更符合世界实际。
OrthographicCamera:正投影相机,不会出现近大远小的效果。
LookDirection:相机镜头朝向。
UpDirection:相机的上方向是哪里。
Position:相机放在哪里。
AmbientLight(环境光)
DirectionalLight(平行光)
PointLight(点光源)
SpotLight(聚光灯)
Positions中每个点从0开始编号,TriangleIndices中每个整数就是Positions中对应编号的点比如你这个例子中:(0)-2 1 -1,(1) 0 2 0,(2) 2 1 -1,(3) -2 -1 -1,(4) 0 -2 0,(5) 2 -1 -1,所以0 3 1对应的就是(0)(-2, 1, -1)、(3)(-2, -1,-1)、(1)(0, 2, 0)
Material(材质),它可以是纯颜色、渐变颜色、图片等
TextureCoordinates用于描述材质如何贴在平面上3D图形案例:
<Window x:Class="WpfCompreExample._3D" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfCompreExample" mc:Ignorable="d" Title="_3D" Height="450" Width="800"> <Grid> <!-- Place a Label control at the top of the view. --> <Label HorizontalAlignment="Center" TextBlock.TextAlignment="Center" FontSize="20" Foreground="Red" Content="Model: Cone"/> <!-- Viewport3D is the rendering surface. --> <Viewport3D Name="myViewport" > <!-- Add a camera. --> <Viewport3D.Camera> <PerspectiveCamera FarPlaneDistance="20" LookDirection="0,0,1" UpDirection="0,1,0" NearPlaneDistance="1" Position="0,0,-3" FieldOfView="45" /> </Viewport3D.Camera> <!-- Add models. --> <Viewport3D.Children> <ModelVisual3D> <ModelVisual3D.Content> <Model3DGroup > <Model3DGroup.Children> <!-- Lights, MeshGeometry3D and DiffuseMaterial objects are added to the ModelVisual3D. --> <DirectionalLight Color="#FFFFFFFF" Direction="3,-4,5" /> <!-- Define a red cone. --> <GeometryModel3D> <GeometryModel3D.Geometry> <MeshGeometry3D Positions="0.293893 -0.5 0.404509 0.475528 -0.5 0.154509 0 0.5 0 0.475528 -0.5 0.154509 0 0.5 0 0 0.5 0 0.475528 -0.5 0.154509 0.475528 -0.5 -0.154509 0 0.5 0 0.475528 -0.5 -0.154509 0 0.5 0 0 0.5 0 0.475528 -0.5 -0.154509 0.293893 -0.5 -0.404509 0 0.5 0 0.293893 -0.5 -0.404509 0 0.5 0 0 0.5 0 0.293893 -0.5 -0.404509 0 -0.5 -0.5 0 0.5 0 0 -0.5 -0.5 0 0.5 0 0 0.5 0 0 -0.5 -0.5 -0.293893 -0.5 -0.404509 0 0.5 0 -0.293893 -0.5 -0.404509 0 0.5 0 0 0.5 0 -0.293893 -0.5 -0.404509 -0.475528 -0.5 -0.154509 0 0.5 0 -0.475528 -0.5 -0.154509 0 0.5 0 0 0.5 0 -0.475528 -0.5 -0.154509 -0.475528 -0.5 0.154509 0 0.5 0 -0.475528 -0.5 0.154509 0 0.5 0 0 0.5 0 -0.475528 -0.5 0.154509 -0.293892 -0.5 0.404509 0 0.5 0 -0.293892 -0.5 0.404509 0 0.5 0 0 0.5 0 -0.293892 -0.5 0.404509 0 -0.5 0.5 0 0.5 0 0 -0.5 0.5 0 0.5 0 0 0.5 0 0 -0.5 0.5 0.293893 -0.5 0.404509 0 0.5 0 0.293893 -0.5 0.404509 0 0.5 0 0 0.5 0 " Normals="0.7236065,0.4472139,0.5257313 0.2763934,0.4472138,0.8506507 0.5308242,0.4294462,0.7306172 0.2763934,0.4472138,0.8506507 0,0.4294458,0.9030925 0.5308242,0.4294462,0.7306172 0.2763934,0.4472138,0.8506507 -0.2763934,0.4472138,0.8506507 0,0.4294458,0.9030925 -0.2763934,0.4472138,0.8506507 -0.5308242,0.4294462,0.7306172 0,0.4294458,0.9030925 -0.2763934,0.4472138,0.8506507 -0.7236065,0.4472139,0.5257313 -0.5308242,0.4294462,0.7306172 -0.7236065,0.4472139,0.5257313 -0.858892,0.429446,0.279071 -0.5308242,0.4294462,0.7306172 -0.7236065,0.4472139,0.5257313 -0.8944269,0.4472139,0 -0.858892,0.429446,0.279071 -0.8944269,0.4472139,0 -0.858892,0.429446,-0.279071 -0.858892,0.429446,0.279071 -0.8944269,0.4472139,0 -0.7236065,0.4472139,-0.5257313 -0.858892,0.429446,-0.279071 -0.7236065,0.4472139,-0.5257313 -0.5308242,0.4294462,-0.7306172 -0.858892,0.429446,-0.279071 -0.7236065,0.4472139,-0.5257313 -0.2763934,0.4472138,-0.8506507 -0.5308242,0.4294462,-0.7306172 -0.2763934,0.4472138,-0.8506507 0,0.4294458,-0.9030925 -0.5308242,0.4294462,-0.7306172 -0.2763934,0.4472138,-0.8506507 0.2763934,0.4472138,-0.8506507 0,0.4294458,-0.9030925 0.2763934,0.4472138,-0.8506507 0.5308249,0.4294459,-0.7306169 0,0.4294458,-0.9030925 0.2763934,0.4472138,-0.8506507 0.7236068,0.4472141,-0.5257306 0.5308249,0.4294459,-0.7306169 0.7236068,0.4472141,-0.5257306 0.8588922,0.4294461,-0.27907 0.5308249,0.4294459,-0.7306169 0.7236068,0.4472141,-0.5257306 0.8944269,0.4472139,0 0.8588922,0.4294461,-0.27907 0.8944269,0.4472139,0 0.858892,0.429446,0.279071 0.8588922,0.4294461,-0.27907 0.8944269,0.4472139,0 0.7236065,0.4472139,0.5257313 0.858892,0.429446,0.279071 0.7236065,0.4472139,0.5257313 0.5308242,0.4294462,0.7306172 0.858892,0.429446,0.279071 " TriangleIndices="0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 " /> </GeometryModel3D.Geometry> <GeometryModel3D.Material> <DiffuseMaterial> <DiffuseMaterial.Brush> <SolidColorBrush Color="Red" Opacity="1.0"/> </DiffuseMaterial.Brush> </DiffuseMaterial> </GeometryModel3D.Material> </GeometryModel3D> </Model3DGroup.Children> </Model3DGroup> </ModelVisual3D.Content> </ModelVisual3D> </Viewport3D.Children> </Viewport3D> </Grid> </Window>
参考:WPF 3D开发教程(一)_lweiyue的专栏-CSDN博客_wpf3d
全网最全3D模型实例:WPF3D模型综合实例(全网最全实例)-C#文档类资源-CSDN下载
更多相关内容 -
WPF 3D动画实例,3D场景模拟
2021-11-24 10:47:20WPF 3D动画实例,3D场景模拟 -
WPF 3D效果图片墙、翻转等效果.zip
2020-09-12 12:46:38WPF 3D效果图片墙、翻转等效果.,其中包含简单3D效果,良心资源,包含翻转效果、照片墙效果等、都是源码支持二次编辑 -
WPF 3D点云显示
2018-09-14 16:12:12wpf 写的点云显示控件,百万级别的数据秒显示! 可供学习 -
WPF 3D 绘图入门,附源码
2018-11-03 09:45:04包含5个关于WPF 3D 绘图的入门文章和一套WPF 3D绘图工具源代码示例,可以作为WPF 3D绘图初学者的敲门砖。 -
WPF 3D图表
2017-08-28 14:32:12WPF 3D图表 -
WPF3D模型库
2018-01-16 14:00:46一个开源的3D模型库,可打开各种3D模型,如3ds、obj等等 -
WPF3D动画在6轴联动机器人运动控制上的高级应用.rar
2020-05-07 10:39:18使用Viewport3D控件做的机器人运动仿真例子,非常不错,值得学习,转载maomao -
WPF 3D
2021-07-25 12:57:55WPF 3D开发基础知识 坐标系 Coodinate System WPF中二维图形的坐标系将原点定位在呈现区域(通常是屏幕)的左上角。 在二维系统中,x 轴上的正值朝右,y 轴上的正值朝下。而在三维坐标系中,原点位于呈现区域的...WPF 3D开发基础知识
坐标系 Coodinate System
WPF中二维图形的坐标系将原点定位在呈现区域(通常是屏幕)的左上角。 在二维系统中,x 轴上的正值朝右,y 轴上的正值朝下。而在三维坐标系中,原点位于呈现区域的中心,x 轴上的正值朝右,但是 y 轴上的正值朝上,z 轴上的正值从原点向外朝向观察者。传统的二维和三维坐标系表示形式如下图
由这些轴定义的空间是三维对象在 WPF 中的固定参考框架。
当您在该空间中生成模型并创建光源和照相机以查看这些模型时,一定要在向每个模型应用变换时,将固定参考框架或“全局空间”与您为该模型创建的局部参考框架区分开。
另请记住,根据光源和照相机设置,全局空间中的对象可能会看上去完全不同或者根本不可见,但是照相机的位置不会改变对象在全局空间中的位置。
3D的世界都是三角形的王国
如下图:
在3D的世界里所有的东西都是用一些列的“三角形”来描述的。那你一定会问为什么是“三角形”?
原因是三角形是用来描述一个平面的最细微的几何体,渲染引擎能够依据每个三角形的材质以及场景中的灯光角度来计算它的颜色。
其实就是三点确定一个平面,在一个平面上做计算最简单,考虑的因素最少。如果用三维空间中大于三个点来做渲染基本单位,那么如果这些点不在同一个平面上的话,渲染计算是相当复杂的。
3D 对象的表面叫做网格(Mesh),一个网格是由许多3D 点来定义的,这些点叫做顶点(vertices)。这些顶点通过缠绕模式(winding pattern)连接在一起组成一个一个的三角形(facet)(如下图箭头所示)。
三角形(facet)又分为“前”和“后”两面,能看到的部分为前面,看不到的部分为后面。
那怎么判定是前面还是后面?
如果三角形的三个点顺时针方向组成的面那么这个面就是前面。如下图
按照0,1,2的顺序三个点组成了的这个面是上面我们可以看到
目前主流(Direct3D and/or OpenGL)都会把三角形分为两个面(前面和后面)。
为帮助大家记忆(facet)“前面”的三维坐标,大拇指是Z+的方向正对着我们(及前面图示中Up方向),食指是y+方向,而中指是Y+方向。(+表示正数的方向)
WPF 3D的关键元素(Elements)
3D 画布
要画画总的有个画布,WPF中呈现3D也需要一个类似功能的东西。Viewport3D(投影3D场景的平面)是WPF中的3D画布,类于2D中的Canvas。其实WPF中也有一个名字开起来类似的东东Viewbox ,不过和3D没啥关系,它处理的都是2D的。
1
2
3
<
Viewport3D
>
Children…
</
Viewport3D
>
该图形系统将 Viewport3D 视为一个像 WPF 中的许多其他元素一样的二维可视化元素。 Viewport3D充当三维场景中的窗口(即视区)。 更准确地说,它是三维场景所投影到的图面。
相机
处理二维对象的开发人员习惯于将绘图基元置于二维屏幕上。 当您创建三维场景时,一定要记住您实际上是要创建三维对象的二维表示形式。 由于三维场景的外观会因观察者的观察位置不同而异,因此您必须指定观察位置。而观察位置就是由相机(Camera 类)来为三维场景指定的。
另一种理解三维场景在二维图上的描述方法就是,将3D场景投影到一个2D平面的表面。如下图:
接着相机成像原来来帮助理解
当然成像过来还会受到畸变的影响,这里不展开叙述了。
从坐标系的角度来看下我们的ProjectionCamera(透视相机)和3D模型的位置,以及2D 投影屏幕的位置关系:
更详细的图解如下:
ProjectionCamera 的 NearPlaneDistance 和 FarPlaneDistance 属性限制照相机的投影范围。由于照相机可以位于场景中的任何位置,因此照相机实际上可能会位于模型内部或者紧靠模型,这使正确区分对象变得很困难。 通过 NearPlaneDistance,可以指定一个距离照相机的最小距离,超过该距离后即不绘制对象。 相反,使用 FarPlaneDistance,可以指定一个距离照相机的距离(即,在超过该距离后将不绘制对象),从而确保因距离太远而无法识别的对象将不包括在场景中。
对比WPF中两种相机
- PerspectiveCamera 可以指定不同的投影及其属性以更改观察者查看三维模型的方式。
- OrthographicCamera 指定三维模型到二维可视化图面上的正投影与其他照相机一样,它指定位置、观察方向和“向上”方向。 但是,与 PerspectiveCamera 不同的是,OrthographicCamera 描述了不包括透视收缩的投影。或者说OrthographicCamera 描述了一个侧面平行的取景框,而不是侧面汇集在场景中一点的取景框。
下图演示使用PerspectiveCamera 和 OrthographicCamera 查看同一模型时的不同效果。
灯光
和现实生活中一样,如果没有光我们将什么也看不到。因此我们需要在我们的场景中至少放置一盏灯来照亮我们场景中的模型。
WPF中支持不同类型的光源,如下:
AmbientLight(环境光)
它所提供的环境光会照亮所有的对象,而不考虑对象的位置或方向。DirectionalLight(平行光)
像远处的光源那样照亮(如太阳光)。将方向光的 Direction 指定为 Vector3D,但是没有为方向光指定位置。PointLight(点光源)
像近处的光源那样照亮。 PointLight 具有一个位置并从该位置投射光。 场景中的对象是根据对象相对于光源的位置和距离而被照亮的。 PointLightBase 公开 Range 属性,该属性确定一个距离,超过该距离后模型将无法由光源照亮。 PointLight 还公开了多个衰减属性,这些属性确定光源的亮度如何随距离的增加而减小。 您可以为光源的衰减指定恒定、线性或二次内插算法。SpotLight(聚光灯)
从 PointLight 继承。 Spotlight 的照亮方式与 PointLight 类似,但是它既具有位置又具有方向。 它们在 InnerConeAngle 和 OuterConeAngle 属性所设置的锥形区域(以度为单位指定)中投射光。
下图展示了各种光源的情况:
光源是 Model3D 对象,因此您可以转换光源对象并对光源属性(包括位置、颜色、方向和范围)进行动画处理。
组合灯光的效果
- Ambient color : Red
- Difusse color : Red
3D模型
说了半天啦,怎么主角还没出现了 ??
对,所有的一切都服务于我们的3D Model。
Model3D 是三维对象的抽象基类。若要生成三维场景,需要一些要查看的对象,而且构成场景图的对象必须派生自 Model3D。 目前,WPF 支持用 GeometryModel3D 对几何形状进行建模。 此模型的 Geometry 属性采用网格基元。
要生成模型,首先生成一个基元或网格。 三维基元是一系列构成单个三维实体的顶点。 大多数三维系统都提供在最简单的闭合图(由三个顶点定义的三角形)上建模的基元。 由于三角形的三个点在一个平面上,因此您可以继续添加三角形,以便对网格这样较为复杂的形状建模。
WPF 三维系统目前提供 MeshGeometry3D 类,使用该类可以指定任何几何形状;它目前不支持预定义的三维基元(如球体和立方体)。 首先通过将三角形顶点的列表指定为它的Positions 属性来创建 MeshGeometry3D。 每个顶点都指定为 Point3D。 (在可扩展应用程序标记语言 (XAML) 中,将该属性指定为三个一组的数字列表,每组中的三个数字表示每个顶点的坐标)。根据网格的几何形状,网格可能会由多个三角形组成,其中的一些三角形共用相同的角(顶点)。 若要正确地绘制网格,WPF 需要有关哪些顶点由哪些三角形共用的信息。 可以通过指定具有 TriangleIndices 属性的三角形索引列表来提供此信息。 此列表指定在 Positions 列表中指定的点将按哪种顺序确定三角形。
材质(Material )
我们生活在多彩的世界中,也不能让我们的3D模型如此单调,这时我们就用到了材质。
在二维中,可以使用 Brush 类来向屏幕中的区域应用颜色、图案、渐变或其他可视化内容。 但是,三维对象的外观是照明模型的功能,而不只是应用于它们的颜色或图案。 实际对象的图面质量不同,它们反射光的方式也会有所不同:光亮的图面与粗糙或不光滑的图面看上去不同,某些对象似乎可以吸收光,而某些对象似乎能够发光。 您可以向三维对象应用与应用于二维对象的完全相同的画笔,但是您不能直接应用它们。
Material 的具体子类用来确定模型图面的某些外观特征,每个子类还提供一个可以向其传递 SolidColorBrush、TileBrush 或 VisualBrush 的 Brush 属性。
- DiffuseMaterial 使用 DiffuseMaterial 与直接针对二维模型使用画笔非常相似;模型表面不反射光,就好像是自发光一样。使用 DiffuseMaterial 与直接针对二维模型使用画笔非常相似;模型表面不反射光,就好像是自发光一样
- SpecularMaterial 可以通过为 SpecularPower 属性指定一个值来设置系统将为纹理的反射特质(或“发光”)建议的度数。
- EmissiveMaterial 可以指定将应用纹理,就好像模型所发出的光与画笔的颜色相同。这不会使模型成为光源;但是,它参与阴影设置的方式将不同于用 DiffuseMaterial 或 SpecularMaterial 设置纹理时的情况。
为进一步提高性能,可以从场景中精选 GeometryModel3D 的背面(由于它们相对于照相机位于模型的背面,因此您将看不到这些面)。若要指定要应用于模型(如飞机)背面的Material,请设置模型的 BackMaterial 属性。
为了实现某些图面质量(如发光或发射效果),您可能希望向模型连续应用几个不同的画笔。 可以使用 MaterialGroup 类来应用和重用多个 Material。 MaterialGroup 的子级在多个呈现过程中按照从头到尾的顺序来应用。
WPF中3D变换和动画
变换
当您创建模型时,它们在场景中具有固定的位置。为了在场景中移动、旋转这些模型或者更改这些模型的大小而更改用来定义模型本身的顶点是不切实际的。 相反,您可以像在二维模型一样应用转换。
每个模型对象都有一个可用来对模型进行移动、重定向或调整大小的 Transform 属性。 当您应用转换时,实际上是按照由Transform 属性指定的向量或值来偏移模型的所有点。
也就是说变换了定义模型的坐标系(“模型空间”)而模型所在的整个场景的坐标系(“全局空间”)却没有改变,从而实现了3D模型的变换。
动画
WPF 三维实现与二维图形参与同一个计时和动画系统。也就是说,要对三维场景进行动画处理,也就是对其模型的属性进行动画处理。 可以直接对基元的属性进行动画处理,但是通常很容易更改模型位置或外观的变换进行动画处理。 由于可以向 Model3DGroup 对象及其各个模型应用转换,因此可以向 Model3DGroup 中某个对象应用一组动画,也可以向这一组子对象应用一组动画。 还可以通过对场景的照明属性进行动画处理来实现各种可视化效果。 最后,您可以选择通过对照相机的位置或视野进行动画处理来对投影本身进行动画处理。
要对 WPF 中的对象进行动画处理,可以创建时间线、定义动画(实际上是随着时间的推移而更改某个属性值)并指定要向其应用动画的属性。 由于三维场景中的所有对象都是Viewport3D 的子节点,因此要应用于场景的任何动画所面向的属性都是 Viewport3D 的属性。
常用辅助类
通过viewport定义三维模型
在viewport节点下边添加模型,模型对象是modelvisual3d,wpf还有其他模型对象,比如网格等等。
<ModelVisual3D x:Name="ModelEarth" > <ModelVisual3D.Content> <GeometryModel3D Geometry ="{Binding Source={StaticResource MeshBall}, Path=Geometry}"> <GeometryModel3D.Material> <DiffuseMaterial x:Name="SphereMaterial" Brush="{StaticResource ImgBrush.BallSkin.Earth}"/> </GeometryModel3D.Material> <GeometryModel3D.Transform> <RotateTransform3D > <RotateTransform3D.Rotation> <AxisAngleRotation3D x:Name="YRotate" Angle="0"/> </RotateTransform3D.Rotation> </RotateTransform3D> </GeometryModel3D.Transform> </GeometryModel3D> </ModelVisual3D.Content> </ModelVisual3D>
<ImageBrush x:Key="ImgBrush.BallSkin.Earth" ImageSource="../Assets/Earth.jpg"/>
模型表面贴图代码,资源是一张地球图片。
效果如下:
通过HelixToolkit定义三维模型
使用HelixToolkit能够十分方便的创建三维模型和添加鼠标坐标,不需要去实现鼠标旋转动画等等,以及封装了相机,能够方便快捷进行场景控制。
直接贴图代码,
创建三维场景十分快捷,这里我踩了一个坑,就是如果在前台xaml定义了相机,以及相机的up direction position数据,写死了之后,后台是没法改的,这里说的后台是code behind方式,当前如果使用了绑定,那肯定是没问题的,因此我注释掉的相机是因为我在后台控制了相机朝向了亚洲,这样才能生效。
-
WPF3D动画在6轴联动机器人运动控制上的每个自由度可控
2019-02-12 15:19:55WPF 3D动画实例。结合最新的机器人控制技术,使用3D场景模拟机器人的动作轨迹。本例旨在模拟机器人运动控制的内在机制。温馨提示:学习本例需要一定的数学基础。没有基础也没关系,示例中给出了较为详尽的解释。想要... -
WPF 3D照片效果(翻转和预览)
2017-05-22 16:47:57wpf3D效果图片,可以实现大部分的3d效果,包含翻转,预览等一系列3D图片的效果,源码已提供,如有遇到问题,欢迎交流 -
WPF 3D效果登录界面 酷
2018-05-28 07:39:06WPF 登录界面酷炫的演示,完全可以再深入完善,共同打造完美的登录界面,有新的创意,email :li_tone@163.com -
PanoDotNet:使用WPF 3D的交互式全景图查看器,用于等角(360x180°)全景图
2021-02-17 08:39:55全景网 用于等角(360x180度)全景的交互式查看器。 用法 生成并运行该应用程序。 需要.NET Framework 4.5。 使用文件/打开打开图像。 目前仅支持JPG图像。 “示例”文件夹中提供了示例图像。... -
WPF 3D效果
2017-09-20 18:32:11一段c#编写的3D效果模型,界面由WPF开发,主要应用了System.Windows.Controls.Viewport3D。实现效果为点击界面,实现3D翻转效果 -
wpf 3D例子
2018-06-25 14:41:33wpf 3D例子 obj 3D模型 HelixToolkit.dll 导入3D图形 -
WPF 3D特效图片预览.zip
2019-09-17 13:49:54C# WPF 3D特效 图片切换,实现图片的3D动态切换和列表切换交互。 警告:本资料禁止用于商业用途! -
WPF的3D显示 ViewPort3D绘图入门参考资料
2021-11-12 14:55:40该程序是基于HelixToolkit.wpf,实现了3D模型的缩放旋转平移。 -
[WPF系列] WPF 3D编程开发 (英文版)
2013-06-20 16:51:09[Microsoft Press] WPF 3D编程开发 (英文版) [Microsoft Press] 3D Programming for Windows Three-Dimensional Graphics Programming for the Windows Presentation Foundation (E-Book) ☆ 出版信息:☆ [作者... -
WPF动态加载3D模型
2021-06-01 14:13:18WPF动态加载3D模型,支持obj,3ds,stl,fbx等常用模型格式,可旋转,缩放,模型和文件路径下载后自己改 -
WPF 3D 模型实例
2013-01-13 21:42:35WPF 3D学习基础,本人的实例, 本实例包含了多个工程,其中还包含一个Wrapper是本人当时学习 C#、CLR/C++、C++混合编程的例子,这里由于是一个大工程所以就没有 拆分了,如果运行时出现问题请尝试把这工程卸载看。 -
WPF 3D墙图片展示软件 1.0.rar
2019-05-23 15:31:01一款基于WPF开发的3D墙图片展示软件源码,华丽效果,适合初学者使用。主要功能:1、通过滑动鼠标,展示3D墙效果注意事项1、开发环境为Visual Studio 2010,使用.net 3.5开发。 -
[C#]WPF 3D 绘制一个正方体并调整视场角
2022-04-10 15:51:17大部分源码参考Github,是一本名为WPF-3D的书的代码,有条件的可以买下实体书。 文章目录xml写法调整相机视场角cs写法 xml写法 若只是希望新建一个下面这样简单的3D图形,那么只需修改xml就能实现。 其主要分为两个...大部分源码参考Github,是一本名为WPF-3D的书的代码,有条件的可以买下实体书。
本文源码:Cube.zipxml写法
若只是希望新建一个下面这样简单的3D图形,那么只需修改xml就能实现。
其主要分为两个部分,如下面的代码所示,其中
ModelVisual3D
即位集合模型,而<Viewport3D.Camera
则代表相机视角。我们在屏幕上所看到的三维图,实际上是相机拍摄到并转化为二维的图。<Window> <Viewport3D> <Viewport3D.Camera></Viewport3D.Camera> <ModelVisual3D> <ModelVisual3D.Content> <Model3DGroup></Model3DGroup> </ModelVisual3D.Content> </ModelVisual3D> </Viewport3D> </Window>
其中,相机部分主要有四个参数,分别是位置
Position
,视角LookDirection
,视场角FieldOfView
。第四个参数
upDirection
用于规定正向,相当于照片拍出来之后要以哪边为正。<Viewport3D.Camera> <PerspectiveCamera Position = "1.5, 2, 3" LookDirection = "-1.5, -2, -3" FieldOfView = "60" UpDirection = "0, 1, 0"/> </Viewport3D.Camera>
接下来,
Model3DGroup
则表示即将绘制的几何体,其中最重要的当然是GeometryModel3D
,用于规定生成几何体的点。在WPF中,三维图形必须通过面的形式展现出来,而每生成一个面,则需要三个点。也就是说,通过一个又一个的三角形来拼接成几何体的表面。
所以,尽管希望生成一个正方体,但并不可以让正方体边上的四边形作为最小的面元。
在设置好三维图形的几何要素之后,则可设置其表面颜色和光线颜色。其中
DiffuseMaterial
中的Brush
属性记为几何体表面颜色。AmbientLight
和DirectionLight
分别代表背景光和前景光。<Model3DGroup> <!-- Lights --> <AmbientLight Color="Gray" /> <DirectionalLight Color="Gray" Direction="1,-2,-3" /> <GeometryModel3D> <GeometryModel3D.Geometry> <!-- Cube --> <MeshGeometry3D Positions=" -1,-1,-1 1,-1,-1 1,-1, 1 -1,-1, 1 -1,-1, 1 1,-1, 1 1, 1, 1 -1, 1, 1 1,-1, 1 1,-1,-1 1, 1,-1 1, 1, 1 1, 1, 1 1, 1,-1 -1, 1,-1 -1, 1, 1 -1,-1, 1 -1, 1, 1 -1, 1,-1 -1,-1,-1 -1,-1,-1 -1, 1,-1 1, 1,-1 1,-1,-1 " TriangleIndices=" 0 1 2 2 3 0 4 5 6 6 7 4 8 9 10 10 11 8 12 13 14 14 15 12 16 17 18 18 19 16 20 21 22 22 23 20 " /> </GeometryModel3D.Geometry> <GeometryModel3D.Material> <DiffuseMaterial Brush="LightBlue" /> </GeometryModel3D.Material> </GeometryModel3D> </Model3DGroup>
调整相机视场角
和位置、方向这两个参数相比,视场角并不是那么容易理解,毕竟人眼的视场角几乎是恒定的,所以体会不到视场角发生变化所带来的视野的不同。
所以接下来新建一个
slider
来绑定视场角,从而直观地感受一下视场角所带来的差别其代码为
<DockPanel LastChildFill="True"> <WrapPanel DockPanel.Dock="Top"> <Slider Width="200" Value="60" Maximum="170" Minimum="1" x:Name="sAngle"/> <TextBox Text="{Binding ElementName=sAngle,Path=Value, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Margin="0 5" Width="30"/> </WrapPanel> <Viewport3D> </Viewport3D> </DockPanel>
此外,需要将
PerspectiveCamera
中的FieldOfView
改为FieldOfView = "{Binding Value, ElementName=sAngle}"
。cs写法
将代码全部写在
xml
端虽然很便携很直观,但在涉及到某些交互操作时,未必十分灵活。好在任何xml
端的代码都可以写在cs
端// 窗口加载时执行 private void Window_Loaded(object sender, RoutedEventArgs e) { // 定义WPF组件 ModelVisual3D visual3d = new ModelVisual3D(); Model3DGroup group3d = new Model3DGroup(); //对应xaml中ModelVisual3D.Content visual3d.Content = group3d; //visual3d是mainViewport的子控件 mainViewport.Children.Add(visual3d); //定义相机、光线和模型. DefineCamera(mainViewport); DefineLights(group3d); DefineModel(group3d); } // 定义相机 private void DefineCamera(Viewport3D viewport) { Point3D p = new Point3D(1.5, 2, 3); Vector3D lookDirection = new Vector3D(-p.X, -p.Y, -p.Z); Vector3D upDirection = new Vector3D(0, 1, 0); double fieldOfView = 60; //对应PerspectiveCamera的四个参数 PerspectiveCamera camera = new PerspectiveCamera( p, lookDirection, upDirection, fieldOfView); viewport.Camera = camera; } // 定义光线. private void DefineLights(Model3DGroup group) { group.Children.Add(new AmbientLight(Colors.Gray)); Vector3D direction = new Vector3D(1, -2, -3); group.Children.Add(new DirectionalLight(Colors.Gray, direction)); }
接下来是比较复杂的定义模型,其实并不复杂,只是点有点多,如果像写xaml那样写,强迫症可能受不了。
考虑到正方体共有8个顶点,6个面,每个面需要两个三角形,则一共需要12个三角形,总计36组顶点号。
对于每个正方形而言,若生成两个三角形,由于有一条重合的边,故而四个点累计使用6次。若想让点号递增时显得自然一些,则可以让每个面生成四个点,即总计24个点。如此一来,拼接点号为
0,1,2,3
的正方形,只需用到0,1,2
和2,3,0
两组点即可。而正方体的六个面的点的坐标也很有特点,即必有一个坐标轴的分量是不变的,而另外两个坐标轴分量则遍历所有可能的取值。这个逻辑相对来说有些复杂,所以就不改了。
最终得到
cs
代码如下。// 定义模型 private void DefineModel(Model3DGroup group) { // Create the geometry. MeshGeometry3D mesh = new MeshGeometry3D(); // Define the positions. Point3D[] points = { new Point3D(-1, -1, -1), new Point3D(1, -1, -1), new Point3D(1, -1, 1), new Point3D(-1, -1, 1), new Point3D(-1, -1, 1), new Point3D(1, -1, 1), new Point3D(1, 1, 1), new Point3D(-1, 1, 1), new Point3D(1, -1, 1), new Point3D(1, -1, -1), new Point3D(1, 1, -1), new Point3D(1, 1, 1), new Point3D(1, 1, 1), new Point3D(1, 1, -1), new Point3D(-1, 1, -1), new Point3D(-1, 1, 1), new Point3D(-1, -1, 1), new Point3D(-1, 1, 1), new Point3D(-1, 1, -1), new Point3D(-1, -1, -1), new Point3D(-1, -1, -1), new Point3D(-1, 1, -1), new Point3D(1, 1, -1), new Point3D(1, -1, -1), }; foreach (Point3D point in points) mesh.Positions.Add(point); // Define the triangles. Tuple<int, int, int>[] triangles = new Tuple<int, int, int>[12]; for (int i = 0; i < triangles.Length; i++) { int tmp = i%2==0 ? 2 : -2; triangles[i] = new Tuple<int, int, int>( 2 * i, 2 * i + 1, 2 * i + tmp); } foreach (var tup in triangles) { mesh.TriangleIndices.Add(tup.Item1); mesh.TriangleIndices.Add(tup.Item2); mesh.TriangleIndices.Add(tup.Item3); } DiffuseMaterial material = new DiffuseMaterial(Brushes.LightBlue); GeometryModel3D model = new GeometryModel3D(mesh, material); group.Children.Add(model); }
-
将WPF 3D场景的.3ds模型转换为XAML资源
2021-04-11 11:05:14将3D Studio模型文件(.3ds)转换为XAML资源以在WPF 3D客厅场景中使用的教程 -
wpf 3d c#实现三维场景
2021-07-27 22:09:45使用HelixToolkit能够十分方便的创建三维模型和添加鼠标坐标,不需要去实现鼠标旋转动画等等,以及封装了相机,能够方便快捷进行场景控制。 创建三维场景十分快捷,这里我踩了一个坑,就是如果在前台xaml定义了相机... -
WPF3D展示图片.rar
2021-04-07 13:08:48WPF3D展示图片 -
wpf 3d特效集
2016-03-30 19:26:18集合了5大类的wpf资源特效,非常适合wpf的开发者。 -
[C#]WPF 3D 用鼠标控制相机视角
2022-04-15 15:55:54WPF 3D初步 用键盘控制相机视角 部分源码参考Github,是一本名为WPF-3D的书的代码,有条件的可以买下实体书。 文章目录将键盘控制封装成类用鼠标控制视角 将键盘控制封装成类 目前已经实现了通过上下左右和Q、E这六...前情提要
部分源码参考Github,是一本名为WPF-3D的书的代码,有条件的可以买下实体书。
本文源码地址:WPF3D+鼠标控制相机视角+封装成类将键盘控制封装成类
目前已经实现了通过上下左右和Q、E这六个键来调整相机的视角,由于这些功能彼此之间比较集中,按照低耦合、高内聚的原则,封装成一个类是十分合理的。
而这样做的结果就是,让
MainWindow
中的代码大大缩减,只剩下Window_Loaded
、DefineCamera
、DefineLights
、DefineModel
、MakeCubeMesh
这5个自定义的函数。而原本的KeyboardControl_KeyDown
等功能就要移到相机控制类了。最终得到的效果与未封装成类时是完全一样的
其中,与相机相关的函数、成员变量为
private PerspectiveCamera TheCamera = null; // 相机遥控器,CameraController是自定义了一个类 private CameraController cc = null; private void DefineCamera(Viewport3D viewport) { TheCamera = new PerspectiveCamera(); TheCamera.FieldOfView = 60; cc = new CameraController(TheCamera, viewport, this); }
接下来就要写
CameraController
这个类,其成员变量如下// 每次转换的的最小值 public const double cmDR = 0.1; public const double cmDTheta = Math.PI / 30; //相机 public PerspectiveCamera cm = null; // 传入主窗口的动作 private UIElement mainWindow = null; // 相机位置和方向 public Point3D cmPosition { get; set; } = new Point3D(4, 0.5, 5); public double cmTheta = Math.PI * 1.3;
其中,两个常量
cmDR
和cmDThera
分别表示单次移动的距离和角度。例如按一下左箭头,那么当前相机的角度就减少cmDTheta
。构造函数为
public CameraController(PerspectiveCamera camera, Viewport3D viewport,UIElement mainWindow) { cm = camera; viewport.Camera = cm; this.mainWindow = mainWindow; this.mainWindow.PreviewKeyDown += mainWindow_KeyDown; PositionCamera(); }
最后是与按键的交互逻辑,这些内容是上一节已经写过的,就不再详述了
// 将角度转为向量 protected Vector3D AngleToVector(double angle, double length) { return new Vector3D( length * Math.Cos(angle), 0, length * Math.Sin(angle)); } protected void MoveLR(bool isLeft=true) { Vector3D v = AngleToVector(cmTheta, cmDR); if (isLeft) cmPosition += new Vector3D(v.Z, 0, -v.X); else cmPosition += new Vector3D(-v.Z, 0, v.X); } //向上或者向下移动 protected void MoveUD(bool isUp = true) { Vector3D v = AngleToVector(cmTheta, cmDR); if (isUp) cmPosition += v; else cmPosition -= v; } // 其中 上、下、Q、E代表平移 // 左右代表旋转 private void mainWindow_KeyDown(object sender, KeyEventArgs e) { switch (e.Key) { case Key.Left: cmTheta -= cmDTheta;break; case Key.Right: cmTheta += cmDTheta;break; case Key.Up:MoveUD(true);break; case Key.Down: MoveUD(false);break; case Key.Q: MoveLR(true);break; case Key.E: MoveLR(false);break; } // 更新相机位置 PositionCamera(); } // 更新相机的位置 protected virtual void PositionCamera() { cm.Position = cmPosition; cm.LookDirection = AngleToVector(cmTheta, 1); cm.UpDirection = new Vector3D(0, 1, 0); }
用鼠标控制视角
仅从代码的结构来说,用鼠标控制和用键盘控制没有任何区别,区别仅在于二者的返回值是不同的。
所以初始化代码是高度相似的
public CameraController(PerspectiveCamera camera, Viewport3D viewport, UIElement mainWindow) { cm = camera; viewport.Camera = cm; this.mainWindow = mainWindow; //鼠标按下时的动作 this.mainWindow.MouseLeftButtonDown += mainWindow_LeftDown; PositionCameraMouse(); }
最终得到的结果为
其中
mainWindow_LeftDown
就是完成动作的关键,顾名思义,这个函数的触发条件是按下鼠标左键。而其实现的功能则为,在左键已经按下的情况下,拖动鼠标,可实现相机视角的变化,所以这个函数写为private Point ptLast; private void mainWindow_LeftDown(object sender, MouseButtonEventArgs e) { mainWindow.CaptureMouse(); mainWindow.MouseMove += MainWindow_MouseMove; mainWindow.MouseUp += MainWindow_MouseUp; ptLast = e.GetPosition(mainWindow); }
其中,
ptLast
是一个全局变量,用于保存鼠标按下时的位置。MainWindow_MouseMove
是鼠标移动时执行的动作,MainWindow_MouseUp
是鼠标离开时的动作,显然后者更容易实现,而且这种鼠标点击时绑定事件、鼠标松开时解绑事件也是一种非常通用的写法,应用十分广泛,具体写法如下:private void MainWindow_MouseUp(object sender, MouseButtonEventArgs e) { mainWindow.ReleaseMouseCapture(); mainWindow.MouseMove -= MainWindow_MouseMove; mainWindow.MouseUp -= MainWindow_MouseUp; }
MouseMove
写的就是交互功能了,private void MainWindow_MouseMove(object sender, MouseEventArgs e) { const double xscale = 0.1; const double yscale = 0.1; Point newPoint = e.GetPosition(mainWindow); double dx = newPoint.X - ptLast.X; double dy = newPoint.Y - ptLast.Y; CameraTheta -= dx * CameraDTheta * xscale; CameraPhi -= dy * CameraDPhi * yscale; ptLast = newPoint; PositionCameraMouse(); } private void PositionCameraMouse() { double x, y, z; y = CameraR * Math.Cos(CameraPhi); double h = CameraR * Math.Sin(CameraPhi); x = h * Math.Sin(CameraTheta); z = h * Math.Cos(CameraTheta); cm.Position = new Point3D(x, y, z); cm.LookDirection = new Vector3D(-x, -y, -z); cm.UpDirection = new Vector3D(0, 1, 0); }
-
WPF3D动画效果演示(超绚)C#
2013-08-15 16:04:06主要实现图片的浮动以及动态缩放、翻转等效果,例子为3D展示图片墙中,鼠标浮动在图片上与点击图片时所产生的3D动态效果 -
mumu_3DDemo_WPF动画_C#_wpf动画_wpf3D_ground44w
2021-09-11 11:04:19使用C# 3DTools.dll WPF技术实现的 3D建模、透视、动画效果 -
WPF 3D绘图技术_1
2012-06-24 11:35:32WPF 3D绘图技术介绍、和WPF3D控件的使用