WPF中的3D Wireframe

简介: 原文:WPF中的3D Wireframe WPF不支持画三维线,但开发人员提供了ScreenSpaceLines3D 类用于实现这个功能。
原文: WPF中的3D Wireframe

WPF不支持画三维线,但开发人员提供了ScreenSpaceLines3D 类用于实现这个功能。我已经在程序中实现并成功显示3D Wireframe,并能够进行3D Solid和3D Wireframe的切换。

我在熟悉这个类的基础上,自己定义了3D Wireframe xml文件的格式,用于保存3D Wireframe数据。

格式如下:

<Wireframe>
  <ScreenSpaceLines3D
    Form="Generic"
    Color="#00FF00"
    Thickness="1.0"
    Points="1540.681396, 706.149353, 449.837555,  1540.681396, 706.149353, 466.246826" />
  <ScreenSpaceLines3D
    Form="Generic"
    Color="#00FF00"
    Thickness="1.0"
    Points="1460.956909, 792.438416, 51.958309,  1460.877686, 784.031250, 54.853123" />
..................................................

</Wireframe>

然后,解析这个xml文件,遍历points属性,并将每个点按照一定规则加到ScreenSpaceLines3D .Points里面,这样有了点wireframe就有了内容,然后将ScreenSpaceLines3D ._model应用到视图就可以正常显示了。具体方法以后有空再总结。

 

下面是我看到有关wireframe的一些文章,摘录一下。

 

How to Draw WPF 3D Wireframe Graphics

A question I periodically see on forums and discussions with WPF 3D graphics users is, "how do I draw wireframe" content for 3D. This isn't supported out of the box, but couple strategies I would suggest are:

 

  • The out of band 3DTools library from members of the WPF 3D team includes "ScreenSpaceLines" which allows for wireframe rendering of lines.

http://www.codeplex.com/3DTools

  •   Charles Petzold has also posted about wireframe rendering with his own implementation.

 (as below)

 

 

 

As Eric Sink pointed out recently, "WPF 3D doesn't know how to draw lines.". Fortunately, the WPF 3D team at Microsoft has made available the 3DTools library that includes the ScreenSpaceLines3D class that derives from ModelVisual3D and draws lines in a 3D scene. The "screen space" in the name of this class indicates that you specify the thickness of the lines in terms of device-independent units, which are 1/96th inch and hence often pixels.

What's really nice is that the source code to ScreenSpaceLines3D is also available so you can see the clever techniques at work to make this happen: Basically, each line is a pair of triangles arranged in a long thin rectangle. While you specify the begin point and end point of this "line" in 3D coordinates, the ScreenSpaceLines3D class must determine the thickness of this "line" at each end so that after the various transforms have been applied to it (including the camera transforms — see Chapter 7 of my book 3D Programming for Windows) it ends up on the screen with a uniform thickness with a surface that is always oriented perpendicularly to the viewer.

This job requires that ScreenSpaceLines3D know about all the transforms that are applied to the visual because it must invert the transform chain to determine the dimensions and orientation of the line that it renders. What makes this job particularly tricky is that these transforms can be animated. For that reason, ScreenSpaceLines3D installs a handler for the CompositionTarget.Rendering event, and walks the parent/child chain up to Viewport3D on each vertical retrace of the video display. As Eric notes, this is a problem.

I spent a lot of time studying ScreenSpaceLines3D because I knew I wanted to implement something similar in my own Petzold.Media3D library (available here). At one point I derived from Viewport3D specifically to provide support for my "wire" classes (as I began thinking of them), but I eventually abandoned that approach.

Instead, my abstract WireBase class installs a handler for CompositionTarget.Rendering but it does so from a static constructor, so regardless how many WireBase objects you have, there's only one call to this handler per vertical retrace. Each instance of WireBase puts itself into a static collection that the CompositionTarget.Rendering handler enumerates for each call, at that point essentially performing the same logic as ScreenSpaceLines3D. However, if a particular WireBase instance discovers that its chain of visual parents no longer ends in a Window object, then it removes itself from this collection and is abandoned. This is how I hope my implementation is a little less insane than ScreenSpaceLines3D.

I had decided that I would be using XAML files to create all the illustrations in my book. Many of the illustrations were created from 400 DPI bitmaps that I generated from XamlCruncher 2.0. At that resolution, ScreenSpaceLines3D had some limitiations I simply couldn't tolerate. Not only did I need to shamelessly copy the technique of ScreenSpaceLines3D but I had to enhance it.

The "wire" classes I eventually created for the Petzold.Media3D begin with WireBase and are shown here roughly in increasing levels of complexity:

  • Object
       DispatcherObject
          DependencyObject
             Visual3D
                ModelVisual3D
                   WireBase
                      WireLine
                      WireLines
                      WirePolyline
                      WirePath
                      WireText
                      Axes

For me, the most serious problem with ScreenSpaceLines3D was the line joins. Here's a ScreenSpaceLines3D element with a width of 40 device-independent units:

  • <tools:ScreenSpaceLines3D
               Points="-1 0 0, 0 0.5 0, 0 0.5 0, 0.5 0 0"
               Thickness="40" Color="Blue" />

In ScreenSpaceLines3D you set the Points property to an even number of Point3D objects; each pair of points define one line. And here's what it looks like:

It's obviously two lines rather than a connected line. The class in the Petzold.Media3D library that's closest in syntax to ScreenSpaceLines3D is WireLines except the property is named Lines rather than Points:

  • <cp:WireLines Lines="-1 0 0, 0 0.5 0, 0 0.5 0, 0.5 0 0"
                  Thickness="40" Color="Blue" />

The image produced by that markup is the same as the ScreenSpaceLines3D example. However, I've also provided a property in WireBase named Rounding of type int that lets you specify the number of little pie slices used to approximate the rounding of the ends of each line:

  • <cp:WireLines Lines="-1 0 0, 0 0.5 0, 0 0.5 0, 0.5 0 0"
                  Thickness="40" Color="Blue" Rounding="10" />

And now the lines are rendered like this:

You can alternatively use the WirePolyline class and just specify the three points that make up this particular figure:

  • <cp:WirePolyline Points="-1 0 0, 0 0.5 0, 0.5 0 0"
                     Thickness="40" Color="Blue"
                     Rounding="10" />

Or, to draw a single straight line, you can use WireLine and set the Point1 and Point2 properties. The WireBase class also defines ArrowEnds, ArrowLength, and ArrowAngle properties to draw arrows at the end of the line (handy for symbolizing vectors in 3D space.)

Similar to the WPF 2D Path class, my WirePath class has a Data property of type PathGeometry3D, and if you check the Paths directory of the Petzold.Media3D source code, you'll find that my PathGeometry3D class defines a Figures property of type PathFigure3DCollection, and PathFigure3D defines a StartPoint property and a Segments property of type PathSegment3DCollection, and PathSegment3D is parent to the four classes LineSegment3D, PolyLineSegment3D, BezierSegment3D, and PolyBezierSegment3D. In other words, I've tried to duplicate the 2D path geometry classes in 3D. (What I didn't get around to doing was a PathGeometry3DConverter that would let you specify a whole path as an encoded text string, but it's high on my to-do list.)

For example, these classes allowed me to create the following XAML file for a figure in Chapter 6 of 3D Programming for Windows:

LongitudeAndLatitude.xaml

You can run that XAML file in XamlCruncher 2.0 if you have the Petzold.Media3D library loaded, or you can just run an XBAP created from the XAML file:

LongitudeAndLatitude.xbap

It looks like this:

It looks better in the book (page 240) because that image was created at 400 DPI rather than 96 DPI as it is here. (It also looks better on the screen with a Tier 2 graphics board because you get anti-aliasing. You don't get anti-aliasing when you're rendering 3D scenes on bitmaps.) All the lines of longitude and latitude are WirePath objects, but inside is a sphere colored with a translucent brush to make the lines around the back a little less dark.

The WireText text class is based around the polylines from the ancient Windows plotter fonts. You set the Font property to a member of the Font enumeration (Modern, Roman, or Script) and FontSize to an approximate character height in 3D units. Set the Origin property to a Point3D where the text is to begin, and HorizontalAlignment (default is Left) and VerticalAlignment (default is Top) to indicate the meaning of that origin. You'll also need to set two vectors: BaselineDirection (default is (1, 0, 0)) and UpDirection (default is (0, 1, 0)). The cross product of BaselineDirection and UpDirection indicates the direction from which the text appears normal. Set the Text property to the text you wish to display.

The size of the text characters will get smaller as the text recedes to the background, but the actual strokes that make up the characters will not. Those are governed by the Thickness property defined by WireBase.

Finally, the Axes class combines lines and text to display the 3D coordinate axes:

Of course, several properties let you set the Extent of the axes (the default is 3), whether it will ShowNumbers, the length of LargeTick and SmallTick, and you can even replace the Labels from X, Y, and Z to something else, such as shown on page 317 of my book.

The Petzold.Media3D Library: The "Wire" Classes

目录
相关文章
|
C# 容器 异构计算
去除WPF中3D图形的锯齿
原文:去除WPF中3D图形的锯齿       理论上讲PC在计算3D图形的时候是无法避免不出现锯齿的,因为3D图形都是又若干个三角形组成,如果3D图形想平滑就必须建立多个三角形,你可以想象一下正5边形和正100边形哪个更接近圆形的道理一样,这样会大量消耗显卡的存储空间或是从内存共享的存储空间,导致程序的整体性能降低,但如果三角形很少,显卡的解析度毕竟有限,就会出现锯齿。
1366 0
|
C#
WPF 3D动态加载模型文件
原文:WPF 3D动态加载模型文件 这篇文章需要读者对WPF 3D有一个基本了解,至少看过官方的MSDN例子。 一般来说关于WPF使用3D的例子,都是下面的流程: 1.美工用3DMAX做好模型,生成一个obj文件 2.程序然后打开Blender,将obj拖动到Blender中,生成xaml代码   但是这样做会有至少两个问题: 1. 维护麻烦,因为一旦模型修改,你需要重复上面的步骤,至少要修改xaml的代码。
1462 0
|
C#
WPF 3D模型的一个扩展方法
原文:WPF 3D模型的一个扩展方法 在WPF 3D中,我们常常需要改变一个ModelVisual3D对象的颜色。 先说说ModelVisual3D,本质上3D模型都是由一个个的三角形构成的,并且经过材质进行渲染(DiffuseMaterial) 。
859 0
|
前端开发 C#
silverlight,WPF动画终极攻略之番外 3D切换导航篇(Blend 4开发)
原文:silverlight,WPF动画终极攻略之番外 3D切换导航篇(Blend 4开发) 这篇介绍的是3D导航,点击图标,页面360°翻转的效果!有什么不足的欢迎大家指出来。 1.新建一个usercontrol,命名为menu. 2.按照下图设置一下属性。
1218 0
|
C#
WPF 3D 模型旋转
原文:WPF 3D 模型旋转     WPF 是 Microsoft 在 Framework3.0 中支持的一种技术,它能作出很绚丽的界面,同时它也支持3D的操作。在3D操作主要包括平移(Translate)、旋转(Rotation)、缩放(Scale)。
1302 0
|
C#
wpf之3d基础
原文:wpf之3d基础     关于3D方面的东西,本人只是浅尝辄止,从未曾在项目中使用过,相信有不少人也是基于一份兴趣去学习。这里将展示几个基本的WPF 3D编程,希望对初学者有一定帮助。     为帮助理解,这里全部使用C#代码构造,而不是写在XAML中,有兴趣的可以在这里下载源代码。
1015 0
|
C# 索引
#WPF的3D开发技术基础梳理
原文:#WPF的3D开发技术基础梳理 自学WPF已经有半年有余了,一遍用,一边学。但是一直没有去触摸WPF的3D开发相关技术,因为总觉得在内心是一座大山,觉得自己没有能力去逾越。
1295 0
|
C#
使用WPF实现3D场景[一]
原文:使用WPF实现3D场景[一] 在这篇文章里,将介绍如何实现一个简单的三维场景,一个三维的空间,包括空间内的三维物体的组合. 首先介绍一下一个三维场景里的基本元素: 先是定义一个简单的三维的场景环境 代码如下: 以上是定义了一个名称叫做 myViewport 的的三维场景,接下来可以在这个三位场景里添加一些元素: 元素一:照相机 照相机是三维场景内用户的视角,当然照相机也是唯一的。
1494 0
|
C#
使用WPF实现3D场景[二]
原文:使用WPF实现3D场景[二] 在上一篇的文章里我们知道如何构造一个简单的三维场景,这次的课程我将和大家一起来研究如何用代码,完成对建立好了的三维场景的观察。
1078 0
|
C#
WPF利用HelixToolKit后台导入3D模型
原文:WPF利用HelixToolKit后台导入3D模型 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m0_37591671/article/details/75044423 ...
3196 0