已阅读5页,还剩12页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第一、准备好OpenGL windows平台下: OpenGL是由SGI公司开发的低层三维图形API,目前已经成为工业标准,由独立非赢利组织ARB管理。它在WINDOWS中以动态链接库的形式存在,Win95 osr2以上版本及Win NT自带有微软公司实现的OpenGL。但本人推荐使用SGI实现的OpenGL来调试程序,快速可靠而且功能丰富,缺点是它是纯软件实现,无法利用硬件加速。 下载了opengl95.exe或opengl2.exe之后执行之,按提示安装即可。默认情况情况下会在C:oglsdk,包括了VC和BC的库及头文件,还有两个演示程序,不妨看看,Fly in the Sky在窗口中移动鼠标就可控制飞行了,还有一份说明书,也不妨看看。 相关文件请到资源区下载 Linux平台下: 装一个Mesa好了,另外在gtk+(GtkGLArea)/qt(QGLWidget+QGLContext)中均包括了OpenGL支持构件(WIDGET),gnome下有许多OpenGL的应用。注意在LD_LIBRARY_PATH加上必要的路径,详见各软件的安装说明(通常叫README或INSTALL)。 Solaris: OpenGL Library 装上随Solaris发售的OpenGL library 。如果执行以下命令: cd /usr/openwin/lib ls libGL* 结果显示如下: libGL.so libGLU.so libGLw.so libGL.so.1* libGLU.so.1* libGLw.so.1* 则意味着OpenGL运行库已经装好了。 通常LD_LIBRARY_PATH里会有该目录,如果没有自己加上就成。 在/usr/openwin/include/GL下有以下头文件: gl.h glu.h glxmd.h glxtokens.h glmacros.h glx.h glxproto.h 在sun的网站有OpenGL开发者FAQ,可参阅。 Mac OS:OpenGL SDK for Apple OS/2:不详。 BeOS:不详。 2*本文的 2.1 - 2.4 部分是针对Borland C+ Builder用户的头文件是OC+5.0以上版本的头文件也行。将C:oglskdbclib下的文件拷至$BCBLib下。为便于编写代码,要将opengl的帮助文件加入搜索范围。在BCB3.0中可用Help|Customize调出OpenHelp设定程序,在每一页中用Edit|Add Files到program filecommonBorland SharedMSHelp下找到必要的文件。说明:系统安装的dll与程序链接时使用的lib要一致,否则像素格式设置调用会失败。2.2、GLUT库为了在初期简化编程负担,可以使用独立于平台的GLUT库,在网上可以找到库、源文件、说明书,基于GLUT的WINDOWS应用程序是WIN32 CONSOL程序,主程序是int main(int,void *),在其中可以只用两三行打开一个窗口,并以填写几个回调函数的方式实现程序功能,省掉了与窗口系统打交道的麻烦。另外,该库是做跨平台应用的首选,它在几乎所有的平台上都可用。目前还没有找到将glut与VCL可视开发结合的方法,所以本教程并没使用它。安装glut运行库:将这些DLL文件(V3.6)(V3.7)复制到windowssystem下,其中有两种版本的dll,分别对应MS(*32.dll)和SGI实现的OpenGL(*.dll)。将其中的glut.h复制到$BCBIncludegl下, 用BCB的implib.exe制作导入库(*.lib),放到$BCBLib下。GLUT使用指南2.3、GLAUX库有一个glaux库(即red Book所用的编程环境),可以大简化窗口界面设定过程,但太过简陋, 不推荐使用。可是为了便于阅读Red Book,现将在BCB中使用glaux的方法简述如下:安装glaux运行库:将BCB版aux库的DLL文件复制到windowssystem下,将其中的glauximp.lib复制到$BCBlib下,或者用BCB的implib.exe制作导入库(*.lib)再复制到$BCBLib下。BCB中已经带有aux库的头文件, aux库的源码在VC中带有。在程序之前加入:USELIB(C:Program FilesBorlandCBuilder3Libglauximp.lib);引号中为导入库所在的位置和名字。GLAUX使用指南 2.4、VCL元件在CBuilder/Delphi环境下还可以使用各种VCL元件,常见的有:下载并展开后,在BCB中加以安装即可,详情请自行查阅其自带的readme,以后有空再逐个解说。本人推荐使用Daniel Plakosh的,简洁易用且带源程序,还可以用BMP格式的图象作纹理。本教程后期将会基于TOpenGLPanel,但前面会用通用的方法,不必借助任何附加元件。Daniel Plakosh said:“ Feel free to whatever you want with the component”说明:该控件对中文支持不灵,另外其内部会自动调用wglMakeCurrent(null,null),所以在OnMouse事件中进行选取时要调用先MakeOpenGLPanelCurrent()。TOpenglPanel安装说明:如果曾经装过老版本的TOpenGLPanel,请先御掉。 在File菜单下选Close All File以关闭所有文件。 在Component菜单下选Install Component。 在Install Component对话框中选Into New Package页 在Inot New Package页中如下填写各项: Unit File Name:填入或浏览(Browse)寻找含路径的单元文件名,如:C:OpenGLv0.3BCB3ComponentTOpenGLPanel.cpp /不必完全相同,就看你把文件放在哪了Search Path:这一条应该会自动填好。如:c:OpenGLv0.3BCB3ComponentPackage File Name:应该填为OpenGLPanel_DPPackage Description:应该填为OpenGL Panel Component 单击OK按纽当提示“Package OpenGLPanel_DP.bpl will be built then installed. Conitnue?”时点“Yes”。 当编译完成后,在File菜单下选Save All,用默认的文件名! 现在OpenGL Panel Component就装好了,你可以在工具栏的最右端发现它。调整BCB3的include及Lib的路径,例如:INCLUDE:$(BCB)include;$(BCB)includevcl;c:dplakoshopenglv0.3bcb3componentLIB:$(BCB)libobj;$(BCB)lib;c:dplakoshopenglv0.3bcb3component/ 不必完全一样,你的文件在哪就填哪$(BCB)代表CBuilder所在目录。在你的系统路径中加入元件所在的目录,以便程序运行。2.5、非Borland C+ Builder用户Borland C+/OWLDelphi /Pascal+APIVisiIt是很好用的,不过封装得太厉害,对于学习者3*如果使用Aux/Glut/VCL则可免去这一步。如果在窗口系统中使用OpenGL则必须给窗口加上WS_CLIPCHILDREN和WS_CLIPSIBLINGS两个属性,否则只能得到黑屏。注:只在MDI应用中需要这样做。在BCB中可在任何窗口控件的CREATEPARAMS成员函数中加入如下语句使之支持OpenGL:/-以TForm为例/-记得在unit1.h中class TForm1的priviate部分加入原型:/-void _fastcall CreateParams(TCreateParams &Params); /-TForm1:CreateParams(TCreateParams &Params)/ 先调用父类中的成员函数,该函数继承自TWindowControl类TForm:CreateParams(Params); Params.Style |= (WS_CLIPCHILDREN | WS_CLIPSIBLINGS); /- 样本工程 所谓窗口控件是指从TWindowControl派生出来的各类控件,通常可见的控件都是窗口件,前面提到过TOpenglPanel就是以TCustomPanel为基类派生的,查看其源码就会发现它对窗口属性的修改与上面所述完全相同。注:这是最简的示例,为使程序在256色等环境中能正常运行,还要在此处理调色板问题4*OpenGL是一种基于客户/服务器和管道(PipeLine)的图形库。即一个应用程序(客户)将各种命令和数据写入管道,这命令和数据将被暂时保存起来,图形库(服务器)直到收到一条专门的指令才会开始处理它们,并将处理结果通过管道传给用户。 所以OpenGL应用程序的基本结构就是: 建立管道根据需要向管道中写入数据和指令关闭管道在Windows95/NT环境中,这个管道就是OpenGL着色环境(OpenGL Render Context)简称RC。因此建立管道实际上就是获取一个可用的RC。而在Windows的GDI系统中进行图形显示是通过图形设备上下文(Device Context)简称DC进行的。所以获取RC就是: 先获取一个DC, 调整这个DC的象素格式(PixelFormat)以便OpenGL库进行绘制, 用DC去调用wglCreateContext(hDC)建立一个RC, 调用wglMakeCurrent(hRC,hDC)将刚才建立的RC指定为当前的RC。当一个RC不再使用时就可以删除它,方法是:使RC不是“当前RC”: wglMakeCurrent(NULL,NULL); /不再有当前RC wglMakeCurrent(hAnotherRC,hDC); /另一个RC成为当前RC wglDEleteContent(hRC); /删除之为了避免反复建设/删除RC所带来的不必要的开支,我们在TForm1中定义了hDC、hRC以保存DC和RC,并在TForm1的构造函数中建立并保存RC,直到清除这个Form即Destory()成员函数运行时才删除RC和DC。主要代码如下:void _fastcall TForm1:CreateParams(TCreateParams& Params) /再次说明:只在MDI应用有必要进行修改。2000.2.17. TForm:CreateParams(Params); /调用原有函数预处理Params.Style|=WS_CLIPCHILDREN|WS_CLIPSIBLINGS;/加上必要的属性 /- _fastcall TForm1:TForm1(TComponent* Owner) : TForm(Owner) hDC=GetDC(Handle); /获取一个DC,TForm1.Handle中保存有Form的窗口句柄SetDCPixelFormat(hDC); /调整该DC的象素格式hRC=wglCreateContext(hDC); /用这种DC去创建一个RC wglMakeCurrent(hDC,hRC); /指定当前DC、当前RC为hDC、hRC /- void _fastcall TForm1:SetDCPixelFormat(HDC hDC) /本函数用于调整DC的象素格式,如缓冲区、颜色数等/先不深究,只要知道它的作用就行 int nPixelFormat; static PIXELFORMATDESCRIPTOR pfd = sizeof(PIXELFORMATDESCRIPTOR),/ Size of this structure 1,/ Version of this structure PFD_DRAW_TO_WINDOW |/ Draw to Window (not to bitmap) PFD_SUPPORT_OPENGL |/ Support OpenGL calls in window PFD_DOUBLEBUFFER/ Double buffered mode PFD_TYPE_RGBA,/ RGBA Color mode 24,/ Want 24bit color 0,0,0,0,0,0,/ Not used to select mode 0,0,/ Not used to select mode 0,0,0,0,0,/ Not used to select mode 32,/ Size of depth buffer 0,/ Not used to select mode 0,/ Not used to select mode PFD_MAIN_PLANE,/ Draw in main plane 0,/ Not used to select mode 0,0,0 ;/ Not used to select mode / Choose a pixel format that best matches that described in pfd nPixelFormat = ChoosePixelFormat(hDC, &pfd); / Set the pixel format for the device context SetPixelFormat(hDC, nPixelFormat, &pfd); /- void _fastcall TForm1:FormPaint(TObject *Sender) /该Form的绘制响应函数 glClearColor(0.5,0.7,0.9,1.0); /指定背景颜色(依次为RGBA) glClear(GL_COLOR_BUFFER_BIT); /用背景色清窗口 RenderScence();/场景绘制 SwapBuffers(hDC); /切交缓冲区,这就是可以启动图形库处理流程并得相应结果的两条命令之一/如果当前RC相联DC具有DoubleBuffer的PixelFormat则用本命令/否则就是单缓冲DC,用glFlush(void)进行更新。 /- void _fastcall TForm1:FormDestroy(TObject *Sender) wglMakeCurrent(NULL,NULL);/取消当前RC和当前DC wglDeleteContext(hRC);/删除该RC DeleteObject(hDC);/删除Windows DC。 /- 5*如果用过3DS/LIGHTWAVE等任何一种三维图形软件包,就可以发现制作一个三维场景无非以下几项工作: 建模:制作各种物体。放置:将做好的各物体通过平移、旋转等放到场景空间的适当位置。上色:给物体模型指定颜色或表面纹理。打灯:在场景中适当位置放置几盏灯以照亮场景。摄像:在空间适当位置放上适当角度的摄像机,以得到所需的视觉效果。用OpenGL开发应用程序与之类似,通常是:设定视见体定义光源生成场景而三维图形生成的流程如下:放置几何变换:平移、旋转、缩放等视见变换:裁剪、消隐、投影等视见体设定:视见体有两种:正投影体和透视投影体,正投影视见体中的物体在屏幕上的投影不会出现近大远小的现象,而透视投影视体则与人眼的观察结果类似,离观察点越远的物体在屏幕上的投影越小,因此透视投影体中的观察结果看起来更真实一些。定义透视投影体的方法是:glFrustum(left,right,bottom,top,near,far);/物体在这六个参数界定的范围内可见,超出边界将被裁掉。/left,bottom,代表左下 right,top代表右上定义透视投影体的方法是:glOrtho(left,right,bottom,top,near,far);/物体在这六个参数界定的范围内可见,超出边界将被裁掉。综上所述,一个三维图形应用程序在建好OpenGL Pipleline之后就要向管道发如下一系列的命令,以建立一个三维观察环境:/1、设定视见体,在窗体的Resize事件时void _fastcall TForm1:FormResize(TObject *Sender) glViewport(0, 0, Width, Height); /使用Form窗体的指定区域为显示区 /如改为Width/4,Height/4,Width/2,Width/2, /则只用Form1的-窗体的中间1/4进行显示 glMatrixMode(GL_PROJECTION); /切换到投影矩阵栈 glLoadIdentity(); /清除投影矩阵 glFrustum(1.0,-1.0,-1.0,1.0,1.0,-1.0); /指定透视视见体范围 /超出部分将被裁去 /或正投影glOrtho(1.0,-1.0,-1.0,1.0,1.0,-1.0); glMatrixMode(GL_MODELVIEW); /切换到模型视见矩阵栈 glLoadIdentity(); /清除视见矩阵6*OpenGL中从三维场景到屏幕图形要经历如下所示的变换过程: 其中四种坐标经常要在程序中用到:世界坐标,物体坐标,设备坐标和眼坐标。世界坐标是OpenGL中用来描述场景的坐标,Z+轴垂直屏幕向外,X+从左到右,Y+轴从下到上,是右手笛卡尔坐标系统。我们用这个坐标系来描述物体及光源的位置。将物体放到场景中也就是将物体平移到特定位置、旋转一定角度,这些操作就是坐标变换。OpenGL中提供了glTranslate*/glRotate*/glScale*三条坐标变换命令,利用OpenGL的矩阵运算命令,则可以实现任意复杂的坐标变换。非常重要:OpenGL中有一个坐标变换矩阵栈(ModelView),栈顶就是当前坐标变换矩阵,进入OpenGL管道的每个坐标(齐次坐标)都会先乘上这个矩阵,结果才是对应点在场景中的世界坐标。OpenGL中的坐标变换都是通过矩阵运算完成的,与图形学课本的描述完全一致。要注意的是变换中的矩阵乘法是左乘,而矩阵乘法与算术乘法不同,不符合交换律(万一不明白去看矩阵代数书好了)。glTranslate*(x,y,z):平移,参数为各轴向的移动量。glRotate(d,x,y,z):旋转,第一个参数为转动的度数,后三个参数表明是否绕该轴旋转。通常x,y,z中只有一个为1,其余为0,用连续几条旋转命令完成复杂旋转。由于矩阵运算的左乘特点,旋转命令的顺序与旋转动作的顺序正好相反。物体坐标是以物体某一点为原点而建立的“世界坐标”,该坐标系仅对该物体适用,用来简化对物体各部分坐标的描述。物体放到场景中时,各部分经历的坐标变换相同,相对位置不变,所以可视为一个整体,与人类的思维习惯一致。眼坐标是以视点为原点,以视线的方向为Z+轴正方向的坐标系中的方向。OpenGL管道会将世界坐标先变换到眼坐标,然后进行裁剪,只有在视线范围(视见体)之内的场景才会进入下一阶段的计算。同样的,有投影变换矩阵栈(Projection),栈顶矩阵就是当前投影变换矩阵,负责将场景各坐标变换到眼坐标,由所得到的结果是裁剪后的场景部分,称为裁剪坐标。前面提到过的视见体设定其实就是在建立该矩阵。OpenGL的重要功能之一就是将三维的世界坐标经过变换、投影等计算,最终算出它在显示设备上对应的位置,这个位置就称为设备坐标。在屏幕、打印机等设备上的坐标是二维坐标。值得一提的是,OpenGL可以只使用设备的一部分进行绘制,这个部分称为视区或视口(viewport)。投影得到的是视区内的坐标(投影坐标),从投影坐标到设备坐标的计算过程就是设备变换了。矩阵栈切换:glMatrixMode(GL_MODELVIEWING或GL_PROJECTION);本命令执行后参数所指矩阵栈就成为当前矩阵栈,以后的矩阵栈操纵命令将作用于它。矩阵栈操纵命令:glPushMatrix(); 当前矩阵入栈,这时矩阵栈将栈顶值压入栈。glPopMatrix(); 栈顶出栈,通常与上一条命令配合使用。glLoadIdentity(); 将栈顶设为不变矩阵(就是对角线全为1其它为0的那个)。glMultMatrix(M);将栈顶T设为M?T。7*OpenGL中的物体是用面边界模型来描述的。我们将物体表面分割成许多个平面,记录面的形状、颜色、纹理,OpenGL根据这些参数再把这些个面绘制出来,我们就能在场景中看到立体的实体了。物体模型最基本的参数是它的形状,形状可以用表面来记录。而记录面的边缘就能描述面的形状。描述边缘的方法是记录边上所有线段的端点。所以用面边界模型描述物体形状的核心就是记录物体表面所有的顶点。这些顶点按所在边的顺序排列起来就能描述一个平面,许多的平面就能表示一个物体的表面,显然平面越多形状越逼真。OpenGL中描述一个顶点的方法是指定其坐标和属性,命令是:glVertex*(Coordination);该命令以参数指定的坐标和当前颜色、纹理坐标、法向等属性定义一个顶点。OpenGL中描述一个面的方法是glBegin/glEnd命令组:glBegin(形状);glVertex(顶点1);glVertex(顶点2);glEnd();OpenGL支持点(GL_POINTS)、线段(GL_LINES)、三角形(GL_TRIANGLES)、四边形(GL_QUADS)、多边形(GL_POLYGON)。可以在一个begin/end对中定义多个同一类型的平面,如在glBegin(GL_TRIANGLES);与glEnd();之间输入11个顶点,则会形成3个三角形,最后两个顶点则被舍弃。OpenGL还支持平面带(STRIP)和平面扇(FAN)。扇:在glBegin(GL_TRIANGLE_FAN);/glEnd();间输入若干顶点,则第一个顶点做为共同的顶点,第二、三个做为底边定义一个三角形,此后的每个顶点与前一个顶点做为底边定义一个三角形,所以11个顶点就会定义9个共顶点的三角形,这些三角形将形成一个扇形。带:输入顶点编号为123456789;定义的三角形为132 243 354 465 567,相邻三角形共用一条边,形成一条带状;依此类推,定义的四边形为1243 3465 5687。实际使用中,可用3ds max/softimage/maya之类的工具以直观的方式建立物体模型保存成文件,然后再用专门的解码工具将模型转换成一系列的顶点。解码工具有三类:插件、工具软件、程序库。目前已经有许多的代码库可以解析多种格式的三维场景,如果还没有合适的还也可以自己编写。3ds max带有一个简单的.asc导出器,但功能很弱,而3dxexp则强大得多,要是不满意还可以自己写,这就得学习学习MAX SDK了。使用3ds2c之类的工具将模型转换为C代码是非常简便的一种方法,但从效率方面考虑,并不是最好的,特别是象PolyTrans之类的软件会为每个面生成一个Begin/End,象下面的这个模型,.3ds文件只有978K,而转换得到的.C文件却有6.8M之巨。稍好一点的办法是充分利用STRIP或使用VertexPointer技术,或者利用wc2pov之类的工具将转换后的多边形数据保存在文件中,使用时再调入;还有一种办法就是view3ds所用的将场景转化为编译后的glList保存起来,在使用时装入系统直接调用,速度非常快。 T_FIGHTER(Hight detail)根本的解决办法还是针对自己的应用设计优化的文件格式,并制作配套的编码、解码库。处理各种格式三维文件的程序库非常多,到网上随便搜搜就能找到一大把。目前俺最喜欢的是GLScene(类示意图1 2 3),它内建树形场景支持,可解析.3ds文件和.md2文件,可扩展性极好,可惜只有delphi版本。8*OpenGL中使用RGBA色彩体系,RGB为红绿蓝三原色,A为值,该值代表色彩融合时所占的比例。颜色是顶点的重要属性之一,没有色彩的世界是毫无生气的。使用glColor*(R,G,B,A);设定当前颜色,此后定义所有的顶点都将是这个颜色的,直到再次改变当前颜色。该命令有两种常用形式glColor*f和glColor*ub,后者可以直接使用GetRValue(pixel)取得的颜色分量作为参数。下面左边的代码就可以生成右边漂亮的三角形: glBegin(GL_TRIANGLES);glColor3f(1.0,0.0,0.0);glVertex3f(-1.0,0.0,0.0);glColor3f(0.0,1.0,0.0);glVertex3f(0.0,1.0,0.0);glColor3f(0.0,0.0,1.0);glVertex3f(1.0,0.0,0.0);glEnd();可以看出,相邻顶点之间的部份也会有颜色,实际上OpenGL会在顶点之间进行插值分割,最终计算出对应光栅每一点的颜色,这个计算结果就是最终显示在屏幕上的图像。也许上边的代码和文字暗示你给顶点指定的颜色就是屏幕图像上显示的颜色,其实最终的颜色取决于多个因素:顶点材质、法线方向、光照条件。不同颜色的光从不同角度照射在顶点上,顶点的颜色也会发生变化。上面的图是在白色光垂直照射条件下得到的(这也是默认设定)。我们也可以不简单的指定顶点颜色,而是详细的说明该顶点产生的环境光、漫反射光、镜面反射光的颜色。OpenGL使用一种简易方法计算出面的图像:根据法向和光源位置的关系将以上几种光的颜色结合灯光对应成份颜色分别指定平面的各部份。从一个顶点产生的反射光不会再照射到其它顶点上,它对其它部份的影响直接在环境光中定义。要想取得更逼真的图像,可以使用光线追踪算法,该方法沿着每一条光线的轨迹,计算出它对所有顶点的影响,将所有光线的效果合并就是最终的图像,由于反射光的照明效果也是精确计算出来的,所以图像逼真。但是OpenGL并不直接支持该方法,需要自己编写计算例程,感兴趣的话去看看光线追踪的书好了。用glMaterial*指定当前材质,第一个参数说明是给面的哪一侧指定材质(前或者后,详见法向部份说明),第二个参数指定要修改的分量,最后部份参数是相应的值。 GLfloat ambient =0.8,0.8,0.8,1.0;/环境光GLfloat diffuse =0.8,0.0,0.8,1.0;/漫反射特性GLfloat specular =1.0,0.0,1.0,1.0;/镜面反射光色GLfloat shininess =50.0; /镜面反射的光亮度glMaterialfv(GL_FRONT,GL_AMBIENT,ambient);glMaterialfv(GL_FRONT,GL_DIFFUSE,diffuse);glMaterialfv(GL_FRONT,GL_SPECULAR,specular);glMaterialfv(GL_FRONT,GL_SHININESS,shininess);gluSphere(obj,0.1,10,10);/用10X10个面绘制半径0.1的球面OpenGL还支持自动双面模式,这种模式下定义的每个面都将生成两个面,位置重合但法向相反,这可以简化对背面和物体内部的描述。该模式默认为关闭。开/关命令是:void glLightModel* GL_LIGHT_MODEL_TWO_SIDE,0/1);打开颜色材质可以简化材质设定,在颜色材质打开时,可以用glColor直接给定顶点材质的颜色,设定材质的哪部分可用glColorMaterial(face,mode);命令设定。而不用象上面那样写一串罗嗦的代码。但是由于不能对材质属性做细节控制,只适用于一些特定的场合。命令是:glEnable(GL_COLOR_MATERIAL);默认值为Disabled。9*OpenGL中用表面来表示物体,一个物体就是一组平面。光线照射在平面上会产生反射,入射线与反射线的角平分线就是法线,它垂直于平面。面法线有两种可能的方向,我们称面有两侧。当描述封闭物体的外表面时,法线应该从内部指向外部;而表示在物体内部时,法线应该从外部指向内部。用glNormal*(N_Vector);指定当前法向矢量。此后的顶点都会使用该法向,直到再次改变。面的法向矢量是怎么确定的呢?右手手指沿顶点顺序握拳,拇指竖立所指方向即为一个面的法向,如果面对该平面,以逆时针序指定顶点,则法向指向你。当你用这样的顺序指定平面的顶点时,OpenGL能够正确的计算出法向矢量。法矢与顶点坐标一样要经过模型视矩阵变换,这样物体坐标系内的法向矢量就可以正确的变成世界坐标系内的法向矢量,保证最终生成的图像是正确的。当一个顶点属于多个平面时,该顶点的法向应该取所在所有平面法向的平均值,以使表面棱角部份平滑自然的,否则会有一道黑线。我们把平面的法向所指一侧称为前面,另一侧称为后面,可以为两侧分别指定不同的属性,所以glMaterial*命令的第一个参数必须是GL_FRONT/GL_BACK/GL_FRONT_AND_BACK之一。下面这组图片展示了法向对场景的影响,角度表示图像是绕Y旋转多少后观察到的:头两行中两三角法向从两者之间指向外部,简称外法向。前三角的面法向(0,0,1),后三角的面法向(0,0,-1),光射线方向(0,0,-1)第一行中,前三角,后三角呈现的是其GL_FRONT部份的材质第二列中,两个三角形的前后关系已经反过来了。三四两行中两三角法向从两者外部指向两者之间的内部,简称内法向。前三角的面法向(0,0,-1),后三角的面法向(0,0,1),光射线方向(0,0,-1)。第五行前两图中两三角法向相同均为(0,0,1)。外法向的平面组可用来表示物体外观(外表面),第五行最后一张图则是这样表示的一个立方体。内法向则适于表示从内部观察物体(灯光、视点均在内部,内表面),程序从略。双三角场景的绘制程序代码如下:glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);glEnable(GL_LIGHTING);glEnable(GL_DEPTH_TEST);glEnable(GL_COLOR_MATERIAL);glEnable(GL_LIGHT0);glLoadIdentity();glRotatef(rot,0,1,0);/全局变量rot即为旋转角度glBegin(GL_TRIANGLES);glNormal3f(0.0,0.0,1.0);/法向与光射线指向同侧glColor3f(1.0,0.0,0.0);glVertex3f(-1.0,0.0,-0.30);glColor3f(0.0,1.0,0.0);glVertex3f(0.0,1.0,-0.30);glColor3f(0.0,0.0,1.0);glVertex3f(1.0,0.0,-0.30);glNormal3f(0.0,0.0,-1.0);/法向与光射线指向相反glColor3f(1.0,0.0,0.0);glVertex3f(-1.0,0.0,0.0);glColor3f(0.0,1.0,0.0);glVertex3f(0.0,1.0,0.0);glColor3f(0.0,0.0,1.0);glVertex3f(1.0,0.0,0.0);glEnd();使用OpenGL默认的光照(光源在0,0,1沿-Z轴方向的白色平行光)和默认的平行投影。为简化代码,打开了GL_COLOR_MATERIAL直接用glColor设定顶点材质。另外为便于阅读图片做了减肥。以上图片是在PII266/FireGL 1000pro/Win2000环境下获取的。这两段代码都放在TOpenGL Panel的OnPaint事件里执行。检讨:右边代码的法向全反了,如果你运行它就会发现虽然看起来仍是一个立方体,但是前后左右上下全都反过来了。这是因为各面法向朝里,前面的后侧对着我们,它不可见,看到的前面实际是后面前侧,而正常情况下后面应该会被前面挡住。立方体场景的绘制程序代码如下:glBegin(GL_QUADS);glNormal3f(0,0,-1);glColor3f(1,0,0);glVertex3f(0,0,0);glVertex3f(1,0,0);glVertex3f(1,1,0);glVertex3f(0,1,0);glNormal3f(-1,0,0);/右glColor3f(0,1,0);glVertex3f(1,0, 0);glVertex3f(1,0,-1);glVertex3f(1,1,-1);glVertex3f(1,1, 0);glNormal3f(0,-1,0);/上glColor3f(0,0,1);glVertex3f(0,1, 0);glVertex3f(1,1, 0);glVertex3f(1,1,-1);glVertex3f(0,1,-1);glNormal3f(0,0,1); /后glColor3f(1,1,0);glVertex3f(0,1,-1);glVertex3f(1,1,-1);glVertex3f(1,0,-1);glVertex3f(0,0,-1);glNormal3f(1,0,0);/左glColor3f(0,1,1);glVertex3f(0,1, 0);glVertex3f(0,1,-1);glVertex3f(0,0,-1);glVertex3f(0,0, 0);glNormal3f(0,1,0);/下glColor3f(1,0,1);glVertex3f(0,0,-1);glVertex3f(1,0,-1);glVertex3f(1,0, 0);glVertex3f(0,0, 0);glEnd();附加说明*由于Delphi自带OpenGL.pas是1.0版的,而现在实际使用的至少是1.1版,Windows纯软件模拟方式也是1.1版的,所以要自己导入一些必要的函数。也可用一些开源的免费单元,如Mike Lischke的OpenGL12.pas。当然,自己写可以设计得更简洁,而且不必在过于超前完备的庞大代码中找错误。 首先引入必要的单元Windows, Messages, OpenGL
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026年心理咨询师考试试题与答案
- 2026年度全国保密教育线上培训考试题库及答案(完整版)
- 2026年共青团入团考试奉献精神测试题库含答案
- 520个带数字的成语
- 2025届申通地铁集团下属公司招聘高校毕业生笔试历年参考题库附带答案详解
- 2025安徽叉车集团有限责任公司(合力叉车)高校毕业生招聘笔试历年参考题库附带答案详解
- 2025国家能源集团技术经济研究院集团系统内招聘11人笔试历年参考题库附带答案详解
- 2025中智集团总部企业管理部公开招聘1人笔试历年参考题库附带答案详解
- 2025中国冶金地质总局在京单位接收应届毕业生情况笔试历年参考题库附带答案详解
- 2026版《金版教程》高考一轮复习政治选择性必修3 模块综合卷(七)
- 2024-2025学年广东省广州市白云区七年级(下)期末语文试卷
- 湖北省合格考数学试卷
- 疏导摊点管理办法
- 广东省珠海市香洲区2024-2025学年八年级下学期期末语文试题(含答案)
- 养老护理员培训课件下载
- 北京市海淀区2023-2024学年五年级下学期英语期末试卷(含答案)
- JG/T 372-2012建筑变形缝装置
- 中国功夫课件
- 大学计算机-计算思维与信息素养 课件 第8章 利用典型计算机语言进行程序设计
- 《传统手工艺》课件
- 职业技术学院2024级人工智能技术与应用专业人才培养方案
评论
0/150
提交评论