效果图如上:
步骤:略,构成顺序参考下图1、2。
图1 城墙构成顺序说明图:
图2 塔楼构成说明图:略
实现代码如下:
main.cpp
1 /********************************************************************** 2 3 Castle - using Display Lists 4 5 June, 12th, 2000 6 7 This tutorial was written by Philipp Crocoll 8 Contact: 9 philipp.crocoll@web.de 10 www.codecolony.de 11 12 Every comment would be appreciated. 13 14 If you want to use parts of any code of mine: 15 let me know and 16 use it! 17 ********************************************************************** 18 ESC: exit 19 20 CAMERA movement: 21 w : forwards 22 s : backwards 23 a : turn left 24 d : turn right 25 x : turn up 26 y : turn down 27 v : strafe right 28 c : strafe left 29 r : move up 30 f : move down 31 32 **********************************************************************/ 33 34 35 #include//includes gl.h and glu.h 36 #include //sine and cosine functions 37 #include "camera.h" 38 #include 39 #define PI 3.1415265359 40 41 static GLfloat MatSpec[] = { 1.0,1.0,1.0,1.0}; 42 static GLfloat MatShininess[] = { 45.0}; 43 static GLfloat LightPos[] = {-2.0,1.5,1.0,0.0}; 44 static GLfloat ModelAmb[] = { 0.5,0.5,0.5,0.0}; 45 46 47 CCamera Camera; 48 49 GLint TowerListNum,WallsListNum; //Numbers of the display lists 50 GLint WallsList; 51 //Tower properties: 52 int NumOfEdges = 12; // 塔身弯曲的精细度 53 GLfloat LowerHeight =3.0; // 塔顶圆台的最小半径 54 GLfloat HigherHeight = 3.5; // 塔顶圆台的最大半径 55 GLfloat HR = 1.3; //Radius of the highest part // 塔顶的半径 56 57 //Wall properties: 58 GLfloat WallElementSize = 0.4; // 城墙的突出部分的长度 59 GLfloat WallHeight = 2.0; // 城墙的高度 60 61 // 画出更高的墙部分--突出的墙垣 62 void DrawHigherWallPart(int NumElements) 63 /*Draws a wall part like this: 64 ___ ___ ___ 65 | | | | | | 66 |___| |___| |___| 67 and so on 68 such an element is squareshaped and has the height/width WallElementSize*/ 69 { 70 glBegin(GL_QUADS); 71 for (int i = 0; i < NumElements; i++) 72 { 73 glNormal3f(0.0,0.0,-1.0); 74 glVertex3f(i*2.0 * WallElementSize, 0.0, 0.0); 75 glVertex3f(i*2.0 * WallElementSize, WallElementSize, 0.0); 76 glVertex3f((i*2.0+1.0) * WallElementSize, WallElementSize, 0.0); 77 glVertex3f((i*2.0+1.0) * WallElementSize, 0.0, 0.0); 78 79 } 80 81 glEnd(); 82 83 } 84 85 // 画出墙体的部分 86 void DrawWall(GLfloat Length) 87 { 88 glBegin(GL_QUADS); 89 glNormal3f(0.0,0.0,-1.0); // 设置法向量 90 glVertex3f(0.0,0.0,0.0); 91 glVertex3f(0.0,WallHeight,0.0); 92 glVertex3f(Length,WallHeight,0.0); 93 glVertex3f(Length,0.0,0.0); 94 glEnd(); 95 // 画出城墙的突出部分。 96 int i = (int)(Length / WallElementSize / 2); 97 if (i * WallElementSize > Length) i--; 98 glPushMatrix(); 99 glTranslatef(0.0,WallHeight,0.0);100 DrawHigherWallPart(i);101 glPopMatrix();102 }103 104 105 106 void Init(void) //used to create the display lists107 {108 TowerListNum = glGenLists(1); // 会生成一组连续的空的显示列表109 GLfloat x,z;110 int i=0;111 GLfloat NVectY; //y component for the NVects of the higher part // y分量的NVects更高的一部分112 113 glNewList(TowerListNum, GL_COMPILE); // 用于创建和替换一个显示列表函数原型114 glBegin(GL_QUADS); // 四边形 115 //Create the lower part of the tower: // 创建塔身的圆柱形部分116 for (i = 0; i < NumOfEdges-1; i++)117 { 118 x = cos((float)i/(float)NumOfEdges * PI * 2.0);119 z = sin((float)i/(float)NumOfEdges * PI * 2.0);120 glNormal3f(x,0.0,z);121 glVertex3f(x,LowerHeight,z);122 //same x,z and NVect:123 glVertex3f(x,0.0,z);124 125 x = cos((float)(i+1)/(float)NumOfEdges * PI * 2.0);126 z = sin((float)(i+1)/(float)NumOfEdges * PI * 2.0);127 glNormal3f(x,0.0,z);128 glVertex3f(x,0.0,z);129 //same x,z and NVect:130 glVertex3f(x,LowerHeight,z);131 }132 // 塔身侧面的连接处 133 x = cos((float)i/(float)NumOfEdges * PI * 2.0);134 z = sin((float)i/(float)NumOfEdges * PI * 2.0);135 glNormal3f(x,0.0,z);136 glVertex3f(x,LowerHeight,z);137 //same x,z and NVect:138 glVertex3f(x,0.0,z);139 x = cos(1.0/(float)NumOfEdges * PI * 2.0);140 z = sin(1.0/(float)NumOfEdges * PI * 2.0);141 glNormal3f(x,0.0,z);142 glVertex3f(x,0.0,z);143 //same x,z and NVect:144 glVertex3f(x,LowerHeight,z);145 146 147 //Create the higher part: // 创建塔顶的倒梯形部分。148 149 //The y component is the same for all NVects, so we can calculate it here:150 // 对所有NVects y分量是一样的,所以在这里我们可以计算:151 NVectY = (HR-1.0) / (LowerHeight - HigherHeight) * (HR-1.0); // = (1.3-1.0)/(3.5-3.0)*(1.3-1.0)152 153 for (i = 0; i < NumOfEdges-1; i++)154 { 155 x = cos((float)i/(float)NumOfEdges * PI * 2.0);156 z = sin((float)i/(float)NumOfEdges * PI * 2.0);157 glNormal3f(x,NVectY,z);158 glVertex3f(x*HR,HigherHeight,z*HR);159 //same x,z and NVect:160 glVertex3f(x,LowerHeight,z);161 162 x = cos((float)(i+1)/(float)NumOfEdges * PI * 2.0);163 z = sin((float)(i+1)/(float)NumOfEdges * PI * 2.0);164 glNormal3f(x,NVectY,z);165 glVertex3f(x,LowerHeight,z);166 //same x,z and NVect:167 glVertex3f(x*HR,HigherHeight,z*HR);168 }169 // 塔顶侧面的连接处170 x = cos((float)i/(float)NumOfEdges * PI * 2.0);171 z = sin((float)i/(float)NumOfEdges * PI * 2.0);172 glNormal3f(x,NVectY,z);173 glVertex3f(x*HR,HigherHeight,z*HR);174 //same x,z and NVect:175 glVertex3f(x,LowerHeight,z);176 x = cos(1.0/(float)NumOfEdges * PI * 2.0);177 z = sin(1.0/(float)NumOfEdges * PI * 2.0);178 glNormal3f(x,NVectY,z);179 glVertex3f(x,LowerHeight,z);180 //same x,z and NVect:181 glVertex3f(x*HR,HigherHeight,z*HR);182 183 glEnd();184 glEndList();185 186 187 188 //WallList189 190 191 192 WallsListNum = glGenLists(1); // 创建显示列表1个193 glNewList(WallsListNum, GL_COMPILE);194 DrawWall(10.0); // 绘制墙面=1195 glPushMatrix(); // 压栈1196 197 glTranslatef(10.0,0.0,0.0); // 移动到点2198 199 glPushMatrix(); // 压栈2200 glRotatef(270.0,0.0,1.0,0.0);201 DrawWall(10.0); // 绘制墙面=2202 glPopMatrix(); // 出栈2203 204 glTranslatef(0.0,0.0,10.0); // 向前10个单位 // 移动到点3205 206 glPushMatrix(); // 压栈3207 glRotatef(180.0,0.0,1.0,0.0);208 DrawWall(5.0); // 绘制墙面=3209 glRotatef(90.0,0.0,1.0,0.0);210 glTranslatef(0.0,0.0,5.0);211 DrawWall(5.0); // 绘制墙面=4212 glPopMatrix();// 出栈3213 214 glTranslatef(-5.0,0.0,5.0); // 移动到点4215 216 glPushMatrix(); // 压栈4217 glRotatef(180.0,0.0,1.0,0.0);218 DrawWall(5.0); // 绘制墙面=5219 glPopMatrix(); // 出栈4220 221 //Last and longest piece:222 glPushMatrix(); // 压栈5223 glRotatef(90.0,0.0,1.0,0.0);224 glTranslatef(0.0,0.0,-5.0); // // 移动到点5225 DrawWall(6.0); // // 绘制墙面=7226 //the "door"227 glTranslatef(6.0,0.0,0.0);228 // 绘制墙面=8229 glBegin(GL_QUADS);230 glNormal3f(0.0,0.0,-1.0);231 glVertex3f(0.0,WallHeight / 2.0,0.0);232 glVertex3f(0.0,WallHeight,0.0);233 glVertex3f(3.0,WallHeight,0.0); // 门的宽度=3.0234 glVertex3f(3.0,WallHeight / 2.0,0.0); 235 glEnd();236 237 i = (int)(3.0 / WallElementSize / 2);238 if (i * WallElementSize > 3.0) i--;239 240 glPushMatrix();// 压栈6241 glTranslatef(0.0,WallHeight,0.0);242 DrawHigherWallPart(i); // 绘制城墙的顶部243 glPopMatrix(); // 出栈6244 245 glTranslatef(3.0,0.0,0.0);246 DrawWall(6.0);// 绘制墙面=9247 glPopMatrix(); // 出栈5248 249 glPopMatrix(); // 出栈1250 251 glEndList();252 }253 254 void Display(void)255 {256 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);257 glLoadIdentity(); 258 Camera.Render();259 glLightfv(GL_LIGHT0,GL_POSITION,LightPos);260 glTranslatef(-7.0,2.0,-7.0);261 glRotatef(90.0,0.0,1.0,0.0);262 glBegin(GL_POLYGON);263 glNormal3f(0.0,1.0,0.0); // 法向量= y轴264 glVertex3f(0.0,0.0,0.0); // 编号点=1265 glVertex3f(10.0,0.0,0.0); // 编号点=2266 glVertex3f(10.0,0.0,10.0); // 编号点=3267 glVertex3f(5.0,0.0,15.0); // 编号点=4268 glVertex3f(0.0,0.0,15.0); // 编号点=5269 glVertex3f(0.0,0.0,0.0);// 编号点=1270 glEnd();271 272 273 //Turn two sided lighting on for the walls274 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);275 276 glCallList(WallsListNum); // 调用城墙的显示列表277 278 //Disable it again for the towers: // 关闭它,塔楼不使用279 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);280 281 282 glCallList(TowerListNum); // 目前点=1283 284 glTranslatef(10.0,0.0,0.0) ; // 移动到点=2285 glCallList(TowerListNum);286 287 glTranslatef(0.0,0.0,10.0); // 移动到点=3288 glCallList(TowerListNum);289 290 glTranslatef(-5.0,0.0,5.0); // 移动到点=4291 glCallList(TowerListNum);292 293 glTranslatef(-5.0,0.0,0.0); // 移动到点=5294 glCallList(TowerListNum);295 296 glFlush(); //Finish rendering297 glutSwapBuffers(); //Swap the buffers ->make the result of rendering visible298 }299 void Reshape(int x, int y)300 {301 if (y == 0 || x == 0) return; //Nothing is visible then, so return302 //Set a new projection matrix303 glMatrixMode(GL_PROJECTION); // 投影模式304 glLoadIdentity();305 //Angle of view:40 degrees306 //Near clipping plane distance: 0.5307 //Far clipping plane distance: 20.0308 gluPerspective(40.0,(GLdouble)x/(GLdouble)y,1.0,200.0); // 投影范围。309 glMatrixMode(GL_MODELVIEW); // 视景模式。310 glViewport(0,0,x,y); 311 }312 void KeyDown(unsigned char key, int x, int y)313 { 314 switch(key)315 {316 case 27: //ESC317 exit(0);318 break;319 case 'a': 320 Camera.RotateY(5.0);321 Display();322 break;323 case 'd': 324 Camera.RotateY(-5.0);325 Display();326 break;327 case 'w': 328 Camera.MoveForwards( -0.3 ) ;329 Display();330 break;331 case 's': 332 Camera.MoveForwards( 0.3 ) ;333 Display();334 break;335 case 'x': 336 Camera.RotateX(5.0);337 Display();338 break;339 case 'y': 340 Camera.RotateX(-5.0);341 Display();342 break;343 case 'c': 344 Camera.StrafeRight(-0.3);345 Display();346 break;347 case 'v': 348 Camera.StrafeRight(0.3);349 Display();350 break;351 case 'f':352 Camera.Move(F3dVector(0.0,-0.3,0.0));353 Display();354 break;355 case 'r':356 Camera.Move(F3dVector(0.0,0.3,0.0));357 Display();358 break;359 360 361 }362 }363 364 int main(int argc, char **argv)365 { 366 glutInit(&argc, argv);367 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);368 glutInitWindowSize(600,600);369 glutCreateWindow("Castle");370 glEnable(GL_DEPTH_TEST); // 深度测试371 glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); // 设置正反面为线形模式372 glClearColor(0.0,0.0,0.0,0.0); // 黑色373 glutDisplayFunc(Display);374 glutReshapeFunc(Reshape);375 glutKeyboardFunc(KeyDown);376 Camera.Move(F3dVector(0.0,5.0,20.0)); // 摄像机的位置。377 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, MatSpec); // 材质属性中的镜面反射光 378 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, MatShininess); // //材质属性的镜面反射指数 379 glEnable(GL_LIGHTING);380 glEnable(GL_LIGHT0);381 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ModelAmb); // 设置光照模式(全局环境光)382 Init();383 glutMainLoop();384 return 0;385 }
原始代码来源:http://www.codecolony.de/