精华区 [关闭][返回]

当前位置:网易精华区>>讨论区精华>>游戏元素>>● 游戏开发>>程序开发>>图形编程>>利用OpenGL实现三维绘图[转贴]

主题:利用OpenGL实现三维绘图[转贴]
发信人: lhoboy2001(哎呀)
整理人: nhyjq(2003-01-05 15:32:31), 站内信件
前言: 
在三维绘图蓬勃发展的过程中,计算机公司推出了大量的三维绘图软件包。其中
SGI公司推出的OpenGL,作为一个性能优越的图形应用程序设计界面(API)异军
突起,取得了很大的成就。它以高性能的交互式三维图形建模能力和易于编程开
发,得到了Microsoft、 IBM、 DEC、 Sun、 HP等大公司的认同。因此,OpenGL
已经成为一种三维图形开发标准,是从事三维图形开发工作的必要工具。 

一.初始化OpenGL绘图环境 
1. 定义颜色格式和缓冲模式 
OpenGL提供两种颜色模式:RGB(RGBA)模式和颜色索引模式。在RGBA模式下所有
颜色的定义用RGB三个值来表示,有时也加上Alpha值(表示透明度)。RGB三个分
量值的范围都在0和1 之间,它们在最终颜色中所占的比例与它们的值成正比。如:
(1,1,0)表示黄色,(0,0,1)表示蓝色。颜色索引模式下每个象素的颜色是
用颜色索引表中的某个颜色索引值表示(类似于从调色板中选取颜色)。由于三维
图形处理中要求颜色灵活,而且在阴影,光照,雾化,融合等效果处理中RGBA 的效
果要比颜色索引模式好,所以,在编程时大多采用RGBA模式。 
OpenGL提供了双缓存来绘制图像。即在显示前台缓存中的图像同时,后台缓存绘制
第二幅图像。当后台绘制完成后,后台缓存中的图像就显示出来,此时原来的前台
缓存开始绘制第三幅图像,如此循环往复,以增加图像的输出速度。 
设置窗口显示模式函数: 
void auxInitDisplayMode( 
AUX_DOUBLE//双缓存方式 
|AUX_RGBA);//RGBA颜色模式 
2.设置光源 
OpenGL的光源大体分为三种:环境光(Ambient light),即来自于周围环境没有固
定方向的光。漫射光(Diffuse light)来自同一个方向,照射到物体表面时在物体的
各个方向上均匀发散。镜面光(Specular light)则是来自于同一方向,也沿同一个方
向反射。全局环境光是一种特殊的环境光,它不来自特于某种定光源,通常做为场景
的自然光源。 
指定光源函数: 
Void glLightfv(Glenum light, //光源号 
Glenum pname, //指明光源种类 
//GL_DIFFUSE 光源为漫射光光源 
//GL_AMBIENT 光源为环境光光源 
//GL_SPECULAR 光源为镜面光光源 
const Glfloat* params);//指向颜色向量的指针 
设置全局环境光函数: 
void glLightModelfv( GL_LIGHT_MODEL_ 
AMBIENT, const Glfloat* param ); 
//param 指向颜色向量的指针 
起用光源函数: 
void glEnable(GL_LIGHTING); 
void glEnable(GL_enum cap);// cap :指明光源号 
3. 设置材质 
在OpenGL中,用材料对光的三原色(红绿蓝)的反射率大小来定义材料的颜色。与光
源相对应,材料的颜色,也分为环境色,漫反射色和镜面反射色,由此决定该材料
对应不同的光呈现出不同的反射率。由于人所看到物体的颜色是光源发出的光经物
体反射后进入眼睛的颜色。所以,物体的颜色是光源的环境光,漫反射光和镜面反
射光与材料的环境色,漫反射色和镜面反射色的综合。例如:OpenGL 的光源色是
(LR,LG,LB),材质色为(MR,MG,MB),那么,在忽略其他反射效果的情况下,
最终进入眼睛的颜色是(LR*MR,LG*MG,LB*MB)。 
材质定义函数: 
void glMaterialfv( GLenum face, //指明在设置材质 
的哪个表面的颜色。可以是GL_FRONT, GL_BACK,或GL_FRONT_AND_BACK 
GLenum pname,//与光源的pname参数相似 
const float* params);//指向材质的颜色向量 
4.定义投影方式 
也即选择观察物体的角度和范围。由于我们是三维绘图,所以采用不同的视点和观
察范围,就会产生不同的观察效果。由于计算机只能显示二维图形,所以在表示真
实世界中的三维图形时,需将三维视景转换成二维视景。这是产生三维立体效果的
关键。OpenGL提供了两种将3D图形转换成2D图形的方式。正投影(Orthographic Projection)和透视投影(Perspective Projection)。其中,正投影指投影后物体的大小与视点的远近无关,通常用于CAD设计;而透视投影则符合人的心理习惯,离视点近的物体大,离视点远的物体小。此外,在OpenGL中还要定义投影范围,只有在该范围中的物体才会被投射到计算机屏幕上,投影范围外的物体将被裁减掉。 
定义投影范围(不同的投影方式对应不同函数): 
void glOrtho( GLdouble left, GLdouble right, 
GLdouble bottom, GLdouble top, 
GLdouble near,GLdouble far); 
//(left,bottom,near)和(right,top,far)分别给出正射投 
//影投影范围的左下角和右上角的坐标。 

二.定义与Windows接口的系统函数 
1.定义绘图窗口的位置: 
void auxInitPosition(GLint x,GLint y,GLsizei width, GLsizei heigh);// (x,y)给出窗口左上角坐标 
// width和 heigh给出窗口的宽高 
2.定义绘图窗口的标题: 
void auxInitWindow(GLbyte* 窗口标题字串); 
3.定义绘图窗口改变时的窗口刷新函数: 
void auxReshapeFunc(回调函数名称); 
//当窗口改变形状时调指定的回调函数 
4.定义空闲状态的空闲状态函数以实现动画: 
void auxIdleFunc(回调函数名称); 
//当系统空闲时调用指定的回调函数 
5.定义场景绘制函数(当窗口更新或场景改变时调用): 
void auxMainLoop(回调函数名称); 
//当窗口需要更新或场景变化时调用 

三.VC下实现 
在VC编辑器下键入下述代码后,保存为后缀是cpp的C++文件。开始编译,在
The build command requires an active project workspace。 Would you like
 to create a default project workspace? 的提示后,选择“是(Y)”。
进入Project菜单,选择Setting项,弹出Project Setting 对话框,选择Link项,
在Libaray栏目中加入OpenGL提供的函数库:“opengl32.lib glu32.lib glaux.lib”。
(注:在执行时,Windows 的system目录下要包含opengl32.dll和glu32.dll两个动态连接库)。 


附源程序代码: 
#include "windows.h" #include "gl/gl.h" #include "gl/glaux.h" #include "gl/glu.h" #include "math.h" void myinit() 

glClearColor(1,1,0,0); 
GLfloat ambient[]={.5,.5,.5,0}; 
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, 
ambient); 
GLfloat mat_ambient[]={.8,.8,.8,1.0}; 
GLfloat mat_diffuse[]={.8,.0,.8,1.0}; 
GLfloat mat_specular[]={1.0,.0,1.0,1.0}; 
GLfloat mat_shininess[]={50.0}; 
GLfloat light_diffuse[]={0,0,.5,1}; 
GLfloat light_position[]={0,0,1.0,0}; 
glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,mat_ambient); 
glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,mat_diffuse); 
glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,mat_specular); 
glMaterialfv(GL_FRONT_AND_BACK,GL_SHININESS,mat_shininess); 
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); 
glLightfv(GL_LIGHT0,GL_POSITION, light_position); 
glEnable(GL_LIGHTING); 
glEnable(GL_LIGHT0); 
glDepthFunc(GL_LESS); 
glEnable(GL_DEPTH_TEST); 

void CALLBACK display() 

glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); 
auxSolidSphere(1.0);//绘制半径为1.0的实体球 
glFlush(); //强制输出图像 
auxSwapBuffers(); //交换绘图缓存 
_sleep(100);} 
void CALLBACK Idledisplay() 

//x,y满足x2+y2=0.01。这样可以使物体沿该圆轨 //迹运动。 
static float x=-.1,y=0.0; 
static BOOL mark=TRUE; 
static float step=.01; 
x+=step; 
if(x<=.1&&x>=-.1) 

if(step>0) 
y=sqrt(.01-x*x); 
else 
y=-sqrt(.01-x*x); 
glTranslatef(x,y,0); 

else 

step=0-step; 

display(); 

void CALLBACK myReshape(GLsizei w,GLsizei h) 

glViewport(0,0,w,h); 
glMatrixMode(GL_PROJECTION); 
glLoadIdentity(); 
if(w<=h)
glOrtho(-3.5,3.5,-3.5*(GLfloat)w/(GLfloat)h, 3.5*(GLfloat)w/(GLfloat)h,-10,10);
else
glOrtho(-3.5*(GLfloat)w/(GLfloat)h,3.5* (GLfloat)w/(GLfloat)h,-3.5,3.5,-10,10);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void main()
{
auxInitDisplayMode(AUX_DOUBLE|AUX_RGBA);
auxInitPosition(0,0,400,400);
auxInitWindow(" circle ");
myinit();
auxReshapeFunc(myReshape);
auxIdleFunc(Idledisplay);
auxMainLoop(display);
}

[关闭][返回]