在VC.net下调用OpenGL的方法
一.相关的Windows Api
OpenGL向渲染上下文(RC)绘制图形,而非设备上下文(DC),所以必须用WinApi把它们关联起来。
要在.net的窗体中调用OpenGL的函数绘图,所使用的Api有六个:
以下三个函数位于"opengl32.dll"中,负责把OpenGL所使用的渲染上下文(RC)和设备上下文关联起来。
HGLRC wglCreateContext(HDC hdc);
BOOL wglDeleteContext(HGLRC hglrc);
BOOL wglMakeCurrent(HDC hdc, HGLRC hglrc);
以下三个函数位于"gdi32.dll"中,负责设置像素格式和交换内存缓冲区。
int ChoosePixelFormat(HDC hdc,PIXELFORMATDESCRIPTOR* pfd);
int SetPixelFormat(HDC hdc,int pf,PIXELFORMATDESCRIPTOR* pfd);
int SwapBuffers(HDC hdc);
在以上这些Api中,使用了句柄HDC和HGLRC,而.net的类库中没有这些类,所以必须对它们重新封装,使其可以在.net编程环境中被调用。
二.用PInvoke封装函数
为了调用上面提到的六个Windows Api,要使用PInvoke技术。所谓PInvoke技术,就是在托管代码中使用非托管的Api。
首先在程序中添加下面的名字空间:
using namespace System::Runtime::InteropServices;
下面对上面提到的六个Windows Api进行封装:
[DllImportAttribute("opengl32.dll")]
extern int wglCreateContext(Int32 hdc);
[DllImportAttribute("opengl32.dll")]
extern bool wglDeleteContext(Int32 hglrc);
[DllImportAttribute("opengl32.dll")]
extern bool wglMakeCurrent(Int32 hdc,Int32 hglrc);
[DllImportAttribute("gdi32.dll")]
extern int ChoosePixelFormat(Int32 hdc,PIXELFORMATDESCRIPTOR* pfd);
[DllImportAttribute("gdi32.dll")]
extern int SetPixelFormat(Int32 hdc,Int32 pf,PIXELFORMATDESCRIPTOR* pfd);
[DllImportAttribute("gdi32.dll")]
extern int SwapBuffers(Int32 hdc);
注意在上面的代码中,我们把句柄封装成int类型,这是因为句柄就是一个指针。
这样,我们就可以在.net的程序中调用这几个Api和OpenGL函数进行绘图。
三.代码示例
下面给出一个简单的代码实例:
新建一个windows窗体应用程序,在窗体的构造函数中加入如下代码:
PIXELFORMATDESCRIPTOR pfd ; //像素格式描述
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1 ; // Version number
pfd.dwFlags = PFD_DOUBLEBUFFER | // Use double buffer
PFD_SUPPORT_OPENGL | // Use OpenGL
PFD_DRAW_TO_WINDOW ; // Pixel format is for a window.
pfd.iPixelType = PFD_TYPE_RGBA ;
pfd.cColorBits = 24; // 8-bit color
pfd.cDepthBits = 32 ; // 32-bit depth buffer
pfd.iLayerType = PFD_MAIN_PLANE ; // Layer type
hdc=this->CreateGraphics()->GetHdc().ToInt32(); //得到设备上下文
int pf = ChoosePixelFormat(hdc, &pfd);
SetPixelFormat(hdc, pf, &pfd);
hglrc = wglCreateContext(hdc); //得到渲染上下文
wglMakeCurrent(hdc,hglrc);
在窗体的Paint事件中加入如下代码:
glClearColor(0.3,0.3,0.3,0.0); //黑色背景
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
int w=this->Width;
int h=this->Height;
glShadeModel(GL_SMOOTH);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0,(GLfloat)w/(GLfloat)h,1.0,25.0); //设置视野
gluLookAt(0.0,5.0,5.0,0.0,-5.0,-5.0,0.0,1.0,0.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
float light_position[]={5.0,5.0,5.0,1.0}; //设置光源
float light_diffuse[]={1.0,1.0,1.0,1.0};
float light_ambient[]={1.0,1.0,1.0,1.0};
float light_specular[]={1.0,1.0,1.0,1.0};
glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient);
glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse);
glLightfv(GL_LIGHT0,GL_SPECULAR,light_specular);
glLightfv(GL_LIGHT0,GL_POSITION,light_position);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
float mat_ambient[]={0.2,0.2,0.2,0.0}; //设置材质属性
float mat_diffuse[]={0.2,0.4,0.9,0.0};
float mat_specular[]={0.2,0.5,0.8,0.0};
glMaterialfv(GL_FRONT,GL_AMBIENT,mat_ambient);
glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_diffuse);
glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);
glMaterialf(GL_FRONT,GL_SHININESS,80.0);
glutSolidTeapot(2.0);
glFlush();
SwapBuffers(hdc);
上面这个代码实例绘制了一个带光照效果的茶壶。