数值模拟实时三维可视化的C#与OpenGL实现
2009-02-26 08:18:46 来源:WEB开发网1. 引言
当代CFD/NHT等大型数值模拟软件的开发工作在全球范围内进行得如火如荼,但主要的成果集中在国外大型相关专业软件开发商,如ANSYS公司的FLUENT和CFX等。国内,尤其是高校内同类软件的开发应该在计算性能和个性化上寻求创新和突破,如果一味地依赖商用软件,我国与国外先进水平的差距将会越拉越大。
哈尔滨工业大学推进理论与技术研究所开发的HITurbine主要是针对航空以及地面燃气涡轮内部流场的数值模拟而设计开发的,图1为HITurbine的主界面。
图1 HITurbine主界面
由于现有大多已有成熟的数值程序是由Fortran编写的,所以HITurbine考虑并采用了如图2所示系统结构:
C# |
Main Program & Interface |
Fortran |
OpenGL |
Real-time 3D Result Visualization |
Computation Program(DLL) |
Other API |
HPC,etc |
图2 HITurbine系统的结构
2. 实时三维可视化实现
目前,微软公司已推出的DirectX 9.0c中已经包含了一个Managed DirectX程序集,这个程序集为.NET框架下的托管代码提供了访问Direct3D的接口,这使得C#能够方便地编写Direct3D代码[1]。OpenGL目前的进展有些落后,虽然运用C/C++、VB以及Fortran等开发OpenGL程序的技术已经相对成熟(参见文献[2][3]),然而.NET仍没有提供OpenGL API的接口,所以也不存在C#开发OpenGL的标准和规范,这对于擅长界面编写的C#来说,亦可称为一种挑战。
Direct3D的参考书籍和网络资源相当丰富,其中在.NET环境下的开发框架在文献[1][4]中有详细的叙述,而OpenGL的资源则相对少得很多。实质上OpenGL具有平台无关性,利用C#与其实现实时的三维可视化与其它语言没有实质性的差异,关键是要在开发环境下做好相应的配置,下文将对.NET 下三种OpenGL具体配置方式加以讨论。
2.1 C# 直接调用 OpenGL
用C#和OpenGL实现计算实时可视化,最直接的方式就是利用C#调用OpenGL所提供的开发库。但是如前所述,OpenGL所提供的函数均为C接口的API形式,用C#实现要进行类似混合语言编程过程的DLL调用,即调用OPENGL32.DLL、GLU32.DLL以及GLUT32.DLL等。另外,为了体现OOP思想,可新建一个OpenGL调用类,如下clsGL类和clsGLU类分别调用OpenGL和GLU:
using System.Runtime.InteropServices;
public class clsGL {
//OpenGL常量声明
public const uint GL_COLOR_ BUFFER_ BIT = 0x00004000;
public const uint GL_MODELVIEW = 0x1700;
public const uint GL_PROJECTION =0x1701;
…… ……
//函数入口声明
[DllImport("opengl32.dll")]
public static extern void glClear(uint mask);
[DllImport("opengl32.dll")]
public static extern void glBegin(uint mode);
…… ……
}
public class clsGLU {
//OpenGL常量与函数入口声明
…… ……
}
然而OpenGL提供约有250个左右不同的函数,还不包括GLUT等常用的工具库和大量如上所述的OpenGL常量,所以若要在C#中进行DLL调用,可想而知其工作量将是非常大的。所以这种方式虽然直接,但相对以下所述的两种方式较为繁琐,所以在实际运用中少见。
2.2 利用CSOpenGL实现
若利用CSOpenGL实现,则需先将CSOpenGL.dll、CSOpenGLC.dll、mfc70.dll和msvcr70.dll四个文件拷贝到可执行文件目录,当然也可以放到系统文件夹system32下公用。然后进行引用“using CSOpenGL;”即可在.NET环境下进行OpenGL代码编写了。
将绘图的功能模块单独写为一个单独的继承自GLViewPainter类的绘图类,如zPainter,该类中的工作仅仅是对Paint()方法的重构和具体绘图方法的建模。代码框架如下:
public class zPainter : GLViewPainter {
public zPainter() { }
public override void Paint(GLView view)
{
……/* OpenGL初始化, 如glViewport(0, 0, view.Width, view.Height); glMatrixMode(GL_PROJECTION);等 */
drawYourImg (); // Draw Images
glFlush();
}
public void drawYourImg() {
……/* OpenGL初始化,如glEnable(GL_BLEND);等 */
……//Draw Your Images Here
}
通过参数传递和drawYourImg()建模,即可实现绘图类的绘图功能。在图1的主界面中,右侧黑色部分为一个pictureBox控
件,此即为图形绘制表面,可以通过如下代码进行指定:
zPainter nZp = new zPainter();
GLView View = new GLView();
View.Parent = this.pictureBox1;
View.CreateControl();
View.Dock = DockStyle.Fill;
View._OnPaint = new zPainter();
以上代码实现了利用CSOpenGL接口进行C#的三维可视化编程,OpenGL初始化及如纹理及场景绘制等具体绘图方法可以参考[5][6]等。
2.3 利用CsGL实现
CsGL的应用方法在文献[5]中有过叙述。本文将在利用CsGL方面做一些补充,以使得更好地运用其开发程序界面。
利用CsGL时csgl.dll与csgl.native.dll是必须的。将其拷贝到可执行文件运行目录或系统目system32下后,新建一个继承于OpenGLControl的新类,并加以引用“using CsGL.OpenGL;”,然后至少作如下三个重构:
class csglP : OpenGLControl {
public override void glDraw() {
base.glDraw();
……/* OpenGL初始化,如glEnable(GL_BLEND);等 */
GL.glBegin(GLenum mode);
……//Draw Your Images Here
GL.glEnd();
}
protected override void InitGLContext() {
base.InitGLContext();
……/*绘制环境初始化,如GL.glShadeModel(GL.GL_SMOOTH);等 */
}
protected override void OnSizeChanged (EventArgs e) {
base.OnSizeChanged(e);
……/* 窗口大小变化时调用,如GL.glViewport(0, 0, this.Width, this.Height);等 */
}
}
为了实现在指定绘制平面内绘图,可以类似CSOpenGL加入以下代码:
csglP zView = new csglP();
Controls.Add(zView);
zView.Parent = this.pictureBox1;
zView.Dock = DockStyle.Fill;
这样就实现了在.NET环境下的CsGL配置,进而可以在.NET 下编写OpenGL的C#代码。与CSOpenGL相比,CsGL的运用方法更接近OpenGL的C接口方式,但大体上十分相似,只是由于封装得不同,所以对用户来说只是需重构的方法不一样而已,关键的核心绘图代码则是一致的,并且与其它语言也很相似,毕竟OpenGL是平台无关的。用户可以自己通过Object Browser查看和比较这两个接口。
3. 具体实例
为了更加清晰地说明,下面以一个实例的实现过程进行较为具体地解释。
3.1 绘制椭球体
在OpenGL中绘制三维图形,椭球体的绘制相对来说较为简单。本例将以CSOpenGL实现过程为例详细说明其具体绘制过程。
做好2.2中所述的配置后,然后再将drawYourImg()方法改写如下:
public void drawYourImg() {
float[] ambient = { 1.0f, 1.0f, 0.0f, 1.0f };
float[] diffuse = { 1.0f, 1.0f, 1.0f, 1.0f };
float[] specular = { 1.0f, 1.0f, 1.0f, 1.0f };
float[] position = { 1.0f, 1.0f,1.0f, 0.0f };
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
glLightfv(GL_LIGHT0, GL_POSITION, position);
glEnable(GL_LIGHT0);
glEnable(GL_LIGHTING);
gluLookAt(6.0, 6.0, 6.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0);
IntPtr hdc = gluNewQuadric();
gluSphere(hdc, 2.0, 38, 38);
gluDeleteQuadric(hdc); }
接下来如2.2中进行绘制表面制定后,即可在主程序中调用该方法,绘制出如图3所示的椭球体:
图3 利用CSOpenGL实现椭球体绘制
3.2 其它
实际上,利用上述各种方式实现都是大同小异的,不同点仅仅在环境的配置上。3.1是一个最简单的例子,如果建立更加复杂的几何模型(即drawYourImg方法),再通过更多的OpenGL参数控制,可以绘制更加复杂的三维图形,如图4和图5为某型航空涡轮叶片,图中表面曲线为插值结果。本文目的在于C#实现框架的建立,OpenGL具体绘制不是本文的重点,在此不加赘述。其中,图3为线框模型渲染的效果,图4添加了光照效果并以平滑着色。实际应用中可以根据需要还可以应用OpenGL提供的阴影和纹理等效果,渲染出更加令人满意的场景。
图4 某型航空涡轮叶片线框模型渲染效果图
图5使用光照并以平滑着色的渲染效果
通过上文的分析可以发现,利用C#编写OpenGL代码更具吸引力,原因在于其更加简单直观,而且省去了C/C++下的很多如前后台缓存交换问题等等的一系列工作。本文说明了常用的三种实现模式,具体 OpenGL的编程技术在文中没有展开,具体可参见[6]等讲述OpenGL的书籍。利用C#和OpenGL实现计算结果实时三维可视化的关键在于OpenGL绘图方法的建模,本文进行的工作是框架的搭建。具体在应用CSOpenGL或 CsGL两个接口进行三维建模时,只要做好上述的环境配置,就可以在.NET环境下应用C#编写OpenGL代码来实现实时三维可视化了,接下来的工作就是通过参数传递,运用计算所得数据实现实时三维可视化。同时可见,一般的数值模拟软件均可以利用此框架进行快速开发,已使其具有计算结果实时可视化功能。用户还可以根据需要扩展和发展这个框架,例如建立多个监视窗口等,这在.NET下利用C#是很容易实现的。
更多精彩
赞助商链接