MFC+OpenGL 编程入门.docx
《MFC+OpenGL 编程入门.docx》由会员分享,可在线阅读,更多相关《MFC+OpenGL 编程入门.docx(13页珍藏版)》请在冰豆网上搜索。
![MFC+OpenGL 编程入门.docx](https://file1.bdocx.com/fileroot1/2023-1/10/2b946fb0-c709-4782-9b85-b5c5fc49ad1e/2b946fb0-c709-4782-9b85-b5c5fc49ad1e1.gif)
MFC+OpenGL编程入门
标题:
MFC+OpenGL编程入门发信人:
qhchen(老道),信区:
VR_3D
发信站:
BBS水木清华站(MonAug917:
55:
551999)
MFC+OpenGL编程入门
1998-09-08
中国科技大学数学系计算专业老道
E-mail:
qhchen@
OpenGL作图非常方便,故日益流行,但对许多人来说,是在微机上
进行的,首先碰到的问题是,如何适应微机环境。
这往往是最关键的一步,
虽然也是最初级的。
下面介绍如何在VC++上进行OpenGL编程。
其实相当简单明快,只
因国内缺少这方面的资料与例子,致使许多小细节要一个一个地试,耗去
大量时间。
希望各位有什么心得体会,也公布出来,从而节省每个人都要
试试的时间。
言归正传,下面以画一条Bezier曲线为例,详细介绍VC++上OpenGL
编程的方法。
这里实际上也给出了个C++良好封装性编程的范例。
文中给
出了详细注释,以便给初学者明确的指引。
一步一步地按所述去做,你将顺
利地画出第一个OpenGL平台上的图形来。
(本文例子以VC++5.0为背景)
一、产生程序框架Test.dsw
NewProject|MFCApplicationWizard(EXE)|"Test"|OK
*注*:
加“”者指要手工敲入的字串
二、导入Bezier曲线类的文件。
用下面方法产生BezierCurve.h
BezierCurve.cpp两个文件:
WorkSpace|ClassView|TestClasses|<右击弹出>NewClass
|GenericClass(不用MFC类)|"CBezierCurve"|OK
三、编辑好Bezier曲线类的定义与实现。
写好下面两个文件:
BezierCurve.h
BezierCurve.cpp
四、设置编译环境:
1.在BezierCurve.h和TestView.h内各加上:
#include
#include
#include
2.在集成环境中,Project|Settings|Link|Object/librarymodule
|"opengl32.libglu32.libglaux.lib"|OK
五、设置OpenGL工作环境:
(下面各个操作,均针对TestView.cpp)
1.处理PreCreateWindow():
设置OpenGL绘图窗口的风格
cs.style|=WS_CLIPSIBLINGS|WS_CLIPCHILDREN|CS_OWNDC;
2.处理OnCreate():
创建OpenGL的绘图设备。
OpenGL绘图的机制
是:
先用OpenGL的绘图上下文RenderingContext(简称为RC)
把图画好,再把所绘结果通过SwapBuffer()函数传给Window的
绘图上下文DeviceContext(简记为DC).要注意的是,程序运行
过程中,可以有多个DC,但只能有一个RC。
因此当一个DC画完图
后,要立即释放RC,以便其它的DC也使用。
在后面的代码中,将有
详细注释。
intCTestView:
:
OnCreate(LPCREATESTRUCTlpCreateStruct)
{
if(CView:
:
OnCreate(lpCreateStruct)==-1)
return-1;
Init();
return0;
}
voidCTestView:
:
Init()
{
m_pDC=newCClientDC(this);//创建DC
ASSERT(m_pDC!
=NULL);
if(!
bSetupPixelFormat())//设定绘图的位图格式,函数下面列出
return;
m_hRC=wglCreateContext(m_pDC->m_hDC);//创建RC
wglMakeCurrent(m_pDC->m_hDC,m_hRC);//RC与当前DC相关联
}//CClient*m_pDC;HGLRCm_hRC;是CTestView的成员变量
BOOLCTestView:
:
bSetupPixelFormat()
{
staticPIXELFORMATDESCRIPTORpfd=
{
sizeof(PIXELFORMATDESCRIPTOR),//sizeofthispfd
1,//versionnumber
PFD_DRAW_TO_WINDOW|//supportwindow
PFD_SUPPORT_OPENGL|//supportOpenGL
PFD_DOUBLEBUFFER,//doublebuffered
PFD_TYPE_RGBA,//RGBAtype
24,//24-bitcolordepth
0,0,0,0,0,0,//colorbitsignored
0,//noalphabuffer
0,//shiftbitignored
0,//noaccumulationbuffer
0,0,0,0,//accumbitsignored
32,//32-bitz-buffer
0,//nostencilbuffer
0,//noauxiliarybuffer
PFD_MAIN_PLANE,//mainlayer
0,//reserved
0,0,0//layermasksignored
};
intpixelformat;
if((pixelformat=ChoosePixelFormat(m_pDC->m_hDC,&pfd))==0)
{
MessageBox("ChoosePixelFormatfailed");
returnFALSE;
}
if(SetPixelFormat(m_pDC->m_hDC,pixelformat,&pfd)==FALSE)
{
MessageBox("SetPixelFormatfailed");
returnFALSE;
}
returnTRUE;
}
3.处理OnDestroy()
voidCTestView:
:
OnDestroy()
{
wglMakeCurrent(m_pDC->m_hDC,NULL);//释放与m_hDC对应的RC
wglDeleteContext(m_hRC);//删除RC
if(m_pDC)
deletem_pDC;//删除当前View拥有的DC
CView:
:
OnDestroy();
}
4.处理OnEraseBkgnd()
BOOLCTestView:
:
OnEraseBkgnd(CDC*pDC)
{
//TODO:
Addyourmessagehandlercodehereand/orcalldefault
//returnCView:
:
OnEraseBkgnd(pDC);//把这句话注释掉,若不然,Window
//会用白色北景来刷新,导致画面闪烁
returnTRUE;//只要空返回即可。
}
5.处理OnDraw()
voidCTestView:
:
OnDraw(CDC*pDC)
{
wglMakeCurrent(m_pDC->m_hDC,m_hRC);//使RC与当前DC相关联
DrawScene();//具体的绘图函数,在RC中绘制
SwapBuffers(m_pDC->m_hDC);//把RC中所绘传到当前的DC上,从而
//在屏幕上显示
wglMakeCurrent(m_pDC->m_hDC,NULL);//释放RC,以便其它DC进行绘图
}
voidCTestView:
:
DrawScene()
{
glClearColor(0.0f,0.0f,0.0f,1.0f);//设置背景颜色为黑色
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glTranslated(0.0f,0.0f,-3.0f);//把物体沿(0,0,-1)方向平移
//以便投影时可见。
因为缺省的视点在(0,0,0),只有移开
//物体才能可见。
//本例是为了演示平面Bezier曲线的,只要作一个旋转
//变换,可更清楚的看到其3D效果。
//如?
glRotated(30,1.0f,0.0f,0.0f);//绕X轴转30度
//glRotated(30,0.0f,1.0f,0.0f);//绕Y轴转30度
glBegin(GL_LINES);//画坐标系,由三条线段组成
glColor3f(1,0,0);
glVertex3f(0,0,0);
glVertex3f(1,0,0);//X坐标
glColor3f(0,1,0);
glVertex3f(0,0,0);
glVertex3f(0,1,0);//Y坐标
glColor3f(0,0,1);
glVertex3f(0,0,0);
glVertex3f(0,0,1);//Z坐标
glEnd();//enddrawthe3Daxis
//下面画一条Bezier曲线
bezier_curve.myPolygon();//画Bezier曲线的控制多边形
bezier_curve.myDraw();//CBezierCurvebezier_curve
//是CTestView的成员变量
//具体的函数见附录
glPopMatrix();
glFinish();//结束RC绘图
return;
}
6.处理OnSize()
voidCTestView:
:
OnSize(UINTnType,intcx,intcy)
{
CView:
:
OnSize(nType,cx,cy);
VERIFY(wglMakeCurrent(m_pDC->m_hDC,m_hRC));//确认RC与当前DC关联
GLResize(cx,cy);//具体的响应WM_SIZE消息,对投影进行修正
VERIFY(wglMakeCurrent(NULL,NULL));//确认DC释放RC
}
voidGLResize(GLsizeiw,GLsizeih)//GLResize()是一个全局函数
{
//Preventadividebyzero
if(h==0)
h=1;
glViewport(0,0,w,h);//设置视口
glMatrixMode(GL_PROJECTION);//进入投影变换状态
glLoadIdentity();
//重新进行投影变换
gluPerspective(20.0f,(GLdouble)w/(GLdouble)h,1.0,40.0f);
glMatrixMode(GL_MODELVIEW);//结束投影变换
glLoadIdentity();
}
7处理OnLButtonDown()
voidCTestView:
:
OnLButtonDown(UINTnFlags,CPointpoint)
{
CView:
:
OnLButtonDown(nFlags,point);
if(bezier_curve.m_N>MAX-1)
{
MessageBox("顶点个数超过了最大数MAX=50");
return;
}
//以下为坐标变换作准备,
//说明:
OpenGL有一个更有力处理方式,即用gluUnProject()
//这里为了证券交易起见,自己处理。
GetClientRect(&m_ClientRect);//获取视口区域大小
w=m_ClientRect.right-m_ClientRect.left;//视口宽度w
h=m_ClientRect.bottom-m_ClientRect.top;//视口高度h
//w,h是CTestView的成员变量
centerx=(m_ClientRect.left+m_ClientRect.right)/2;//中心位置,
centery=(m_ClientRect.top+m_ClientRect.bottom)/2;//取之作原点
//centerx,centery是CTestView的成员变量
GLdoubletmpx,tmpy;
tmpx=scrx2glx(point.x);//屏幕上点坐标转化为OpenGL画图的规范坐标
tmpy=scry2gly(point.y);
bezier_curve.m_Vertex[bezier_curve.m_N].x=tmpx;//加一个顶点
bezier_curve.m_Vertex[bezier_curve.m_N].y=tmpy;
bezier_curve.m_N++;//顶点数加一
InvalidateRect(NULL,TRUE);//发送刷新重绘消息
}
doubleCTestView:
:
scrx2glx(intscrx)//可能有毛病,因为点到的位置总
{//总画不到,望指正
return(double)(scrx-centerx)/double(h);
}
doubleCTestView:
:
scry2gly(intscry)
{
return(double)(centery-scry)/double(h);
}
附录:
1.CBezierCurve的声明:
(BezierCurve.h)
classCBezierCurve
{
public:
CBezierCurve();
virtual~CBezierCurve();
voidbezier_generation(myPOINT2DP[MAX],intlevel);
//算法的具体实现
voidmyDraw();//画曲线函数
public:
voidmyPolygon();//画控制多边形
myPOINT2Dm_Vertex[MAX];//控制顶点,以数组存储
//myPOINT2D是一个存二维点的结构
//成员为Gldoublex,y
intm_N;//控制顶点的个数
};
2.CBezierCurve的实现:
(BezierCurve.cpp)
CBezierCurve:
:
CBezierCurve()
{
m_N=4;
m_Vertex[0].x=-0.5f;
m_Vertex[0].y=-0.5f;
m_Vertex[1].x=-0.5f;
m_Vertex[1].y=0.5f;
m_Vertex[2].x=0.5f;
m_Vertex[2].y=0.5f;
m_Vertex[3].x=0.5f;
m_Vertex[3].y=-0.5f;
}
CBezierCurve:
:
~CBezierCurve()
{
}
voidCBezierCurve:
:
myDraw()
{
bezier_generation(m_Vertex,LEVEL);
}
voidCBezierCurve:
:
bezier_generation(myPOINT2DP[MAX],intlevel)
{//算法的具体描述,请参考相关书本
inti,j;
level--;
if(level<0)return;
if(level==0)//不要写成level=0!
!
!
{
glColor3f(1.0f,1.0f,1.0f);
glBegin(GL_LINES);//画出线段
glVertex2d(P[0].x,P[0].y);
glVertex2d(P[m_N-1].x,P[m_N-1].y);
glEnd();//结束画线段
return;//递归到了最底层,跳出递归
}
myPOINT2DQ[MAX],R[MAX];
for(i=0;i{
Q[i].x=P[i].x;
Q[i].y=P[i].y;
}
for(i=1;i{
R[m_N-i].x=Q[m_N-1].x;
R[m_N-i].y=Q[m_N-1].y;
for(j=m_N-1;j>=i;j--)
{
Q[j].x=(Q[j-1].x+Q[j].x)/double
(2);
Q[j].y=(Q[j-1].y+Q[j].y)/double
(2);
}
}
R[0].x=Q[m_N-1].x;
R[0].y=Q[m_N-1].y;
bezier_generation(Q,level);
bezier_generation(R,level);
}
voidCBezierCurve:
:
myPolygon()
{
glBegin(GL_LINE_STRIP);//画出连线段
glColor3f(0.2f,0.4f,0.4f);
for(inti=0;i{
glVertex2d(m_Vertex[i].x,m_Vertex[i].y);
}
glEnd();//结束画连线段
}
*************本文结束****************************
--