用vc6.0在mfc中调用opengl如何画三次B样条曲线,求 *** 作步骤和程序代码。谢谢!

用vc6.0在mfc中调用opengl如何画三次B样条曲线,求 *** 作步骤和程序代码。谢谢!,第1张

#include <stdlib.h>

#include <GL/glut.h>

#pragma comment(lib,"glut32.lib")

//

#if 0

// the points of the curve - these are the same as the bezier curve

// points demonstrated in the bezier curve example.

float Points[4][3] = {

{ 10,10,0 },

{ 5,10,2 },

{ -5,0,0 },

{-10,5,-2}

}

#define NUM_POINTS 4

// The following sets of 4 indices are the curves that need to

// be drawn to create a clamped cubic b-spline. In total there

// are 5 curve segments to draw.

//

// 0 0 0 1

//0 0 1 2

// 0 1 2 3

//1 2 3 3

// 2 3 3 3

//

// Remember this when trying to understand knot vectors!!

//

#else

float Points[9][3] = {

{ 10,5,0 },

{ 5,10,0 },

{ -5,15,0 },

{ -10,-5,0 },

{ 4,-4,0 },

{ 10,5,0 },

{ 5,10,0 },

{ -5,15,0 },

{ -10,-5,0 }

}

#define NUM_POINTS 9

//若绘制过首尾控制点的曲线

// 0 0 0 1

// 0 0 1 2

// 0 1 2 3

// 1 2 3 4

// 2 3 4 5

// 3 4 5 6

// 4 5 6 6

// 5 6 6 6

//

// Remember this when trying to understand knot vectors!!

//

//若绘制首尾相接的平滑曲线 ,即为当前绘制

// 0 1 2 3

// 1 2 3 4

// 2 3 4 5

// 3 4 5 6

#endif

// the level of detail for the curve

unsigned int LOD=20

#define NUM_SEGMENTS (NUM_POINTS-3)

//

float* GetPoint(int i)

{

// return 1st point

if (i<0)

{

return Points[0]

}

if (i<NUM_POINTS)

{

return Points[i]

}

// return last point

return Points[NUM_POINTS-1]

}

//------------------------------------------------------------ OnKeyPress()

void myIdle(void)

{

glutPostRedisplay()

}

//------------------------------------------------------------ OnDraw()

void OnDraw()

{

// clear the screen &depth buffer

glClear(GL_COLOR_BUFFER_BIT)

// clear the previous transform

glLoadIdentity()

// set the camera position

// gluLookAt( 1,10,30,// eye pos

// 0,0,0, // aim point

// 0,1,0)// up direction

// glColor3f(0.5,0.2,0)

glPointSize(3)

//

// // draw curve hull

glColor3f(0.3,0,0.5)

glBegin(GL_LINE_STRIP)

for(int i=0i!=NUM_POINTS++i)

{

glVertex3fv( Points[i] )

}

glEnd()

glColor3f(0,1,0)

// begin drawing our curve

glBegin(GL_LINE_STRIP)

for(int start_cv=0,j=0j<NUM_SEGMENTSj++,start_cv++)

{

// for each section of curve, draw LOD number of divisions

for(int i=0i!=LOD++i)

{

// use the parametric time value 0 to 1 for this curve

// segment.

float t = (float)i/LOD

// the t value inverted

float it = 1.0f-t

// calculate blending functions for cubic bspline

float b0 = it*it*it/6.0f

float b1 = (3*t*t*t - 6*t*t +4)/6.0f

float b2 = (-3*t*t*t +3*t*t + 3*t + 1)/6.0f

float b3 = t*t*t/6.0f

// calculate the x,y and z of the curve point

float x = b0 * GetPoint( start_cv + 0 )[0] +

b1 * GetPoint( start_cv + 1 )[0] +

b2 * GetPoint( start_cv + 2 )[0] +

b3 * GetPoint( start_cv + 3 )[0]

float y = b0 * GetPoint( start_cv + 0 )[1] +

b1 * GetPoint( start_cv + 1 )[1] +

b2 * GetPoint( start_cv + 2 )[1] +

b3 * GetPoint( start_cv + 3 )[1]

float z = b0 * GetPoint( start_cv + 0 )[2] +

b1 * GetPoint( start_cv + 1 )[2] +

b2 * GetPoint( start_cv + 2 )[2] +

b3 * GetPoint( start_cv + 3 )[2]

// specify the point

glVertex2f( x,y )

}

}

// we need to specify the last point on the curve

//glVertex3fv( Points[NUM_POINTS-1] )

glEnd()

// draw CV's

glBegin(GL_POINTS)

for(int i=0i!=NUM_POINTS++i)

{

glVertex3fv( Points[i] )

}

glEnd()

// currently we've been drawing to the back buffer, we need

// to swap the back buffer with the front one to make the image visible

glutSwapBuffers()

}

//------------------------------------------------------------ OnInit()

void OnInit()

{

//glClearColor(1,1,1,0)

}

//------------------------------------------------------------ OnExit()

void OnExit()

{

}

//------------------------------------------------------------ OnReshape()

void OnReshape(int w, int h)

{

// prevents division by zero when minimising window

if (h==0)

{

h=1

}

// set the drawable region of the window

glViewport(0,0,w,h)

// set up the projection matrix

glMatrixMode(GL_PROJECTION)

glLoadIdentity()

// just use a perspective projection

//gluPerspective(45,(float)w/h,0.1,100)

if(w<=h)

{

glOrtho(-20.0,20.0,-20.0*(GLfloat)h/(GLfloat)w,20.0*(GLfloat)h/(GLfloat)w,0.0,100.0)

}

else

{

glOrtho(-20.0,20.0,-20.0*(GLfloat)h/(GLfloat)w,20.0*(GLfloat)h/(GLfloat)w,0.0,100.0)

}

// go back to modelview matrix so we can move the objects about

glMatrixMode(GL_MODELVIEW)

glLoadIdentity()

}

//------------------------------------------------------------ main()

int main(int argc,char** argv)

{

// initialise glut

glutInit(&argc,argv)

// request a depth buffer, RGBA display mode, and we want double buffering

glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE)

// set the initial window size

glutInitWindowSize(640,480)

// create the window

glutCreateWindow("Clamped B-Spline Curve")

// run our custom initialisation

OnInit()

// set the function to use to draw our scene

glutDisplayFunc(OnDraw)

<a href="http://www.jsykyy.com/" target="_blank">涂料加盟</a>

// set the function to handle changes in screen size

glutReshapeFunc(OnReshape)

glutIdleFunc(&myIdle)

// set the function to be called when we exit

atexit(OnExit)

// this function runs a while loop to keep the program running.

glutMainLoop()

return 0

}

OpenGL 函数库相关的API有核心库(gl)、实用库(glu)、辅助库(aux)、实用工具库(glut)、窗口库(glx、agl、wgl)和扩展函数库等。从图1可以看出,gl是核心,glu是对gl的部分封装。glx、agl、wgl 是针对不同窗口系统的函数。glut是为跨平台的OpenGL程序的工具包,比aux功能强大。扩展函数库是硬件厂商为实现硬件更新利用OpenGL的扩展机制开发的函数。下面逐一对这些库进行详细介绍。

1.OpenGL核心库核心库包含有115个函数,函数名的前缀为gl。这部分函数用于常规的、核心的图形处理。此函数由gl.dll来负责解释执行。由于许多函数可以接收不同数以下几类。据类型的参数,因此派生出来的函数原形多达300多个。核心库中的函数主要可以分为以下几类函数裤正纯:

(1)绘制基本几何图元的函数。如绘制图元的函数glBegain()、glEnd()、glNormal*()、glVertex*()。

(2)矩阵 *** 作、几何变换和投影变换的函数。如矩阵入栈函数glPushMatrix()、矩阵出栈函数glPopMatrix()、装载矩阵函数glLoadMatrix()、矩阵相乘函数glMultMatrix(),当前矩阵函数 glMatrixMode()和矩阵标准化函数glLoadIdentity(),几何变换函数glTranslate*()、glRotate*()和 glScale*(),投影变换函数glOrtho()、glFrustum()和视口变换函数glViewport()等等。

(3)颜色、光照和材质的函数。如设置颜色模式函数glColor*()、glIndex*(),设清拿置光照效果的函数glLight*() 、glLightModel*()和设置材质效果函数glMaterial()等等。

(4)显示列表函数、主要有创建、结束、生成、删除和调用显示列表的函数glNewList()、 glEndList()、glGenLists()、glCallList()和glDeleteLists()。

(5)纹理映射函数,主要有一维纹理函数glTexImage1D()、二维纹理函数glTexImage2D()、 设置纹理参数、纹理环境和纹理坐标的函数glTexParameter*()、glTexEnv*()和glTetCoord*()等。

(6)特殊效果函数。融合函数glBlendFunc()、反走样函数glHint()和雾化效果glFog*()。

(7)光栅化、象素 *** 作函数。如象素位置glRasterPos*()、线型宽度glLineWidth()、多边形绘制模式glPolygonMode(),读取象素glReadPixel()、复制象素glCopyPixel()等。

(8)选择与反馈函数。主要有渲染模式glRenderMode()、选择缓冲区glSelectBuffer()和反馈缓冲区glFeedbackBuffer()等。

(9)曲线与曲面的绘制函数。生成曲线或曲面的函数glMap*()、glMapGrid*(),求值器的函数glEvalCoord*() glEvalMesh*()。

(10)状态设置与查询函数。主要有glGet*()、glEnable()、glGetError()等。

2.OpenGL实用库The OpenGL Utility Library (GLU)包含有43个函数,函数名的前缀为glu。OpenGL提供了强大的但是为数不多的绘图命令,所有较复杂的绘图都必须从点。线、面开始。Glu 为了减轻繁重的编程工作,封装了OpenGL函数,Glu函数通过调用核心库的函数,为开发者提供相对简单的用法,实现一些较为复杂的 *** 作。此函数由 glu.dll来负责胡咐解释执行。OpenGL中的核心库和实用库可以在所有的OpenGL平台上运行。主要包括了以下几种:

(1)辅助纹理贴图函数,有gluScaleImage() 、gluBuild1Dmipmaps()、gluBuild2Dmipmaps()。

(2)坐标转换和投影变换函数,定义投影方式函数gluPerspective()、gluOrtho2D() 、gluLookAt(),拾取投影视景体函数gluPickMatrix(),投影矩阵计算gluProject()和 gluUnProject()等等。

(3)多边形镶嵌工具,有gluNewTess()、 gluDeleteTess()、gluTessCallback()、gluBeginPolygon() gluTessVertex()、gluNextContour()、gluEndPolygon()等等。

(4)二次曲面绘制工具,主要有绘制球面、锥面、柱面、圆环面gluNewQuadric()、gluSphere()、gluCylinder()、gluDisk()、gluPartialDisk()、gluDeleteQuadric()等等。

(5)非均匀有理B样条绘制工具,主要用来定义和绘制Nurbs曲线和曲面,包括gluNewNurbsRenderer()、 gluNurbsCurve()、gluBeginSurface()、gluEndSurface()、gluBeginCurve()、 gluNurbsProperty()等函数。

(6)错误反馈工具,获取出错信息的字符串gluErrorString()。

3.OpenGL辅助库包含有31个函数,函数名前缀为aux。这部分函数提供窗口管理、输入输出处理以及绘制一些简单三维物体。此函数由glaux.dll来负责解释执行。创建aux库是为了学习和编写 OpenGL程序,它更像是一个用于测试创意的预备基础接管。Aux库在windows实现有很多错误,因此很容易导致频繁的崩溃。在跨平台的编程实例和演示中,aux很大程度上已经被glut库取代。OpenGL中的辅助库不能在所有的OpenGL平台上运行。辅助库函数主要包括以下几类:

(1)窗口初始化和退出函数,auxInitDisplayMode()和auxInitPosition()。

(2)窗口处理和时间输入函数,auxReshapeFunc()、auxKeyFunc()和auxMouseFunc()。

(3)颜色索引装入函数,auxSetOneColor()。

(4)三维物体绘制函数。包括了两种形式网状体和实心体,如绘制立方体auxWireCube()和 auxSolidCube()。这里以网状体为例,长方体auxWireBox()、环形圆纹面auxWireTorus()、圆柱 auxWireCylinder()、二十面体auxWireIcosahedron()、八面体auxWireOctahedron()、四面体 auxWireTetrahedron()、十二面体auxWireDodecahedron()、圆锥体auxWireCone()和茶壶 auxWireTeapot()。

(5)背景过程管理函数auxIdleFunc()。

(6)程序运行函数auxMainLoop()。

4.OpenGL工具库 OpenGL Utility Toolkit包含大约30多个函数,函数名前缀为glut。glut是不依赖于窗口平台的OpenGL工具包,由Mark KLilgrad在SGI编写(现在在Nvidia),目的是隐藏不同窗口平台API的复杂度。函数以glut开头,它们作为aux库功能更强的替代品,提供更为复杂的绘制功能,此函数由glut.dll来负责解释执行。由于glut中的窗口管理函数是不依赖于运行环境的,因此OpenGL中的工具库可以在X-Window, Windows NT, OS/2等系统下运行,特别适合于开发不需要复杂界面的OpenGL示例程序。对于有经验的程序员来说,一般先用glut理顺3D图形代码,然后再集成为完整的应用程序。这部分函数主要包括:

(1)窗口 *** 作函数,窗口初始化、窗口大小、窗口位置等函数glutInit() glutInitDisplayMode() glutInitWindowSize() glutInitWindowPosition()等。

(2)回调函数。响应刷新消息、键盘消息、鼠标消息、定时器函数等,GlutDisplayFunc() glutPostRedisplay() glutReshapeFunc() glutTimerFunc() glutKeyboardFunc() glutMouseFunc()。

(3)创建复杂的三维物体。这些和aux库的函数功能相同。创建网状体和实心体。如glutSolidSphere()、glutWireSphere()等。在此不再叙述。

(4)菜单函数。创建添加菜单的函数GlutCreateMenu()、glutSetMenu()、glutAddMenuEntry()、glutAddSubMenu() 和glutAttachMenu()。

(5)程序运行函数,glutMainLoop()。

采用Visual C++ 6.0 和OpenGL graphics library 编程,根据图9-35中概化的黑河流域水循环规律,研制其可视系统(记作HHWS)。该系统遵循了直观、形象和动态地展示出全流域水循环的整个演化过程的原则,为黑河流域水资源可持续开发利用研究提供了崭新的视角和有效的技术手段。

图9-35 黑河流域地表水与地下水系统之间水循环演化规律示意图

一、可视化水循环系统剖面

黑河流域水循环演化过程,以祁连山区(莺落峡西)—临泽县城—高台县城(沿黑河河床)—正义峡(沿黑河河床)—湖西新村—额济纳旗县城的典型剖面为例,大致可划分为以下几个过程。

(1)在祁连山区

祁连山山区侵蚀基准面以上的地下水主要排泄场所是地表水文网系。山巅基岩裂隙地下水在向山缘运动过程中,排泄于沟谷而转化为河水。尽管祁连山内部地下水与河水之间转化过程十分复杂,但是就总的特征而言,在流出山体以前,大部分基岩裂隙水排泄、汇流于河道,以地表径流的形式流出山区。

(2)在中游山前径流补给区

祁连山山区河流出山口进入中游盆地,在透水性极强的山前洪积扇扇顶和扇中部卵砾石层戈壁带,大规模下渗,转化为地下水。在冲洪积扇群带,地下水沿地形坡降自扇顶向扇缘运动,随着地形变缓,颗粒变细,透水性变差,地下径流受阻,潜水雍高,水位变浅。在洪积扇扇缘与冲积细土平原交接处,由于地层岩性或基底隆起毕谨变化,潜水水位接近地表,沿沟壑泉大量溢出地表。

(3)在中游径流排泄区

在中游的冲积细土平原,岩性变细,地势变缓,地下水径流变慢,潜水水位埋深变浅。在黑河流域中游细土带,黑河河床是地下水与河水之间相互转化的重要场所。河流切割含水层,且河水水位低于地下水水位,地下水向河道排泄。在高崖—平川(靠近张掖)地段,地下水转化为河水量最大,在高台附近河段地下水转化为河水量较小,在高台—正义峡河段(中游下段)转化量虽较高台附近有所增加,但是小于高崖—平川河段。

在黑河中游区至哪行下游的河流出口(正义峡—夹山的河床带),由于砂岩和泥岩组成的基岩导水性很低,导致中游区地下水溢出而转化为地表河水进入下游区。

(4)在下游径流排泄区

当河水进入下游盆地,再度渗漏而转化为地下水。在下游区,潜水水位普遍低于河水水位,下游河床处于渗漏状态。在靠近正义峡地带,河床岩性多为砂和砂砾石,入渗性强。再往下游段,随着河床岩性颗粒的变细和地下水水位的变浅,河水渗漏率逐渐减小。

二、HHWS系统主要功能

根据上述背景条件,研制了黑河流域水循环演化可视系统(HHWS),它具有如下主要功能。

1)动态显示从祁连山山区至中游走廊平原、最后进入下游沙漠区的整个流域水循环演化过程,并且可以根据拦蓄和开采条件变化,例如水库大坝闸门、抽水井等模拟 *** 作,以直观形象展现地下水与地表水之间相互转化关系和渗流场宏观分布特征与变化趋势。

2)提供完善的图形编辑工具,可进行流线的跟踪、重构、裁剪、复制和删除等编辑修改工作,建立完善正确的水循环演化动态模型。

3)数据文件及纹理图片的装载与保存。

4)根据微机硬件的不同配置,通过设置图像帧之间的时间步长,控制水流的动态模拟演示速度,以满足不同用户的视觉要求。

5)友好的用户界面,可以交互式地完成图像的视点、颜色等参数的设定,任意缩放、平移图像,显示整体区域或局部区域的水循环演化状况。

三、开发环境与设计技术

HHWS系统是在微手缓基型计算机平台上开发, *** 作系统为Windows98,使用Visual C++6.0和OpenGL graphics library编程实现,纹理图片采用Microsoft Image Composer图形工具绘制。

(一)系统的体系结构

HHWS系统的体系结构如图9-36所示,可划分为输入阶段、设计阶段和输出阶段3部分。

图9-36 黑河流域水循环可视化系统结构

输入阶段由数据输入模块组成,分为数据文件的输入和纹理图片的输入,作为系统设计的预处理阶段。

设计阶段包括纹理映射、模型设计和图形编辑工具3个模块。通过交互式图形编辑工具,能够便利地对模型进行各种设计,主要包括对每一图像帧中的流线进行跟踪、重构,对现有流线进行裁剪、删除,在不同图像帧之间完成流线的复制等 *** 作。

输出阶段由模型保存和交互 *** 作、动态演示3个模块构成。模型保存的作用是将设计阶段建立的地下水渗流场和地表河流数据模型以文件形式保存起来,作为动态演示模块的数据,以加快动态显示的速度。

基于粒子系统的理论和方法,HHWS提出的随机转换算法在模型设计和动态演示过程中,有效地利用了图像帧以及部分流线之间的可重用性,缩短了动画制作周期,降低了存储开销,大大提高了效率。

图9-37是HHWS系统中,动态演示模块显示某时刻黑河流域水循环的一个演化状态。

(二)实现方法

在开发研制HHWS系统过程中,主要涉及的技术与方法有:插值方法、纹理映射技术、融合与反走样技术、选择拾取技术、可视跟踪技术、动态显示方法等,对主要的实现方法简介如下。

1.线连续性处理

在模型设计过程中,HHWS系统采用了3次B样条曲线插值方法,既能保证图像帧中每条流线C2连续,而且计算量不大,不会影响动态显示速度。

给定某一流线上的点列Pi(i=1,2,…,n),计算控制顶点Vj(j=1,2,…,n+1,n+2),使其定义的3次B样条曲线通过点列Pi(i=1,2,…,n),对原有流线进行拟合。

图9-37 黑河流域典型剖面水循环演化过程可视化平台图

3次均匀B样条曲线的矩阵可表示为:

西北内陆黑河流域水循环与地下水形成演化模式

则各段曲线的首点为:Pi=Pi(0)=(V1+4Vi+1+Vi+2),i=1,2,…,n-1。最后一段曲线的末点为:Pn=Vn+2

2.纹理映射

纹理映射技术可以增强图像的真实感,能够将任意一块纹理按不同的方式映射到平面或曲面上,它不仅可以是二维映射,也可以是一维或多维映射。纹理映射过程相当复杂,包括定义纹理、控制滤波、说明映射方式、绘制场景、给出顶点的纹理坐标和几何坐标。

HHWS系统定义了一个二维纹理映射,纹理的尺寸为1024×256,采用OpenGL图形库中最靠近象素中心的4个象素加权平均值的滤波方式,它提供了比较光滑的效果,并且选择用纹理中的值来调整图形剖面原来颜色的映射方式。

在HHWS系统中,纹理映射能够实现水流场中背景景物与前景动画的有机结合。

3.融合与反走样

融合是指两种颜色各分量依据一定的比例混合在一起。通过源因子(Source Factor)和目的因子(Destination Factor)分别表示源颜色和目的颜色在最终颜色中所占的比例。从数学的角度来看,设源因子和目的因子分别为(Sr、Sg、Sb、Sa)与(Dr、Dg、Db、Da),则融合的最终结果是

西北内陆黑河流域水循环与地下水形成演化模式

式中每个元素值都约简到[0,1]之间。

由于计算机生成的图形是由离散点组成的数字化图像,因而生成的图形必然与真实景物之间存在一定误差。这种误差表现为图形上的直线或光滑的曲线呈现锯齿状、彩色花纹失去原有的形态和色彩、细小物体在画面上得不到反映等等。反走样技术就是处理真实物体与显示图像之间的误差。HHWS系统采用按照透视投影纠正方式进行插值,对颜色进行线性插值,以减少或消除这些现象。

融合与反走样技术的运用,能够使图像帧中的流线、山峦等产生更加逼真的效果。

4.空间对象拾取

是否提供一个易 *** 作、可视化、数据可实时解释的友好界面,始终是评价一个软件系统的标准之一。HHWS提供了一种空间对象拾取技术,是交互式图形编辑工具中的关键技术之一。可根据用户需求选择对象或对象集,并实时解释相应对象或对象集所包含的信息。

其主要实现步骤如下:

1)设置鼠标拾取的范围,范围的大小直接影响拾取矩阵。

2)将对象(集)绘入帧缓冲区;如果采用隐式拾取方法,则直接转入下一步。

3)拾取 *** 作由鼠标的LBUTTONDOWN消息触发。首先重复执行上一步。然后,进入选择模式,将候选对象排序,依次放入索引队列中,并将候选对象的索引号压入名字堆栈中。当退出选择模式时,通过将拾取矩阵与投影矩阵相乘,从而将绘图 *** 作限制在视口中鼠标附近的一个小区域内,鼠标附近绘制的物体就会被选中,返回用户拾取的对象索引号。

4)如果需要选择拾取多个对象,则重复执行上一步,并将拾取的一系列对象的索引号存入临时缓冲区。

5)匹配临时缓冲区中的对象(集),并对拾取的对象实现进一步 *** 作,如移动、编辑、显示对象所包含的信息等。

HHWS系统不仅实现了对黑河流域水循环演化过程的动态演示,而且也可以作为一个通用的动画制作工具,适用于地下水流、地表水流、溶质运移、地质灾害和生态环境变化等领域。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/12555168.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-26
下一篇 2023-05-26

发表评论

登录后才能评论

评论列表(0条)

保存