gis
gis
管理员
管理员
  • 注册日期2003-07-16
  • 发帖数15947
  • QQ554730525
  • 铜币25339枚
  • 威望15364点
  • 贡献值0点
  • 银元0个
  • GIS帝国居民
  • 帝国沙发管家
  • GIS帝国明星
  • GIS帝国铁杆
阅读:1070回复:2

OPENGL三维图形绘制讨论

楼主#
更多 发布于:2003-10-22 10:18
----科学计算可视化,计算机动画和虚拟现实是现在计算机图形学的三个热点。而这三个热点的核心都是三维真实感图形的绘制。由于OpenGL(Open GraphicsLibrary)具有跨平台性、简便、高效、功能完善,目前已经成为了三维图形制作方法中事实上的工业标准。自从WindowsNT3.51在微机平台上支持OpenGL以后,现在微软公司在Windows95OSR2、WindowsNT4.0中连续性的提供OpenGL开发环境。VisualC++从4.2 版本以后已经完全支持OpenGL API,使三维世界的"平民化"已成为必然。

----Windows操作系统对OpenGL的支持

----具有Windows编程经验的人都知道,在Windows下用GDI作图必须通过设备上下文(DeviceContext简写DC)调用相应的函数;用OpenGL作图也是类似,OpenGL函数是通过"渲染上下文"(RenderingContext简写RC)完成三维图形的绘制。Windows下的窗口和设备上下文支持"位图格式"(PIXELFORMAT)属性,和RC有着位图结构上的一致。只要在创建RC时与一个DC建立联系(RC也只能通过已经建立了位图格式的DC来创建),OpenGL的函数就可以通过RC对应的DC画到相应的显示设备上。这里还有以下需要注意的方面:

----1.一个线程只能拥有一个渲染上下文(RC),也就是说,用户如果在一个线程内对不同设备作图,只能通过更换与RC对应的DC来完成,而RC在线程中保持不变。(当然,删除旧的RC后再创建新的是可以的)与此对应,一个RC也只能属于一个线程,不能被不同线程同时共享。

----2.设定DC位图格式等于设定了相应的窗口的位图格式,并且DC和窗口的位图格式一旦确定就不能再改变。这一点只能期望以后的Windows 版本改进了。

----3.一个RC虽然可以更换DC,在任何时刻只能利用一个DC(这个DC称为RC的当前DC),但由于一个窗口可以让多个DC作图从而可以让多个线程利用多个RC在该窗口上执行OpenGL操作。

----4.现在的Windows下的OpenGL版本对OpenGL和GDI 在同一个DC上作图有一定的限制。当使用双缓存用OpenGL产生动画时,不能使用GDI函数向该DC作图。

----5.不建议用ANSIC在Windows下编写OpenGL 程序。这样的程序虽然具有跨平台的可移植性(比如很多SGI的例子程序),但是它们不能利用Windows操作系统的很多特性,实用价值不大。

----用VC来编写OpenGL程序

----经过上面的分析,用VC来调用OpenGL作图的方法就很显然了。步骤如下:

----1.先设置显示设备DC的位图格式(PIXELFORMAT)属性。这通过填充一个PIXELFORMATDESCRIPTOR的结构来完成(关于PIXELFORMATDESCRIPTOR 中各项数据的意义,请参照VC的帮助信息),该结构决定了OpenGL作图的物理设备的属性,比如该结构中的数据项dwFlags中PFD_DOUBLEBUFFER位如果没有设置(置1),通过该设备的DC上作图的OpenGL命令就不可能使用双缓冲来做动画。有一些位图格式(PIXELFORMAT)是DC支持的,而有一些DC就不支持了。所以程序必须先用ChoosePixelFormat来选择DC所支持的与指定位图格式最接近的位图格式,然后用SetPixelFormat设置DC的位图格式。

----2.利用刚才的设备DC建立渲染上下文RC(wglCreateContext),使得RC与DC建立联系(wglMakeCurrent)。

----3.调用OpenGL函数作图。由于线程与RC一一对应,OpenGL函数的参数中都不指明本线程RC的句柄(handle)

----4.作图完毕以后,先通过置当前线程的RC为NULL(::wglMakeCurrent(NULL, NULL);),断开当前线程和该渲染上下文的联系,由此断开与DC的联系。此时RC句柄的有效性在微软自己的文档中也没有讲清楚,所以在后面删除RC的时候要先判断以下RC句柄的有效性(if(m_hrc)::wglDeleteContext(m_hrc);)。再根据情况释放(ReleaseDC)或者删除(DeleteDC)DC

----所附程序说明

----所附的程序用MFC完成了一个简单的OpenGL作图,用OpenGL的辅助库画了一个有光照的实心圆球。OpenGL本身的函数这里就不解释了,仅对用MFC编OpenGL时需要注意的内容做一个简要的说明:

----1.一旦设定了一个DC的位图格式,该DC所联系的窗口的位图格式随之设定。该窗口若含有子窗口或者有兄弟窗口,这些兄弟/子窗口的位图格式没有设成与对应RC一致的格式,OpenGL在它们上面作图就容易出错。故而OpenGL作图的窗口必须具有WS_CLIPCHILDREN和WS_CLIPSIBLINGS风格,程序中在主框窗的构造函数中用LoadFrame(IDR_MAINFRAME,WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN|WS_CLIPSIBLINGS,NULL,NULL );指定了主窗口的风格。

----2.在ANSIC的OpenGL编程中,由auxReshapeFunc 定义设置OpenGL视口大小和作图尺寸的回调函数。在MFC中应该由WM_SIZ消息的处理函数来完成。在ANSIC的OpenGL编程中,由EauxMainLoop定义作图的回调函数。在MFC中应该由WM_PAINT 消息的处理函数来处理。相应的,由OpenGL定义的键盘、鼠标处理函数都应该由相应的Windows 处理函数来响应。

----3.OpenGL自己有刷新背景的函数glClear,故而应禁止Windows刷新窗口背景。否则,当窗口需要重画时,Windows会自动先发送WM_ERASEBKGND,而缺省的处理函数使用白色的背景刷。当OpenGL使用的背景颜色不是白色时,作图时有一帧白色的闪烁。这种现象在做动画时特别明显。程序中只需要在WM_ERASEBKGND的消息处理函数中禁止父窗口类的消息处理,简单的返回一个TRUE即可。

----4.由于OpenGL的跨平台性,它必须用操作系统的调色板。所以如果GL_INDEX_MODE作图时,必须用VC自己定义调色板。不过一般情况下,用GL_RGBA_MODE 模式比较方便,很少用到GL_INDEX_MODE模式。

----5.在OpenGL作图期间,RC对应的DC不能删除或者释放。

----6.由于OpenGL作图时需要长时间占用DC,所以最好把作图窗口类设成CS_OWNDC。MFC缺省的窗口类风格中没有设这一属性,程序中在主窗口C++ 类的PreCreateWindow方法中自己注册了一个窗口类,除了设定了CS_OWNDC属性以外,还设定了CS_HREDRAW、CS_VREDRAW和CS_SAVEBITS。设定CS_HREDRAW、CS_VREDRAW是为了让窗口缩放时产生WM_PAINT消息,修正OpenGL视口和作图尺寸;由于OpenGL作图需要很多计算,设定CS_SAVEBITS是为了在OpenGL窗口被遮盖后显现出来时,不产生WM_PAINT消息,用内存存储的图象来填充,从而用空间消耗换取计算时间。

----7.本程序中没有对OpenGL函数的出错情况作出处理。OpenGL出错后返回错误码,不会抛出异常;而且在某一个函数出错以后,后继函数也一般不会出现异常,只是返回错误码,一不小心就可能忽略某些错误。而对每一个OpenGL函数都做出错与否的判断比较麻烦,所以编程序时对OpenGL的函数应当非常小心。

----参考书籍:

----《OpenGLProgrammer'sGuide》SGIinc.

----《OpenGL三维图形程序设计》廖朵朵、张华军著,星球地图出版社

----《VisualC++5.0联机帮助》

----附程序:

----程序运行时必须确定OpenGL32.dll、glu.dll、glaux.dll 在Windows的System目录下。如果找不到这些文件,可以从Windows95OSR2的机器上面将这些文件拷贝过来即可。OpenGL运行不需要注册库信息。在VC的STUDIO中运行程序时,工程文件中必须加入OpenGL.H、glu.h、glaux.h以及OpenGL.lib、glu.lib、glaux.lib,这些文件由VC自带。

----主窗口类定义(OpenGLWnd.h):

s#if!defined(AFX_OPENGLWND_H__3FB1AB28_0E70
_11D2_9ACA_48543300E17D__INCLUDED_)
#defineAFX_OPENGLWND_H__3FB1AB28_0E70_11D2
_9ACA_48543300E17D__INCLUDED_

#if_MSC_VER>=1000
#pragmaonce
#endif//_MSC_VER>=1000

#include
#include"SimpleGLApp.h"
#include"resource.h"
//OpenGLWnd.h:headerfile
//
///////////////////////////////////////
//////////////////////////////////////
//COpenGLWndframe

classCOpenGLWnd:publicCFrameWnd
{
        DECLARE_DYNCREATE(COpenGLWnd)
public:
        COpenGLWnd();
//protectedconstructorusedbydynamiccreation
protected:
        HGLRC                                        m_hrc;
        CClientDC                                *m_pDC;
//Attributes
public:

//Operations
public:

//Overrides
        //ClassWizardgeneratedvirtualfunctionoverrides
        //{{AFX_VIRTUAL(COpenGLWnd)
        protected:
        virtualBOOLPreCreateWindow(CREATESTRUCT&cs);
        //}}AFX_VIRTUAL

//Implementation
public:
        virtual~COpenGLWnd();

        //Generatedmessagemapfunctions
        //{{AFX_MSG(COpenGLWnd)
        afx_msgintOnCreate(LPCREATESTRUCTlpCreateStruct);
        afx_msgvoidOnSize(UINTnType,intcx,intcy);
        afx_msgvoidOnDestroy();
        afx_msgBOOLOnEraseBkgnd(CDC*pDC);
        afx_msgvoidOnPaint();
        //}}AFX_MSG
        DECLARE_MESSAGE_MAP()
};

///////////////////////////////////////
//////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
//MicrosoftDeveloperStudiowillinsert
additionaldeclarationsimmediatelybeforethepreviousline.

#endif//!defined(AFX_OPENGLWND_H__3FB1AB28_
0E70_11D2_9ACA_48543300E17D__INCLUDED_)
主窗口类的实现(OpenGLWnd.cpp):
//OpenGLWnd.cpp:implementationfile
//

#include"stdafx.h"
#include"OpenGLWnd.h"
#include"SimpleGLApp.h"
#include"gl\glu.h"
#include"gl\gl.h"
#include"gl\glaux.h"

#ifdef_DEBUG
#definenewDEBUG_NEW
#undefTHIS_FILE
staticcharTHIS_FILE[]=__FILE__;
#endif

///////////////////////////////////////
//////////////////////////////////////
//COpenGLWnd

IMPLEMENT_DYNCREATE(COpenGLWnd,CFrameWnd)

COpenGLWnd::COpenGLWnd()
{
        m_pDC=NULL;
        m_hrc=0;
        LoadFrame(IDR_MAINFRAME,WS_OVERLAPPEDWINDOW
|WS_CLIPCHILDREN|WS_CLIPSIBLINGS
                ,NULL,NULL);
}

COpenGLWnd::~COpenGLWnd()
{
}


BEGIN_MESSAGE_MAP(COpenGLWnd,CFrameWnd)
        //{{AFX_MSG_MAP(COpenGLWnd)
        ON_WM_CREATE()
        ON_WM_SIZE()
        ON_WM_DESTROY()
        ON_WM_ERASEBKGND()
        ON_WM_PAINT()
        //}}AFX_MSG_MAP
END_MESSAGE_MAP()



BOOLCOpenGLWnd:reCreateWindow(CREATESTRUCT&cs)
{
        //TODO:Addyourspecialized
codehereand/orcallthebaseclass
cs.lpszClass=AfxRegisterWndClass(        CS_DBLCLKS        |
                                        CS_HREDRAW        |
                                        CS_VREDRAW        |
                                        CS_SAVEBITS|
                                        CS_NOCLOSE        |
        CS_OWNDC
                                        ,AfxGetApp()-
>LoadStandardCursor(IDC_ARROW),0,
AfxGetApp()->LoadStandardIcon(IDI_APPLICATION));
        returnCFrameWnd:reCreateWindow(cs);
}


intCOpenGLWnd::OnCreate(LPCREATESTRUCTlpCreateStruct)
{
        if(CFrameWnd::OnCreate(lpCreateStruct)==-1)
                return-1;
        
intpixelformat;

m_pDC=newCClientDC(this);//在客户区作图
        ASSERT(m_pDC!=NULL);

        staticPIXELFORMATDESCRIPTORpfd=
        {
sizeof(PIXELFORMATDESCRIPTOR),//固定值
1,//固定值
PFD_DRAW_TO_WINDOW|//supportwindow
PFD_SUPPORT_OPENGL|//supportOpenGL
PFD_TYPE_RGBA,//RGBA模式,不用调色板
16,//程序在16位色彩下运行
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
};


if((pixelformat=ChoosePixelFormat
(m_pDC->GetSafeHdc(),&pfd))==0)
{
MessageBox("在该DC上找不到与PFD接近的位图结构";
return-1;
}

if(SetPixelFormat(m_pDC->
GetSafeHdc(),pixelformat,&pfd)==FALSE)
{
MessageBox("无法在该DC上设置位图结构";
return-1;
}
m_hrc=wglCreateContext(m_pDC->GetSafeHdc());
wglMakeCurrent(m_pDC->GetSafeHdc(),m_hrc);
        
glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);


glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
        
        return0;//OpenGL窗口构造成功
}

voidCOpenGLWnd::OnSize(UINTnType,intcx,intcy)
{
        CFrameWnd::OnSize(nType,cx,cy);
        
        //TODO:Addyourmessagehandlercodehere
if(cy>0)
{
glViewport(0,0,cx,cy);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
                if(cx<=cy)
        glOrtho(-3.0,3.0,-3.0*(GLfloat)cx/(GLfloat)cy,
                3.0*(GLfloat)cx/(GLfloat)cy,-3.0,3.0);
                else
        glOrtho(-3.0,3.0,-3.0*(GLfloat)cy/(GLfloat)cx,
                3.0*(GLfloat)cy/(GLfloat)cx,-3.0,3.0);
glMatrixMode(GL_MODELVIEW);
}
}

voidCOpenGLWnd::OnDestroy()
{

        CFrameWnd::OnDestroy();
::wglMakeCurrent(NULL,NULL);
if(m_hrc)
::wglDeleteContext(m_hrc);
        if(m_pDC)
deletem_pDC;
        //TODO:Addyourmessagehandlercodehere
}

BOOLCOpenGLWnd::OnEraseBkgnd(CDC*pDC)
{
        //TODO:Addyourmessage
handlercodehereand/orcalldefault
        returnTRUE;
        //returnCFrameWnd::OnEraseBkgnd(pDC);
}

voidCOpenGLWnd::OnPaint()
{
        CPaintDCdc(this);//devicecontextforpainting

        GLfloatlight_position[]={2.0f,0.0f,4.0f,0.0f};
        
        //TODO:Addyourmessagehandlercodehere

glClearColor(0.0f,0.0f,0.0f,1.0f);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

glPushMatrix();

glTranslatef(0.0f,0.0f,-2.0f);
                glLightfv(GL_LIGHT0,GL_POSITION,light_position);
                glEnable(GL_LIGHTING);
                glEnable(GL_LIGHT0);
                glDepthFunc(GL_LESS);
                glEnable(GL_DEPTH_TEST);
                auxSolidSphere(1.0);

glPopMatrix();

glFinish();

        //DonotcallCFrameWnd::OnPaint()forpaintingmessages
}
应用程序类的定义(SimpleGLApp.h):
#if!defined(AFX_SIMPLEGLAPP_H__3FB1AB29
_0E70_11D2_9ACA_48543300E17D__INCLUDED_)
#defineAFX_SIMPLEGLAPP_H__3FB1AB29_0E70
_11D2_9ACA_48543300E17D__INCLUDED_

#if_MSC_VER>=1000
#pragmaonce
#endif//_MSC_VER>=1000
//SimpleGLApp.h:headerfile
//
#include
#include"OpenGLWnd.h"
#include"resource.h"

///////////////////////////////////////
//////////////////////////////////////
//CSimpleGLAppthread

classCSimpleGLApp:publicCWinApp
{
        DECLARE_DYNCREATE(CSimpleGLApp)
public:
        CSimpleGLApp();
//protectedconstructorusedbydynamiccreation

//Attributes
public:

//Operations
public:

//Overrides
        //ClassWizardgeneratedvirtualfunctionoverrides
        //{{AFX_VIRTUAL(CSimpleGLApp)
        public:
        virtualBOOLInitInstance();
        virtualintExitInstance();
        //}}AFX_VIRTUAL

//Implementation
public:
        virtual~CSimpleGLApp();

        //Generatedmessagemapfunctions
        //{{AFX_MSG(CSimpleGLApp)
        afx_msgvoidOnAppExit();
        //}}AFX_MSG

        DECLARE_MESSAGE_MAP()
};

///////////////////////////////////////
//////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
//MicrosoftDeveloperStudiowillinsert
additionaldeclarations
immediatelybeforethepreviousline.

#endif//!defined(AFX_SIMPLEGLAPP_H__3FB1AB29_
0E70_11D2_9ACA_48543300E17D__INCLUDED_)
应用程序类的实现(SimpleGLApp.cpp):
//SimpleGLApp.cpp:implementationfile
//

#include"stdafx.h"
#include"SimpleGLApp.h"
#include"OpenGLWnd.h"

#ifdef_DEBUG
#definenewDEBUG_NEW
#undefTHIS_FILE
staticcharTHIS_FILE[]=__FILE__;
#endif

///////////////////////////////////////
//////////////////////////////////////
//CSimpleGLApp

IMPLEMENT_DYNCREATE(CSimpleGLApp,CWinApp)

CSimpleGLApp::CSimpleGLApp()
{
}

CSimpleGLApp::~CSimpleGLApp()
{
}

BOOLCSimpleGLApp::InitInstance()
{
        //TODO:performandper-threadinitializationhere
        m_pMainWnd=newCOpenGLWnd();
        m_pMainWnd->ShowWindow(m_nCmdShow);
        m_pMainWnd->UpdateWindow();
        returnTRUE;
}

intCSimpleGLApp::ExitInstance()
{
        returnCWinApp::ExitInstance();
}

BEGIN_MESSAGE_MAP(CSimpleGLApp,CWinApp)

//{{AFX_MSG_MAP(CSimpleGLApp)

        ON_COMMAND(ID_APP_EXIT,OnAppExit)
        //}}AFX_MSG_MAP
END_MESSAGE_MAP()

///////////////////////////////////////
//////////////////////////////////////
//CSimpleGLAppmessagehandlers
voidCSimpleGLApp::OnAppExit()
{
        //TODO:Addyourcommandhandlercodehere
        CWinApp::OnAppExit();
}

CSimpleGLAppSimpleGLApp;
喜欢0 评分0
jgh
jgh
路人甲
路人甲
  • 注册日期2003-11-19
  • 发帖数65
  • QQ
  • 铜币202枚
  • 威望0点
  • 贡献值0点
  • 银元0个
1楼#
发布于:2003-11-21 08:48
请问管网纵横断面计算生成图形的编程原理?如何根据MAPX上的线转换计算?
举报 回复(0) 喜欢(0)     评分
gis
gis
管理员
管理员
  • 注册日期2003-07-16
  • 发帖数15947
  • QQ554730525
  • 铜币25339枚
  • 威望15364点
  • 贡献值0点
  • 银元0个
  • GIS帝国居民
  • 帝国沙发管家
  • GIS帝国明星
  • GIS帝国铁杆
2楼#
发布于:2004-11-22 16:50
<P>就是根据你管线的属性来进行了</P><P>算法并不是很复杂</P>
举报 回复(0) 喜欢(0)     评分
游客

返回顶部