WPF绘制深度不同颜色的3D模型填充图和线框图
在机械测量过程中,测量的数据需要进行软件处理。通常测量一个零件之后,需要重建零件的3D模型,便于观察测量结果是否与所测工件一致。
重建的3D模型需要以填充图和线框图两种方式切换显示,其中填充图的材质需要根据不同深度进行着色,线框图需要消隐(不能透视)。以圆柱为例,如下图:
由于WPF对DirectX进行了封装,并构建出一套简单的3D绘图框架,因此我们可以快速的创建所需要的3D模型,便于像我这样的对三维计算机图形学不太了解的人进行开发。
关于WPF 3D绘图的基础,大家可以参考《Practical WPF Charts and Graphics》一书,里面也讲到一些3D显示的计算机图形学和数学基础。
下面我们开始3D模型的构建。
在WPF中,我们可以按如下步骤进行操作:
1、创建一个Viewport3D对象来host 三维模型;
2、继承ModelVisual3D或者ModelUIElement3D来定义3D对象;
3、指定3D场景中的光源,在WPF中光源也是一种ModelVisual3D;
4、创建一个相机来进行3D图形到2D显示器的映射。
根据工程中的经验,我们考虑传感器采集的数据是圆柱体工件的五个截面(实际可能更多或者更少),每个截面包含8192(或者更多)个点,并且是极坐标格式数据。
这里我们使用ModelVisual3D来定义三维物体。其中重要的是三角剖分和材质贴图的部分。由于每一层数据点个数都是一致的,因此我们可以将圆柱体分成三个部分,上下底面和侧面。参考《Practical WPF Charts and Graphics》,我们可以把圆柱的侧面分成多个四边形,每个四边形分成两个三角形,并将上下底面分成多个三角形(类似扇形)。
剖分方式大致如下图:
由于数据点坐标是极坐标,每一层有不同的高度(即三维坐标系中的Y),因此需要将极坐标转化为三维坐标系中的坐标,即Point3D结构,坐标系如下图:
需要注意的是,我们绘制的3D模型是三个曲面构成,每个曲面没有封闭,这样看上去会在首尾相接处出现缺口,因此需要多加一些三角形将首尾进行缝合。未缝合的模型如下:
在三维模型创建结束之后,需要贴上材质,由于工程中需要体现出不同深度(即不同半径 )的差别,需要使用渐变色进行呈现,类似Matlab中的效果
参考我转载的一篇文章(http://blog.csdn.net/congduan/article/details/21092341),就可以得出基本思路:在计算模型的时候,根据不同的R值,生成一张RGB color的映射表,并将其作为材质应用在3D模型上。
参考Codeproject上http://www.codeproject.com/KB/WPF/WPFChart3D.aspx这篇文章的源码,其中的TextureMapping.cs文件便是进行材质颜色映射的类,可以根据需要将多种颜色改写成2种颜色等等,做出适合自己的定制。当然,这个类使用了C#指针(unsafe关键字),需要在项目属性生成一项中开启不安全代码支持。以下是我修改例子,做出的两种颜色的渐变图:
以下便是参考该文例子写出的本文圆柱的代码:
for (int i = 0; i < drawPointCount; i++)
{
for (int j = 0; j < PointCollectionList.Count; j++)
{
//从极坐标构造笛卡尔坐标系数据
points[i, j] = MathHelper.GetPosition(baseRadius +
ZoomContourValue * (PointCollectionList[j][i * interval].Y - fittedCircles[j].Radius) / (maxR - minR),
PointCollectionList[j][i * interval].X,
(j - halfPointCollectionCount) * h,
(Vector3D)Center);
//根据表面半径差值,生成RGB颜色纹理坐标
double u = (PointCollectionList[j][i * interval].Y - minR) / (maxR - minR);
Color color = TextureMapping.PseudoColor(u);
Point mapPt = m_mapping.GetMappingPosition(color);
texcoords[i, j] = new Point(mapPt.X, mapPt.Y);
}
}
注意其中半径都是归一化之后才生成颜色值的。
最后将TextureMapping生成的材质贴到模型上。
//填充表面材质
surfaceModel = new GeometryModel3D(surfaceMeshBuilder.ToMesh(), m_mapping.m_material);
======================================================================
对于线框图(WireFrame),WPF支持的不好,因为WPF中没有3D线段的类,好在微软的人意识到了这一点,开发出开源的3D Tools for WPF(http://3dtools.codeplex.com/)作为补充,其中就有ScreenSpaceLines3D类用于3D线段绘制。这样前面的填充图也可以加上轮廓了。
但是,问题又来了。绘制出的线框图是下面这样的:
由于没有消隐,很多线段交叉重叠在一起,影响判断。《Practical WPF Charts and Graphics》一文中的例子是这样处理的,在前面填充图的基础上加上线框,但是填充的材质改成纯白色,并将线框线条加粗。效果还是不错的,如下:
但是我这样试过之后,发现一些问题,偶尔线条会被填充白色的三角形遮挡住,为了解决这个问题,我找到OpenGL的C#开源封装库,比如OpenTK和SharpGL,其中SharpGL中做如下处理之后会得到较好的效果:
//突出边框,设置多边形偏移
gl.Enable(OpenGL.GL_POLYGON_OFFSET_FILL);
gl.PolygonOffset(1.0f, 1.0f);
//开启反走样
gl.Enable(OpenGL.GL_BLEND);
gl.Enable(OpenGL.GL_LINE_SMOOTH);
gl.Enable(OpenGL.GL_POLYGON_SMOOTH);
gl.Hint(OpenGL.GL_POINT_SMOOTH_HINT, OpenGL.GL_NICEST); // Make round points, not square points
gl.Hint(OpenGL.GL_LINE_SMOOTH_HINT, OpenGL.GL_NICEST); // Antialias the lines
gl.BlendFunc(OpenGL.GL_SRC_ALPHA, OpenGL.GL_ONE_MINUS_SRC_ALPHA);
效果:
可以SharpGL未能很好地利用GPU,将数据全部拷贝到内存中,导致内存暴涨,甚至有时候内存泄露。因此最后放弃了这个库。而OpenTK并没有WPF的控件,只能使用WindowsFormsHost来host WinForm的控件,不是很方便。
后来使用Helix 3D Toolkit,它将WPF和SharpDX进行了再次封装,并提供了一些比较好的3D算法。并使用其中的MeshBuilder更方便地创建三角形和3D线段,最终出现本文开始的效果。
最后,重点提一下线框图中的线段分布的算法。
显示线框图的时候,会绘制一部分竖线,开始考虑的是均匀间隔绘制,但是竖线绘制多少,是一个需要仔细思考的问题。线段多了,损耗性能,线段少了,轮廓的还原度不会搞,尤其是一些凹槽和凸出的部分会因为过于稀疏的线段无法显示出来,如下图的部分:
思考了很久,想到一种比较满意的算法:计算每一层所有数据点的陡变程度,提取前100个(可以根据不同疏密需要的情况进行选取)陡变最大的点绘制竖线。
由于数据点是离散的,可以使用离散曲率刻画点的陡变程度,离散曲率的计算公式如下:
参考论文《一种度量图像像素陡变程度的方法》可以知道,这种连续曲线曲率直接离散化的结果并不是很好,并且该论文提出了一种更好的算法,具体算法大家可以去阅读论文原文。公式如下:
有了这样的评判标准,实现之后变成功将需要的轮廓比较完整地显示了出来。由于数据点很多,计算公式也比较复杂,最好是放入后台线程异步处理,避免UI线程阻塞。
最后,注意大量数据点会造成三角形过多(这里会达到20W个左右),导致构建性能问题突出,最好在保证3D模型还原度高的情况下,进行稀疏处理,减少三角形数量。
WPF绘制深度不同颜色的3D模型填充图和线框图的更多相关文章
- WPF利用HelixToolKit后台导入3D模型
原文:WPF利用HelixToolKit后台导入3D模型 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/m0_37591671/article/de ...
- 基于 HTML5 Canvas 的 3D 模型贴图问题
之前注意到的一个例子,但是一直没有沉下心来看这个例子到底有什么优点,总觉得就是一个 list 列表,也不知道右边的 3d 场景放两个节点是要干嘛,今天突然想起来就仔细地看了一下这个例子的代码,实际操作 ...
- OpenGL编程(七)3D模型的深度(z轴)检测
下图是我们要修改后的效果图: 一.深度检测 1.模型Z轴显示有问题: 上一次试验中,如果认真留意,会发现一个问题.当控制锥体在左右或上下旋转时,你会发现锥体看起来是在+-180度之间来回摆动,而不是3 ...
- WPF 3D模型 3D场景
1.首先得说明的是这并不是真正的3D,模型被导出为一系列的单个图片,例如一个3D户型图,以某个视角旋转360°,渲染出一系列连续的单个图片文件. 2.在Image.MouseMove事件中添加相应代码 ...
- 基础篇:3.4)3d模型绘制的好坏会影响产品合格率(注意点)
本章目的:为了量产品的产能与合格率,重视3d图纸. 1.前言 作者希望本文能引起重视,是那些刚入行业的菜鸟: 还有只用2d图纸,便能绘制出能量产合格品的前辈大牛工程师. 2.3d图纸不合格的现状及典型 ...
- 3ds Max绘制一个漂亮的青花瓷碗3D模型
这篇教程向小伙伴门介绍使用3ds Max绘制一个漂亮的青花瓷碗3D模型方法,教程很不错,很适合大家学习,推荐过来,一起来学习吧! 车削,材质贴图的应用,添加位图,渲染视图 步骤如下: 在桌面找到3DM ...
- WPF程序加入3D模型
原文:WPF程序加入3D模型 版权声明:本文为博主原创文章,转载请附上链接地址. https://blog.csdn.net/ld15102891672/article/details/8006474 ...
- WPF 3D 模型旋转
原文:WPF 3D 模型旋转 WPF 是 Microsoft 在 Framework3.0 中支持的一种技术,它能作出很绚丽的界面,同时它也支持3D的操作.在3D操作主要包括平移(Translate) ...
- WPF 3D模型的一个扩展方法
原文:WPF 3D模型的一个扩展方法 在WPF 3D中,我们常常需要改变一个ModelVisual3D对象的颜色. 先说说ModelVisual3D,本质上3D模型都是由一个个的三角形构成的,并且经过 ...
随机推荐
- eclipse去掉js验证
第一步:去除eclipse的js验证:window->preference->Java Script->Validator->Errors/Warnings->Enabl ...
- Android Widget和悬浮窗 原理
1.简单介绍 Android widget是桌面插件,在android系统应用开发层面有特殊用途. AppWidget是把一个进程的控件嵌入到别外一个进程的窗口里的一种方法.悬浮窗的效果与Widget ...
- 为什么位运算可以实现加法(1、 不考虑进位的情况下位运算符中的异或^可以表示+号)(2、 位运算符中的与运算符&和左移运算符<<可以模拟加法中的进位)(3、位运算不仅可以做加法,还可以做其它的乘法减法等:计算机本质是二进制运算)
为什么位运算可以实现加法(1. 不考虑进位的情况下位运算符中的异或^可以表示+号)(2. 位运算符中的与运算符&和左移运算符<<可以模拟加法中的进位)(3.位运算不仅可以做加法,还 ...
- 序列 mysql
CREATE TABLE emp_seq (seq INT); INSERT INTO emp_seq VALUES(0); UPDATE emp_seq SET seq = LAST_INSERT_ ...
- 指针知识梳理6-const与指针
const 定义的变量为仅仅读变量.在语法层面上通过这个变量去改动内存是不同意的. 可是对于下面代码.就有非常多人绕了: const int *p1; //p1能变.*p1不能变 int cons ...
- js获取滚动条的宽度
function getScrollWidth() { var noScroll, scroll, oDiv = document.createElement("DIV"); oD ...
- 【u215】河床
问题描述 小明是一个地理学家,经常要对一段河流进行测量分析.他从上游开始向下游方向等距离地选择了N个点测量水位深度.得到一组数据d1,d2,--,dn,回到实验室后数据分析员根据需要对数据进行分析,发 ...
- [Javascript] Javascript 'in' opreator
If you want to check whether a key is inside an Object or Array, you can use 'in': Object: const obj ...
- php如何实现把多平台文件中所有的行合成一行?
php如何实现把多平台文件中所有的行合成一行? 一.总结 1.str_replace中的数组替换:str_replace(array("/r","/n",&qu ...
- JM-2 jQuery Mobile的使用(多看学习视频)
JM-2 jQuery Mobile的使用(多看学习视频) 一.总结 一句话总结:前端框架的使用全都一个样,本质都是css和js,引入文件也是这些.使用都是看手册,超简单. 1.jQuery Mobi ...