1. 曲面和曲線
前面我們講了如何繪制平面的圖形,這一節我們學習如何繪制曲線和曲面。
例10:繪制一個曲面,本程式使用二維求值器繪制一個曲面。本例中也有一些特殊效果的操作。
#include <windows.h>
#include <GL/GLAUX.h>
#include <GL/glut.h>
#include <math.h>
GLfloat ctrlpoints[5][5][3] = {{{-2,0,0},{-1,1,0},{0,0,0},{1,-1,0},{2,0,0}},
{{-2,0,-1},{-1,1,-1},{0,0,-1},{1,-1,-1},{2,0,-1}},
{{-2,0,-2},{-1,1,-2},{0,0,-2},{1,-1,-2},{2,0,-2}},
{{-2,0,-3},{-1,1,-3},{0,0,-3},{1,-1,-3},{2,0,-3}},
{{-2,0,-4},{-1,1,-4},{0,0,-4},{1,-1,-4},{2,0,-4}}};
GLfloat mat_ambient[] = {0.1,0.1,0.1,1.0};
GLfloat mat_diffuse[] = {1.0,0.6,0.0,1.0};
GLfloat mat_specular[] = {1.0,1.0,1.0,1.0};
GLfloat light_ambient[] = {0.1,0.1,0.1,1.0};
GLfloat light_diffuse[] = {1.0,1.0,1.0,0.0};
GLfloat light_specular[] = {1.0,1.0,1.0,0.0};
GLfloat light_position[] = {2.0,23.0,-4.0,1.0};
void myInit(void)
{
glClearColor(0.0,0.0,0.0,0.0);//設定背景色
/*為光照模型指定材質參數*/
glMaterialfv(GL_FRONT,GL_AMBIENT,mat_ambient);
glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_diffuse);
glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);
glMaterialf(GL_FRONT,GL_SHININESS,60.0);
/*設定光源參數*/
glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient);
glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse);
glLightfv(GL_LIGHT0,GL_SPECULAR,light_specular);
glLightfv(GL_LIGHT0,GL_POSITION,light_position);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
/*enable depth comparisons and update the depth buffer*/
glEnable(GL_DEPTH_TEST);
/*設定特殊效果*/
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glHint(GL_LINE_SMOOTH_HINT,GL_DONT_CARE);
glEnable(GL_BLEND);
glEnable(GL_AUTO_NORMAL);
glEnable(GL_NORMALIZE);
glFrontFace(GL_CW);
glShadeModel(GL_SMOOTH);
glEnable(GL_LINE_SMOOTH);
}
void myDisplay(void)
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glColor3f(0.0,0.0,0.0);
glTranslatef(0.0,-1.0,0.0);
glRotatef(50.0,1.0,0.0,0.0);
glPushMatrix();
/*繪制曲面*/
glEnable(GL_MAP2_VERTEX_3);
glMap2f(GL_MAP2_VERTEX_3,0,1,3,5,0,1,15,5,&ctrlpoints[0][0][0]);
glMapGrid2f(10.0,0.0,1.0,10.0,0.0,1.0);
glEvalMesh2(GL_FILL,0,10.0,0,10.0);
glPopMatrix();
glutSwapBuffers();
void myReshape(GLsizei w,GLsizei h)
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0,(GLfloat)w/(GLfloat)h,1.0,100.0);
glMatrixMode(GL_MODELVIEW);
glTranslatef(0.0,0.0,-5.0);
int main(int argc,char ** argv)
/*初始化*/
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH);
glutInitWindowSize(400,400);
glutInitWindowPosition(200,200);
/*建立視窗*/
glutCreateWindow("lighted Bezier surface");
/*繪制與顯示*/
myInit();
glutReshapeFunc(myReshape);
glutDisplayFunc(myDisplay);
glutMainLoop();
return(0);
myInit()中的幾個有關特殊效果的操作。
l glBlendFunc(GLenum sfactor,GLenum dfactor) 指定像素算法。sfactor指定紅,綠,藍及alpha源混合因素是如何計算的。dfactor指定紅,綠,藍及alpha目标混合因素是如何計算的。
l glHint(GLenum target,GLenum mode)指定操作線索。
Target為需要控制的符号常量。mode為所希望的行為符号常數。本例中GL_LINE_SMOOTH_HINT指定反走樣線段的采樣品質。GL_DONT_CARE指對選項不做考慮。
myDisplay()中的曲面操作
l void glMap2f(GLenum target,GLfloat u1,GLfloat u2,Glint ustride, Glint uorder, GLfloat v1, GLfloat v2, Glint vstride, Glint vorder, const GLfloat *points);定義2維求值器。
target指定求值器生成的數值類型。本例中的GL_MAP2_VERTEX_3 指明每一個控制點為x、y、z表示的三個浮點值。
u1,u2指定線性映射。
ustride 指定控制點Rij的起始點和控制點 R(i+1)j的的起始點之間單精度或雙精度浮點值的個數。這裡i和j分别是u和v控制點索引,它允許控制點裝入任意的資料結構中。唯一的限制是對于特定控制點的數值必須存在連續的記憶體單元。
uorder控制點數組在u軸方向上的維數。
v1,v2指定線性映射v
vstride指定控制點Rij的起始點和控制點 Ri(j+ 1)的起始點之間單精度或雙精度浮點值的個數。這裡i和j分别是u和v控制點索引,它允許控制點裝入任意的資料結構中。唯一的限制是對于特定控制點的數值必須存在連續的記憶體單元。
vorder控制點數組在v軸方向上的維數。
points 一個指向控制點數組的指針。
l glMapGrid定義一維或二維網格。void glMapGrid2f(Glint un, GLfloat u1, GLfloat u2,Glint vn, GLfloat v1,GLfloat v2);
un 在網格[u1,u2]中的分段數目。
u1,u2 指定整數網格範圍 i= 0;i= un的映射。
vn在網格[v1,v2]中的分段數目。
v1,v2 指定整數網格範圍 j = 0;j= vn的映射。
l glEvalMesh 計算一維或二維點或線網格。本例中為2維。void glEvalMesh2(GLenum mode,Glint i1,Glint i2,Glint j1,Glint j2);
mode 指定是否計算二維點、線或多邊形的網格。
i1,i2 分别為網格定義域變量i的第一個和最後一個整數值。
j1,j2分别為網格定義域變量j的第一個和最後一個整數值。
glMapGrid和glEvalMesh用來生成并求取一系列等間隔的網格點,glEvalMesh逐漸計算一維或二維網格,他的定義範圍由glMap指定。mode決定最終計算的頂點是繪制為點、線還是充實的多邊形。具體的映射關系及有關圖形方面的知識,你可以很友善的在MSDN、網際網路及有關書籍中查到,本文就不詳述這方面的内容。
2. 繪制NURBS曲線和曲面
上一節講了一般的曲線與曲面的繪制,本節講NURBS曲線和曲面的繪制。
例11:此例繪制兩個相同形狀的NURBS曲面,不同之處是一個為線框式,一個是由實多邊形組成。運作後可以看到其中的差別。
GLUnurbsObj *theNurb1;
GLUnurbsObj *theNurb2;
GLfloat ctrlpoints[5][5][3] = {{{-3,0.5,0},{-1,1.5,0},{-2,2,0},{1,-1,0},{-5,0,0}},
{{-3,0.5,-1},{-1,1.5,-1},{-2,2,-1},{1,-1,-1},{-5,0,-1}},
{{-3,0.5,-2},{-1,1.5,-2},{-2,2,-2},{1,-1,-2},{-5,0,-2}},
{{-3,0.5,-3},{-1,1.5,-3},{-2,2,-3},{1,-1,-3},{-5,0,-3}},
{{-3,0.5,-4},{-1,1.5,-4},{-2,2,-4},{1,-1,-4},{-5,0,-4}}};//控制點
GLfloat mat_diffuse[] = {1.0,0.5,0.1,1.0};
GLfloat mat_shininess[] = {100.0};
GLfloat light_position[] = {0.0,-10.0,0.0,1.0};
glClearColor(1.0,1.0,1.0,0.0);//設定背景色
glMaterialfv(GL_FRONT,GL_SHININESS,mat_shininess);
glLightfv(GL_FRONT,GL_POSITION,light_position);//設定光源參數
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);//設定光照模型參數
/*激活光照*/
glDepthFunc(GL_LEQUAL);
glEnable(GL_LEQUAL);
theNurb1 = gluNewNurbsRenderer();//建立NURBS對象theNurb1
gluNurbsProperty(theNurb1,GLU_SAMPLING_TOLERANCE,25.0);
gluNurbsProperty(theNurb1,GLU_DISPLAY_MODE,GLU_OUTLINE_POLYGON);
theNurb2 = gluNewNurbsRenderer();//建立NURBS對象theNurb2
gluNurbsProperty(theNurb2,GLU_SAMPLING_TOLERANCE,25.0);
gluNurbsProperty(theNurb2,GLU_DISPLAY_MODE,GLU_FILL);
int spin = 0;
/*接收鍵盤指令*/
static void myKey(unsigned char key,int x,int y)
switch(key)
{
case'd':
spin = spin + 1;
glRotatef(spin,1.0,1.0,0.0);
glutPostRedisplay();
break;
case 27:
exit(0);
default:
}
/*繪制曲面*/
GLfloat knots[10] = {0.0,0.0,0.0,0.0,0.0,1.0,1.0,1.0,1.0,1.0};
glRotatef(50.0,1.0,1.0,0.0);
/*第一個曲面*/
glTranslatef(1.0,0.0,0.0);
gluBeginSurface(theNurb1);
/*定義曲面形狀*/
gluNurbsSurface(theNurb1,10,knots,10,knots,5*3,3,&ctrlpoints[0][0][0],5,5,GL_MAP2_VERTEX_3);
gluEndSurface(theNurb1);
/*第二個曲面*/
glTranslatef(7.0,0.0,0.0);
gluBeginSurface(theNurb2);
gluNurbsSurface(theNurb2,10,knots,10,knots,5*3,3,&ctrlpoints[0][0][0],5,5,GL_MAP2_VERTEX_3);
gluEndSurface(theNurb2);
gluPerspective(50.0,(GLfloat)w/(GLfloat)h,1.0,15.0);
glTranslatef(0.0,0.0,-9.0);
/*初始化*/
glutInitWindowSize(600,400);
/*建立視窗*/
glutCreateWindow("NURBS surface");
/*繪制與顯示*/
glutKeyboardFunc(myKey);
l GLUnurbsObj* glNewNurbsRenderer()建立一個NURBS對象,并傳回一個指向該對象的指針。如果沒有足夠的記憶體配置設定給該對象,則傳回值為0。
l void gluNurbsProperty(GLUnurbsObj* nobj, GLenum property, GLfloat value)設定NURBS屬性。
nobj 指向NURBS對象的指針。
property需設定的屬性。
value 設定指定屬性的值。
l glBeginSurface及gluEndSurface兩個函數一起限定一個NURBS面的定義。傳回值均為void,參數均為GLUnurbsObj* nobj,為指向NURBS對象的指針。
l void gluNurbsSurface(GLUnurbsObj *nobj, Glint knot_count, GLfloat tknot_count, GLfloat *tknot, Glint s_stride, Glint t_stride, GLfloat *ctlarry, GLint sorder, GLint torder,GLenum type) 定義NURBS曲面形狀。
sknot_count 參數化u方向上的節點數。
sknot 參數化u方向上的非遞減節點值。
tknot_count 參數化v方向上的節點數。
tknot 參數化v方向上的非遞減節點值。
s_stride在ctlarry中參數化u方向上相鄰控制點的偏移量。
t_stride在ctlarry中參數化v方向上相鄰控制點的偏移量。
ctlarryNURBS的控制點數組。
sorder參數化u方向上NURBS的階數,階數比維數大1。
torder參數化v方向上NURBS的階數,階數比維數大1。
type曲面類型。
例12:繪制一個彩色的曲線,曲線閉合成圓。在曲線的邊緣繪制8個點。
GLUnurbsObj *theNurb;
GLfloat ctrlpoints[12][3] = {{4,0,0},{2.828,2.828,0},{0,4,0},{-2.828,2.828,0},
{-4,0,0},{-2.828,-2.828,0},{0,-4,0},{2.828,-2.828,0},
{4,0,0},{2.828,2.828,0},{0,4,0},{2.828,2.828,0}};//控制點
GLfloat color[12][3]={{1.0,0.0,0.0},{1.0,1.0,0.0},{0.0,1.0,0.0},{-1.0,1.0,0.0},
{-1.0,0.0,0.0},{-1.0,-1.0,0.0},{0.0,-1.0,0.0},{1.0,-1.0,0.0},
{1.0,0.0,0.0},{1.0,1.0,0.0},{0.0,1.0,0.0},{1.0,1.0,0.0}};
GLfloat knots[15] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
theNurb = gluNewNurbsRenderer();//建立NURBS對象theNurb
gluNurbsProperty(theNurb,GLU_SAMPLING_TOLERANCE,10);
/*繪制曲線*/
int i;
glColor3f(0.0,0.0,0.0);
glLineWidth(3.0);
/*繪制曲線*/
gluBeginCurve(theNurb);
gluNurbsCurve(theNurb,15,knots,3,&ctrlpoints[0][0],3,GL_MAP1_VERTEX_3);
gluNurbsCurve(theNurb,15,knots,3,&ctrlpoints[0][0],3,GL_MAP1_COLOR_4);
gluEndCurve(theNurb);
/*繪制點*/
glColor3f(1.0,0.0,0.0);
glPointSize(5.0);
glBegin(GL_POINTS);
for(i = 0;i < 8;i++)
glVertex2fv(&ctrlpoints[i][0]);
glEnd();
if(w <=h)
glOrtho(-10.0,10.0,-10.0*(GLfloat)h/(GLfloat)w,10.0*(GLfloat)h/(GLfloat)w,-10.0,10.0);
else
glOrtho(-10.0*(GLfloat)w/(GLfloat)h,10.0*(GLfloat)w/(GLfloat)h,-10.0,10.0,-10.0,10.0);
glutCreateWindow("NURBS curve");
l gluBeginCurve,gluEndCurve限定NURBS曲面。傳回值均為void,參數均為GLUnurbsObj* nobj,為指向NURBS對象的指針。
l void gluNurbsCurve(GLUnurbsObj *nobj, GLint nknots, GLfloat *knot, Glint stride, GLfloat *ctlarray, GLint order,GLenum type)定義曲線形狀。
nknots 節點數,節點數等于控制點數加上階數。
knot nknots數組非遞減節點值。
stride相鄰控制點的偏移量。
Ctlarry指向NURBS的控制點數組的指針。
order NURBS曲線的階數,階數比維數大1。
3. 二次幾何體
這一章我們講一下二次幾何物體的繪制。二次幾何物體的繪制有幾種不同的方式,在本例中可以看出不同的繪制方式的不同效果。
例13:本例使用GLU庫函數繪制了四個幾何物體,分别為圓柱體、球體、圓盤和部分圓盤。
/*聲明四個二次曲面物體*/
GLUquadricObj *quadObj1;
GLUquadricObj *quadObj2;
GLUquadricObj *quadObj3;
GLUquadricObj *quadObj4;
static float light_ambient[] = {0.1,0.1,0.1,1.0};
static float light_diffuse[] = {0.5,1.0,1.0,1.0};
static float light_position[] = {90.0,90.0,150.0,0.0};
static float front_mat_shininess[] = {60.0};
static float front_mat_specular[] = {0.2,0.2,0.2,1.0};
static float front_mat_diffuse[] = {0.5,0.5,0.28,1.0};
static float back_mat_shininess[] = {60.0};
static float back_mat_specular[] = {0.5,0.5,0.2,1.0};
static float back_mat_diffuse[] = {1.0,0.9,0.2,1.0};
static float Imodel_ambient[] = {1.0,1.0,1.0,1.0};
static float Imodel_twoside[] = {GL_TRUE};
static float Imodel_oneside[] = {GL_FALSE};
/*設定背景色*/
glClearColor(0.0,0.0,0.0,1.0);
/*設定光照*/
/*設定材質*/
glMaterialfv(GL_FRONT,GL_DIFFUSE,front_mat_diffuse);
glMaterialfv(GL_FRONT,GL_SPECULAR,front_mat_specular);
glMaterialfv(GL_FRONT,GL_SHININESS,front_mat_shininess);
glMaterialfv(GL_BACK,GL_DIFFUSE,back_mat_diffuse);
glMaterialfv(GL_BACK,GL_SPECULAR,back_mat_specular);
glMaterialfv(GL_BACK,GL_SHININESS,back_mat_shininess);
/*設定光照模型參數*/
glLightModelfv(GL_LIGHT_MODEL_AMBIENT,Imodel_ambient);
glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE,Imodel_twoside);
/*激活關照*/
glShadeModel(GL_SMOOTH);
/*建立四個二次曲面物體*/
quadObj1 = gluNewQuadric();
quadObj2 = gluNewQuadric();
quadObj3 = gluNewQuadric();
quadObj4 = gluNewQuadric();
/*繪制一個圓柱體*/
gluQuadricDrawStyle(quadObj1,GLU_FILL);
gluQuadricNormals(quadObj1,GL_FLAT);
gluQuadricOrientation(quadObj1,GLU_INSIDE);
gluQuadricTexture(quadObj1,GL_TRUE);
glColor3f(1.0,1.0,0.0);
glRotatef(30,1.0,0.0,0.0);
glRotatef(40,0.0,1.0,0.0);
gluCylinder(quadObj1,2.0,2.0,9.0,20.0,8.0);
/*繪制一個球體*/
gluQuadricDrawStyle(quadObj2,GLU_SILHOUETTE);
glTranslatef(-5.0,-1.0,0.0);
gluSphere(quadObj2,3.0,20.0,20.0);
/*繪制一個圓盤*/
gluQuadricDrawStyle(quadObj3,GLU_LINE);
glTranslatef(-2.0,4.0,0.0);
gluDisk(quadObj3,2.0,5.0,15.0,10.0);
/*繪制一個部分圓盤*/
gluQuadricDrawStyle(quadObj4,GLU_POINT);
glTranslatef(-3.0,-7.0,0.0);
gluPartialDisk(quadObj4,2.0,5.0,15.0,10.0,10.0,100.0);
/*删除四個二次曲面物體對象*/
gluDeleteQuadric(quadObj1);
gluDeleteQuadric(quadObj2);
gluDeleteQuadric(quadObj3);
gluDeleteQuadric(quadObj4);
glFlush();
void myReshape(int w,int h)
glViewport(0,0,(GLsizei)w,(GLsizei)h);
gluPerspective(45.0,(GLfloat)w/(GLfloat)h,1.0,50.0);
glTranslatef(0.0,0.0,-25.0);
/*初始化*/
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB|GLUT_DEPTH);
glutInitWindowPosition(100,100);
/*建立視窗*/
glutCreateWindow(" DRAW QUADRIC OBJECTS ");
/*繪制與顯示*/
myInit();
return 0;
l gluNewQuadric建立一個二次對象。這個函數建立并傳回一個指向新的二次對象的指針。當調用二次描述和控制函數是指向這個對象。如果傳回值為0則表明沒有足夠的空間配置設定給該對象。
l glQuadricDrawStyle函數指定二次對象的繪制方式。本例中圓柱體的繪制方式為GLU_FILL。含義為用多邊形原繪制本二次對象,多邊形的繪制方式為逆時針。球體的繪制方式為GL_SILHOUETTE,即除邊界外用一系列線來繪制二次對象。圓盤的繪制方式為GL_LINE,即用一系列線來繪制二次對象。部分圓盤的繪制方式為GL_POINT,即用一系列點來繪制二次對象。
l glQuadricNormals,指定二次對象使用的法向量類型。
l glQuadricOrientation,指定二次對象的内面或外面方位。GLU_OUTSIDE為預設值,表明使用指向内面的法相量繪出二次對象,GLU_INSIDE表明使用指向外面的法相量繪出二次對象。
l glQuadricTexture指定二次對象是否使用紋理。GL_FALSE為預設值。
l void gluCylinder(GLUquadricObj *qobj,GLdouble baseRadius,GLdouble topRadius,GLdouble height,Glint slices,Glint stacks)繪制一個圓柱體。
qobj指明是哪個二次對象。
baseRadius圓柱體在z=0時的半徑。
topRadius圓柱體在z=height時的半徑。
height圓柱體的高。
slices圍繞着z軸分片的個數。
stacks順着z軸分片的個數。stacks和slices垂直。
l void gluSphere(GLUquadricObj *qobj,GLdouble radius,Glint slices,Glint stacks)繪制一個球形。
radius球體半徑。
stacks順着z軸分片的個數。
l void gluDisk(GLUquadricObj *qobj,GLdouble innerRadius,GLdouble outerRadius,Glint slices,Glint loops)繪制一個圓盤。
innerRadius圓盤的内部半徑,可能為0。
outerRadius圓盤的外部半徑。
loops圓盤同心圓個數。
l void gluPartialDisk(GLUquadricObj *qobj,GLdouble innerRadius,GLdouble outerRadius,Glint slices,Glint loops,GLdouble startAngle,GLdouble sweepAngle)繪制一個圓盤的一部分。
startAngle起始角度,機關為度。
sweepAngle掃描角,機關為度。
4. 像素操作
本節講解像素操作。
例14:本例在視窗繪制一個三角形,然後利用glCopyPixel函數拷貝了五次該圖形,并将這五個三角形放置在視窗的不同位置。
#include <stdlib.h>
/*設定背景色*/
glClearColor(1.0,1.0,1.0,1.0);
/*繪制彩色三角形*/
void triangle(void)
glBegin(GL_TRIANGLES);
glVertex2f(10.0,10.0);
glColor3f(0.0,0.3,1.0);
glVertex2f(20.0,30.0);
glColor3f(1.0,0.0,0.0);
glVertex2f(30.0,10.0);
void myDisplay()
glTranslatef(10.0,100.0,0.0);
triangle();
for(i = 0;i < 5;i++)
{
glRasterPos2i(20+i*30,10+i*5);//為像素操作指定光栅位置
glCopyPixels(50,200,500,500,GL_COLOR);//在緩存中拷貝像素
}
if( w <= h)
gluOrtho2D(0.0,150,0.0,150.0*(GLfloat)h/(GLfloat)w);
gluOrtho2D(0.0,150*(GLfloat)w/(GLfloat)h,0.0,150.0);
glutInitWindowSize(500,400);
glutCreateWindow(" copy ");
l glRasterPos在像素操作中指定光栅位置。同樣後面的數字表示坐标維數,2表示坐标為x、y,3表示、,y、z。數字後面的字母表示參數類型。最後帶V表示參數為指針。
l void glCopyPixels(GLint x, Glint y, GLsizei width, GLsizei height, GLenum type)函數将像素拷貝到緩存中。
x,y指定被拷貝像素的右下角坐标。
width,heigth指定被拷貝像素矩形區域的大小。
type指定拷貝數值的類型。值為顔色、深度或膜闆值。本例中為顔色。
例15:此例在視窗左下角寫單詞FILE。
/*字母F*/
GLubyte f_rasters[12] = {0xc0,0xc0,0xc0,0xc0,0xc0,0xfc,
0xfc,0xc0,0xc0,0xc0,0xff,0xff};
/*字母I*/
GLubyte i_rasters[12] = {0xff,0xff,0x18,0x18,0x18,0x18,
0x18,0x18,0x18,0x18,0xff,0xff};
/*字母L*/
GLubyte l_rasters[12] = {0xff,0xff,0xc0,0xc0,0xc0,0xc0,
0xc0,0xc0,0xc0,0xc0,0xc0,0xc0};
/*字母E*/
GLubyte e_rasters[12] = {0xff,0xff,0xc0,0xc0,0xc0,0xff,
0xff,0xc0,0xc0,0xc0,0xff,0xff};
glPixelStorei(GL_UNPACK_ALIGNMENT,1);//設定像素存儲模式
glClearColor(1.0,1.0,1.0,1.0);//設定背景為白色
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0.0,0.0,0.0);//設定像素顔色為黑色
glRasterPos2i(20,20);//為像素指定位置
/*繪制位圖*/
glBitmap(8,12,0.0,0.0,14.0,0.0,f_rasters);
glBitmap(8,12,0.0,0.0,14.0,0.0,i_rasters);
glBitmap(8,12,0.0,0.0,14.0,0.0,l_rasters);
glBitmap(8,12,0.0,0.0,14.0,0.0,e_rasters);
glOrtho(0,w,0,h,-1.0,1.0);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
glutCreateWindow(" BitMap");
/*繪制圖形*/
glutMainLoop();//進入GLUT事件處理循環
l glBitmap(GLsizei width,GLsizei height,GLfloat xorig,GLfloat yorig,GLfloat xmove,GLfloat ymove,const GLubyte *bitmap)函數繪制一個位圖。
width,height分别指定位圖圖像的寬度和高度。
xorig,yorig位圖圖像的原點位置。原點為位圖的左下角。向右和向上為坐标軸的正向。
xmove,ymove繪制完位圖後x,y相對于目前光栅的位移。
bitmap位圖圖像的位址。
你可以改變此函數的參數,觀察不同大小不同位置的效果。
5. 動畫
到目前為止我們所做的圖形全部都是靜止的。而OpenGL的是一個可以制作大型3D圖形、動畫的工具。下面我們做一個可以旋轉的立方體。
例16:一個旋轉的立方體
GLfloat X = 10.0f;
GLfloat Y = 1.0f;
GLfloat Z = 5.0f;
GLfloat diffuse[] = {0.7,0.7,0.0,1.0};
glColor3f(1.0,1.0,1.0);
/*繪制立方體*/
glRotatef(X,1.0,0.0,0.0);
glRotatef(Y,0.0,1.0,0.0);
glRotatef(Z,0.0,0.0,1.0);
glMaterialfv(GL_FRONT,GL_DIFFUSE,diffuse);
glutSolidCube(1.0);
glutSwapBuffers();//交換目前視窗使用層的緩存
gluOrtho2D(-1.5,1.5,-1.5,1.5);
if(w <= h)
glOrtho(-2.25,2.25,-2.25*h/w,2.25*h/w,-10.0,10.0);
glOrtho(-2.25*w/h,2.25*w/h,-2.25,2.25,-10.0,10.0);
void myAnimate(void)
X += 1.0;
Y += 1.0;
Z += 1.0;
glutPostRedisplay();//标記目前視窗需要重新繪制
glutCreateWindow("color");
glutIdleFunc(myAnimate);//設定全局空閑回調函數
myDisplay函數中有一個glutSwapBuffers()函數。此函數交換目前視窗使用層的緩存,它将背景緩存中的内容交換到前台緩存中,該函數執行的結果直到顯示器垂直回行掃描後才看得到。必須使用雙緩存結構,否則此函數不起任何作用。
myAanimate函數中glutPostRedisplay()函數标記目前視窗需要重新繪制。在glutMainLoop函數的事件處理循環的下一個反複中,将調用該視窗的顯示回調函數重繪該視窗的圖像層。
在main函數中glutInitDisplayMode中為GLUT_DOUBLE,而我們以前的很多例子為GLUT_SINGLE。main函數中還調用了glutIdleFunc,此函數設定全局空閑回調函數。,進而使GLUT程式可以執行背景任務或連續動畫。
6. 菜單管理
菜單是我們經常使用的工具,很友善,直覺。本節讨論在OpenGL中如何進行菜單管理。
例17:本例在藍色的背景上繪制一個白色的正方形,在視窗内單擊滑鼠右鍵,彈出菜單,當選擇不同菜單項時指令視窗會顯示出是哪個菜單的哪個菜單相被激活。本例一個主菜單,主菜單有3個菜單條目及兩個子菜單。兩個子菜單都有3個菜單條目。
#include <stdio.h>
int menu,subMenu1,subMenu2;
/*在藍色的背景上繪制一個白色的正方形*/
void myDraw(void)
glClearColor(0.0,0.0,1.0,0.0);
glOrtho(-1.0,1.0,-1.0,1.0,-1.0,1.0);
glBegin(GL_POLYGON);
glVertex2f(-0.5,-0.5);
glVertex2f(-0.5,0.5);
glVertex2f(0.5,0.5);
glVertex2f(0.5,-0.5);
/*寫出目前是哪個菜單*/
void GetCurrentMenu(void)
int nMenu;
nMenu = glutGetMenu();
if(nMenu == menu)
printf("The current menu is Main Menu.\n");
if(nMenu == subMenu1)
printf("The current menu is SubMenu1.\n");
if(nMenu == subMenu2)
printf("The current menu is SubMenu2.\n");
/*子菜單1*/
void SubMenuFunc1(int data)
GetCurrentMenu();
switch(data)
case 1:
printf("SubMenu1's item 1 is triggered.\n");
case 2:
printf("SubMenu1's item 2 is triggered.\n");
case 3:
printf("SubMenu1's item 3 is triggered.\n");
/*子菜單2*/
void SubMenuFunc2(int data)
printf("SubMenu2's item 1 is triggered.\n");
printf("SubMenu2's item 2 is triggered.\n");
printf("SubMenu2's item 3 is triggered.\n");
/*主菜單*/
void MenuFunc(int data)
printf("MainMenu's item 1 is triggered.\n");
printf("MainMenu's item 2 is triggered.\n");
printf("MainMenu's item 3 is triggered.\n");
glutCreateWindow(" MENU");
glutDisplayFunc(myDraw);
/*建立子菜單1并加入菜單條目*/
subMenu1 = glutCreateMenu(SubMenuFunc1);
glutAddMenuEntry("SubMenu1's item1",1);
glutAddMenuEntry("SubMenu1's item2",2);
glutAddMenuEntry("SubMenu1's item3",3);
glutAttachMenu(GLUT_RIGHT_BUTTON);
/*建立子菜單2并加入菜單條目*/
subMenu2 = glutCreateMenu(SubMenuFunc2);
glutAddMenuEntry("SubMenu2's item1",1);
glutAddMenuEntry("SubMenu2's item2",2);
glutAddMenuEntry("SubMenu2's item3",3);
/*建立主菜單并加入菜單條目及子菜單*/
menu = glutCreateMenu(MenuFunc);
glutAddMenuEntry("Item1",1);
glutAddMenuEntry("Item2",2);
glutAddMenuEntry("Item3",3);
glutAddSubMenu("SubMenu 1",subMenu1);
glutAddSubMenu("SubMenu 2",subMenu2);
glutAttachMenu(GLUT_RIGHT_BUTTON);
l int glutCreateMenu(void(*func)(int value))建立一個新的彈出式菜單并傳回一個唯一辨別此菜單的整型表示符。func指明此菜單的功能。
l int glutAddMenuEntry(char *name,int value)在目前菜單底部增加一個菜單條目。
name指定顯示在新菜單條目上的ASCII碼字元串。
value指定當選擇該菜單條目時傳遞到菜單回調函數中的數值。
l void glutAddSubMenu(char *name,int menu)在目前菜單的底部增加一個子菜單觸發條目。
name指定顯示在新菜單觸發條目上的ASCII碼字元串。
meun當選擇該子菜單觸發條目時彈出的子菜單的辨別符。
l void glutAttachMenu(int button)把目前視窗的一個滑鼠按鍵與目前菜單的辨別符聯系起來。
button指明滑鼠的哪個按鍵。GLUT_LEFT_BUTTON、GLUT_MIDDLE_BUTTON及GLUT_RIGHT_BUTTON,分别表明滑鼠左、中及右鍵。
l int glutGetMenu(void)擷取目前菜單的辨別符,如果沒有菜單存在或前一個目前菜單被删除了,glutGetMenu則傳回0值。
7. 小結
本文介紹了有關OpenGL的基本知識,主要涉及顔色、繪制幾何體、坐标變換、堆棧操作、顯示清單、光照和材質、紋理映射、特殊效果、曲面和曲線的繪制、二次幾何體繪制、像素操作、如何繪制動畫物體及菜單管理。OpenGL查詢函數、網格化以及互操作等許多方面都未涉及。即使涉及的有關方面也比較淺顯。但是通過對本文及本文中例子的了解消化,你可以較容易的掌握OpenGL其他知識點。相信,通過一段時間的學習,你将很快得成為OpenGL的高手。
本文轉自 21cnbao 51CTO部落格,原文連結:http://blog.51cto.com/21cnbao/120261,如需轉載請自行聯系原作者