如何绘制标量场呢?我们常用诸如商业软件Tecplot,或者基于Python的开源软件包matplotlib中的contour绘制Contour图形(等值线)。这里介绍使用显卡GPU绘制Contour,使用flash的stage3D技术,目前而言flash过时了,但它的参考意义仍然在。
显卡是什么,笔者浅薄,先简单认为显卡擅长于画三角形,对三角形进行着色,渲染,加之诸如灯光、迷雾之类的效果。其实三角形是所有图形的基础,我们看到的大千世界也可以近视为若干三角形无缝拼接而成(貌似在画有限元的三角元网格,其实差不多),而每个三角形的顶点颜色各异,三角形内部的颜色是顶点颜色的线性插值(眼熟?和有限元中形函数似的,的确);也可以看作是将眼前的景象拍照,把照片遮挡在眼前看,这是GPU显示的另一种工作方式:贴图,这里不谈。所以我们如何操纵GPU绘制等值图呢?将离散区域分为有限个无缝连接的小三角形,然后用GPU绘制每个三角形即可得到整个域的等值图。下面给予一段网上(http://www.adobe.com/devnet/flashplayer/articles/hello-triangle.html)抄袭来的顶点着色器(Vertex Shader)的Demo,用GPU绘制一个三角形:
1. package
2. {
3. import com.adobe.utils.AGALMiniAssembler;
4.
5. import flash.display.Sprite;
6. import flash.display3D.Context3D;
7. import flash.display3D.Context3DProgramType;
8. import flash.display3D.Context3DVertexBufferFormat;
9. import flash.display3D.IndexBuffer3D;
10. import flash.display3D.Program3D;
11. import flash.display3D.VertexBuffer3D;
12. import flash.events.Event;
13. import flash.geom.Matrix3D;
14. import flash.geom.Rectangle;
15. import flash.geom.Vector3D;
16. import flash.utils.getTimer;
17.
18. [SWF(width="800", height="600",frameRate="60",backgroundColor="#FFFFFF")]
19. public classHelloTriangleColored extends Sprite
20. {
21. protected varcontext3D:Context3D;
22. protected varprogram:Program3D;
23. protected varvertexbuffer:VertexBuffer3D;
24. protected varindexbuffer:IndexBuffer3D;
25.
26. public functionHelloTriangleColored()
27. {
28. stage.stage3Ds[0].addEventListener(Event.CONTEXT3D_CREATE, initMolehill );
29. stage.stage3Ds[0].requestContext3D();
30.
31. addEventListener(Event.ENTER_FRAME, onRender);
32.
33. }
34.
35. protected functioninitMolehill(e:Event):void
36. {
37. context3D= stage.stage3Ds[0].context3D;
38. context3D.configureBackBuffer(800,600, 1, true);
39.
40. var vertices:Vector.<Number> = Vector.<Number>([
41. -0.3,-0.3,0,1, 0, 0, // x, y, z, r, g, b
42. -0.3,0.3, 0, 0, 1, 0,
43. 0.3,0.3, 0, 0, 0, 1]);
44.
45. // Create VertexBuffer3D. 3 vertices, of 6 Numbers each
46. vertexbuffer= context3D.createVertexBuffer(3, 6);
47. // Upload VertexBuffer3D to GPU. Offset 0, 3 vertices
48. vertexbuffer.uploadFromVector(vertices,0, 3);
49.
50. var indices:Vector.<uint> = Vector.<uint>([0, 1, 2]);
51.
52. // Create IndexBuffer3D. Total of 3 indices. 1 triangle of3 vertices
53. indexbuffer= context3D.createIndexBuffer(3);
54. // Upload IndexBuffer3D to GPU. Offset 0, count 3
55. indexbuffer.uploadFromVector(indices, 0, 3);
56.
57. var vertexShaderAssembler : AGALMiniAssembler = new AGALMiniAssembler();
58. vertexShaderAssembler.assemble(Context3DProgramType.VERTEX,
59. "m44 op, va0, vc0\n" + // pos to clipspace
60. "mov v0, va1" //copy color
61. );
62.
63. var fragmentShaderAssembler : AGALMiniAssembler= new AGALMiniAssembler();
64. fragmentShaderAssembler.assemble(Context3DProgramType.FRAGMENT,
65.
66. "mov oc, v0"
67. );
68.
69. program= context3D.createProgram();
70. program.upload(vertexShaderAssembler.agalcode, fragmentShaderAssembler.agalcode);
71. }
72.
73.
74. protected functiononRender(e:Event):void
75. {
76. if ( !context3D )
77. return;
78.
79. context3D.clear( 1, 1, 1, 1 );
80.
81. // vertex position to attribute register 0
82. context3D.setVertexBufferAt(0, vertexbuffer, 0, Context3DVertexBufferFormat.FLOAT_3);
83. // color to attribute register 1
84. context3D.setVertexBufferAt(1,vertexbuffer, 3, Context3DVertexBufferFormat.FLOAT_3);
85. // assign shader program
86. context3D.setProgram(program);
87.
88. var m:Matrix3D = new Matrix3D();
89. m.appendRotation(getTimer()/40, Vector3D.Z_AXIS);
90. context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX,0, m, true);
91.
92. context3D.drawTriangles(indexbuffer);
93.
94. context3D.present();
95.
96. }
97.
98. }
99. }
看不懂吧,正常,第一次接触Flash的3D编程,看不懂太正常了,等你看了他的入门后句会觉得简单,请搜索Molehill Flash。我们现在可以迁移这个技术到HTML5 webGL实现基于HTML5的Contour绘制,本教程目前只提供参考思路。
如此我们可以实现绘制等值图,如下是运行结果。
等等,还缺点什么?Legend,这个漂亮的东西困扰了我好久。2010年秋季,我去宣化做项目,几个老外在现场调试程序,隧围观之,不得不说,人家的用户体验确实到位,使用3D技术显示工业测控值。看到他们的Legend竟然是几段拼接而成,我恍然大悟,原来Legend是几组颜色过渡而成。下面是我曾经写基于Flex SDK有限元前处理和后处理程序包中的一个算法(),函数getGradualColor可以得到一组连续的颜色分布,程序不做解释,可意会,不可言传:
1. packageFEModel.util.visual
2. {
3. public class ColorUtil
4. {
5. public static function combineRGB(r:uint,g:uint,b:uint):uint
6. {
7. if(r<0) r=0
8. if(r>255) r=255;
9.
10. if(g<0) g=0
11. if(g>255) g=255;
12.
13. if(b<0) b=0
14. if(b>255) b=255;
15.
16. var RGB:uint=(r<<16)|(g<<8)|b;
17. return RGB;
18. }
19.
20. public static function getGradualColor(cnt:uint=10):Vector.<uint>
21. {
22. var colorList:Vector.<uint>=new Vector.<uint>(cnt+1,true);
23.
24. for(var i:uint=0;i<cnt+1;i++)
25. {
26. var ratio:Number=i/cnt;
27. if(ratio<=0.25)
28. colorList[i]=colorInR1(ratio);
29. else if(ratio<=0.5)
30. colorList[i]=colorInR2(ratio);
31. else if(ratio<=0.75)
32. colorList[i]=colorInR3(ratio);
33. else
34. colorList[i]=colorInR4(ratio);
35. }
36. return colorList.reverse();
37. }
38.
39. public static function colorInR1(ratio:Number):uint
40. {
41. ratio/=0.25;
42. return combineRGB(255,ratio*255,0);
43. }
44.
45. public static function colorInR2(ratio:Number):uint
46. {
47. ratio=(ratio-0.25)/0.25;
48. return combineRGB((1-ratio)*255,255,0);
49. }
50.
51. public static function colorInR3(ratio:Number):uint
52. {
53. ratio=(ratio-0.5)/0.25;
54. return combineRGB(0,255,ratio*255);
55. }
56.
57. public static function colorInR4(ratio:Number):uint
58. {
59. ratio=(ratio-0.75)/0.25;
60. return combineRGB(0,(1-ratio)*255,255);
61. }
62. }
63. }
给出Legend的绘制结果:
结语:本文简要介绍了基于GPU的Contour图绘制,这里鼓励感兴趣的同学使用HTML5 webGL实现Contour图的绘制。
本文分享自 传输过程数值模拟学习笔记 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!