在不少游戏中,我们都可能会出现这样的场景,我们在一个建筑内行走,这个建筑有房间也有走廊,这时候在漫游中就有这样一个要求:人不能穿墙。当人物不被绘制而是以人物视野来代替时,这个问题就抽象为漫游时视点与场景碰撞检测的问题,可以看出它和标准的碰撞检测是有区别的,一般的碰撞检测问题考虑的是两个包围盒是否存在交,而在这里我们把可以把问题变得更容易,判断视线与包围盒是否存在交,如果存在,进行怎样的修补保证不穿墙,因为我们可以发现,当视线和包围盒产生交点的时候,人就已经或者即将穿墙。同样的思想在光线追踪算法中也是适用的,我们也是给物体先做一个包围盒,然后再与光线求交。
而作为编程练习而言,我把这个问题又更进一步的简化了:使用以轴向平行的线段为边的AABB包围盒,忽略y轴信息(因为我们不需要检测是否会穿过天花板和地板),转换为二维的碰撞检测。这个时候,我们事实上判断线线是否相交即可,也就是视线和包围盒正方形的四个边分别判断是否相交。在算法导论中已经给出了判断线段相交的快速算法,在这里我们可以直接使用。
我们知道求交是一个比较麻烦的运算,当然在这里我们做的并不是求交,而是判断是否存在交点,对于计算机而言,判断是与否相比起说出是什么,要容易得多。尽管如此,这个算法依然非常糟糕,在这里我考虑到了8种一般情况和4种特殊情况,但是这些情况的判定不是完全独立的,它们之间有很小的交集,但正是这样的交集,导致情况的错误识别,整个算法在某些比较特殊的方位会穿墙,或者会出现视角跳变。这些问题都是可以通过多进行分类讨论解决,在这里暂时没有做出修正。
同样,在性能上,我们还可以做很多优化,首先,我们发现碰撞检测是在人物移动的每个按键响应事件中执行的,所有的物体无论和视点隔得有多远,我们都会进行碰撞检测的计算,这其中的计算量不能算少,更为聪明的做法应当是首先进行一个粗略的排查,把不太可能发生碰撞的物体剔除掉,后续不进行相关运算,在这里我们需要借助一些用于场景管理的数据结构,如八叉树,四叉树等等,思想是递归的二分(或更多)划分空间,最终确定物体所在空间。这里只是一个改进的方案,并没有具体实现。
当然,在这里,包围盒有内外两种,一种是我们走不出,一种是我们走不进,对于一个房间而言,那么我们应该是走不出(不考虑门),对于一个物体而言,我们应该是走不进,在这里走不出的碰撞检测实现起来比较容易,因为它的四个面不会产生干扰,不过在这里我把它写的更简单了,不考虑人物当前方向直接纠正方向为轴向,所以当人物斜撞墙时会自动纠正为贴墙走。而走不进的碰撞检测则留意改进了这一点。
以下讨论第二种碰撞检测:
8种一般情况:
//视线与A面线段相交
1.前进碰撞A面
2.后退碰撞A面
//视线与B面线段相交
3.前进碰撞B面
4.后退碰撞B面
//视线与C面线段相交
5.前进碰撞C面
6.后退碰撞C面
//视线与D面线段相交
7.前进碰撞D面
8.后退碰撞D面
4种特殊情况:
不与任何线相交,平行进入物体内部(因为存在浮点误差,这里的平行也是相对的概念)
1.平行于z轴进入A面
2.平行于z轴进入D面
3.平行于x轴进入C面
4.平行于x轴进入B面
其余内容明天将继续完成
test.h
#pragma once #define GLUT_DISABLE_ATEXIT_HACK #include "GL/GLUT.H" void drawRect(GLuint texture); void drawCube(GLuint texture); void loadTex(int i, char *filename, GLuint* texture); typedef enum { left, right, front, back }direction; void move(float* eye, float* center, direction dir); void rotate(float* eye, float* center, direction dir); void inCollisionTest(float* eye, float* center, float x1, float z1, float x2, float z2); void outCollisionTest(float* eye, float* center, float x1, float z1, float x2, float z2);
texture.cpp
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<windows.h> #include"test.h" #define BITMAP_ID 0x4D42 //读纹理图片 static unsigned char *LoadBitmapFile(char *filename, BITMAPINFOHEADER *bitmapInfoHeader) { FILE *filePtr; // 文件指针 BITMAPFILEHEADER bitmapFileHeader; // bitmap文件头 unsigned char *bitmapImage; // bitmap图像数据 int imageIdx = 0; // 图像位置索引 unsigned char tempRGB; // 交换变量 // 以“二进制+读”模式打开文件filename filePtr = fopen(filename, "rb"); if (filePtr == NULL) { printf("file not open\n"); return NULL; } // 读入bitmap文件图 fread(&bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, filePtr); // 验证是否为bitmap文件 if (bitmapFileHeader.bfType != BITMAP_ID) { fprintf(stderr, "Error in LoadBitmapFile: the file is not a bitmap file\n"); return NULL; } // 读入bitmap信息头 fread(bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, filePtr); // 将文件指针移至bitmap数据 fseek(filePtr, bitmapFileHeader.bfOffBits, SEEK_SET); // 为装载图像数据创建足够的内存 bitmapImage = new unsigned char[bitmapInfoHeader->biSizeImage]; // 验证内存是否创建成功 if (!bitmapImage) { fprintf(stderr, "Error in LoadBitmapFile: memory error\n"); return NULL; } // 读入bitmap图像数据 fread(bitmapImage, 1, bitmapInfoHeader->biSizeImage, filePtr); // 确认读入成功 if (bitmapImage == NULL) { fprintf(stderr, "Error in LoadBitmapFile: memory error\n"); return NULL; } //由于bitmap中保存的格式是BGR,下面交换R和B的值,得到RGB格式 for (imageIdx = 0; imageIdx < bitmapInfoHeader->biSizeImage; imageIdx += 3) { tempRGB = bitmapImage[imageIdx]; bitmapImage[imageIdx] = bitmapImage[imageIdx + 2]; bitmapImage[imageIdx + 2] = tempRGB; } // 关闭bitmap图像文件 fclose(filePtr); return bitmapImage; } //加载纹理的函数 void loadTex(int i, char *filename, GLuint* texture) { BITMAPINFOHEADER bitmapInfoHeader; // bitmap信息头 unsigned char* bitmapData; // 纹理数据 bitmapData = LoadBitmapFile(filename, &bitmapInfoHeader); glBindTexture(GL_TEXTURE_2D, texture[i]); // 指定当前纹理的放大/缩小过滤方式 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, //mipmap层次(通常为,表示最上层) GL_RGB, //我们希望该纹理有红、绿、蓝数据 bitmapInfoHeader.biWidth, //纹理宽带,必须是n,若有边框+2 bitmapInfoHeader.biHeight, //纹理高度,必须是n,若有边框+2 0, //边框(0=无边框, 1=有边框) GL_RGB, //bitmap数据的格式 GL_UNSIGNED_BYTE, //每个颜色数据的类型 bitmapData); //bitmap数据指针 }
test.cpp
#include<stdio.h> #include<math.h> #include"test.h" const float PI = 3.1415926536f; float min(float x, float y) { return x < y ? x : y; } float max(float x, float y) { return x > y ? x : y; } struct dot { float x; float y; dot(float _x, float _y) :x(_x), y(_y) { } }; double Direction(dot pi, dot pj, dot pk) { return (pk.x - pi.x)*(pj.y - pi.y) - (pj.x - pi.x)*(pk.y - pi.y); } bool OnSegment(dot pi, dot pj, dot pk) { if ((min(pi.x, pj.x) <= pk.x) && (pk.x <= max(pi.x, pj.x)) && (min(pi.y, pj.y) <= pk.y) && (pk.y <= max(pi.y, pj.y))) return true; else return false; } bool SegmentIntersect(dot p1, dot p2, dot p3, dot p4) { int d1, d2, d3, d4; d1 = Direction(p3, p4, p1); d2 = Direction(p3, p4, p2); d3 = Direction(p1, p2, p3); d4 = Direction(p1, p2, p4); if (((d1>0 && d2<0) || (d1<0 && d2>0)) && ((d3>0 && d4<0) || (d3<0 && d4>0))) return true; else if (d1 == 0 && OnSegment(p3, p4, p1)) return true; else if (d2 == 0 && OnSegment(p3, p4, p2)) return true; else if (d3 == 0 && OnSegment(p1, p2, p3)) return true; else if (d4 == 0 && OnSegment(p1, p2, p4)) return true; else return false; } float abs(float x) { return x >= 0 ? x : -x; } void move(float* eye, float* center, direction dir) { const float d = 1.0f; float x1, x2, y1, y2, x, y; x1 = eye[0], y1 = eye[2], x2 = center[0], y2 = center[2]; float len = sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1)); if (x2 - x1<0.1f&&x2 - x1>-0.1f)x2 = x1; if (y2 - y1 < 0.1f&&y2 - y1>-0.1f)y2 = y1; switch (dir) { case front: { eye[0] = d*(x2 - x1) / len + x1; eye[2] = d*(y2 - y1) / len + y1; center[0] = eye[0] + x2 - x1; center[2] = eye[2] + y2 - y1; break; } case back: { eye[0] = d*(x1 - x2) / len + x1; eye[2] = d*(y1 - y2) / len + y1; center[0] = eye[0] + x2 - x1; center[2] = eye[2] + y2 - y1; break; } case left: { eye[0] = d*(y2 - y1) / len + x1; eye[2] = d*(x1 - x2) / len + y1; center[0] = eye[0] + x2 - x1; center[2] = eye[2] + y2 - y1; break; } case right: { eye[0] = d*(y1 - y2) / len + x1; eye[2] = d*(x2 - x1) / len + y1; center[0] = eye[0] + x2 - x1; center[2] = eye[2] + y2 - y1; break; } default:break; } return; } void rotate(float* eye, float* center, direction dir) { const float alpha = 1.0f / (10 * PI); float x1, x2, y1, y2; x1 = eye[0], y1 = eye[2], x2 = center[0], y2 = center[2]; switch (dir) { case left: { center[0] = x1 + (x2 - x1)*cos(alpha) + (y2 - y1)*sin(alpha); center[2] = y1 + (y2 - y1)*cos(alpha) - (x2 - x1)*sin(alpha); break; } case right: { center[0] = x1 + (x2 - x1)*cos(alpha) - (y2 - y1)*sin(alpha); center[2] = y1 + (y2 - y1)*cos(alpha) + (x2 - x1)*sin(alpha); break; } default:break; } } void outCollisionTest(float* eye, float* center, float x1,float x2,float z1, float z2) { if (x1 < 0)x1 += 2; else x1 -= 2; if (x2 < 0)x2 += 2; else x2 -= 2; if (z1 < 0)z1 += 2; else z1 -= 2; if (z2 < 0)z2 += 2; else z2 -= 2; if (center[0] < x1) { center[0] = x1; } if (center[0] > x2) { center[0] = x2; } if (center[2] < z1) { center[2] = z1; } if (center[2] > z2) { center[2] = z2; } float distance = sqrt((eye[0] - center[0])*(eye[0] - center[0]) + (eye[2] - center[2])*(eye[2] - center[2])); if (distance <= 2.0f) { eye[0] = 2.0f*(eye[0] - center[0]) / distance + center[0]; eye[2] = 2.0f*(eye[2] - center[2]) / distance + center[2]; } bool flag = false; if (eye[0] < x1) { flag = true; eye[0] = x1; } if (eye[0] > x2) { flag = true; eye[0] = x2; } if (eye[2] < z1) { flag = true; eye[2] = z1; } if (eye[2] > z2) { flag = true; eye[2] = z2; } if (flag) { distance = sqrt((eye[0] - center[0])*(eye[0] - center[0]) + (eye[2] - center[2])*(eye[2] - center[2])); if (distance <=2.0f) { center[0] = 2.0f*(center[0] - eye[0]) / distance + eye[0]; center[2] = 2.0f*(center[2] - eye[2]) / distance + eye[2]; } } return; } void inCollisionTest(float* eye, float* center, float x1, float z1, float x2, float z2) { //printf("%f,%f,%f,%f\n", center[0], center[2], eye[0], eye[2]); const float d = 2.0f; float _x1 = center[0], _x2 = eye[0], _z1 = center[2], _z2 = eye[2]; float len = sqrt((_x2 - _x1)*(_x2 - _x1) + (_z2 - _z1)*(_z2 - _z1)); dot d1(eye[0], eye[2]),d2(center[0],center[2]); dot d3(x1, z1), d4(x1, z2), d5(x2, z1), d6(x2, z2); if (SegmentIntersect(d1,d2,d4,d6)) { if (center[2] < eye[2]) { printf("1\n"); center[0] = _x1 + (_x2 - _x1)*(z2 - _z1) / (_z2 - _z1); center[2] = z2; eye[0] = center[0] + d*(_x2 - _x1) / len; eye[2] = center[2] + d*(_z2 - _z1) / len; } else if (center[2] > eye[2]) { printf("2\n"); eye[0] = _x2 + (_x1 - _x2)*(z2 - _z2) / (_z1 - _z2); eye[2] = z2; center[0] = eye[0] + d*(_x1 - _x2) / len; center[2] = eye[2] + d*(_z1 - _z2) / len; } } else if (SegmentIntersect(d1, d2, d5, d6)) { if (center[0]<eye[0]) { printf("3\n"); center[0] = x2; center[2] = _z1 + (_z2 - _z1)*(x2 - _x1) / (_x2 - _x1); eye[0] = center[0] + d*(_x2 - _x1) / len; eye[2] = center[2] + d*(_z2 - _z1) / len; } else if (center[0]>eye[0]) { printf("4\n"); eye[0] = x2; eye[2] = _z2 + (_z1 - _z2)*(x2 - _x2) / (_x1 - _x2); center[0] = eye[0] + d*(_x1 - _x2) / len; center[2] = eye[2] + d*(_z1 - _z2) / len; } } else if (SegmentIntersect(d1, d2, d3, d5)) { if (center[2] > eye[2]) { printf("5\n"); center[0] = _x1 + (_x2 - _x1)*(z1 - _z1) / (_z2 - _z1); center[2] = z1; eye[0] = center[0] + d*(_x2 - _x1) / len; eye[2] = center[2] + d*(_z2 - _z1) / len; } else if (center[2] < eye[2]) { printf("6\n"); eye[0] = _x2 + (_x1 - _x2)*(z1 - _z2) / (_z1 - _z2); eye[2] = z1; center[0] = eye[0] + d*(_x1 - _x2) / len; center[2] = eye[2] + d*(_z1 - _z2) / len; } } else if (SegmentIntersect(d1, d2, d3, d4)) { if (center[0] > eye[0]) { printf("7\n"); center[0] = x1; center[2] = _z1 + (_z2 - _z1)*(x1 - _x1) / (_x2 - _x1); eye[0] = center[0] + d*(_x2 - _x1) / len; eye[2] = center[2] + d*(_z2 - _z1) / len; } else if (center[0] < eye[0]) { printf("8\n"); eye[0] = x1; eye[2] = _z2 + (_z1 - _z2)*(x1 - _x2) / (_x1 - _x2); center[0] = eye[0] + d*(_x1 - _x2) / len; center[2] = eye[2] + d*(_z1 - _z2) / len; } } else if (_x1 - _x2 < 0.1f&&_x2 - _x1 >= -0.1f && ((_z1>z1&&_z1<z2) || (_z2>z1&&_z2<z2))) { if (_x1 > x1&&_x1 < (x1 + x2) / 2) { center[0] = x1; eye[0] = x1; } else if (_x1 >(x1 + x2) / 2 && _x1 < x2) { center[0] = x2; eye[0] = x2; } } else if (_z1 - _z2 < 0.1f&&_z2 - _z1 >= -0.1f && ((_x1>x1&&_x1<x2) || (_x2>x1&&_x2<x2))) { if (_z1 > z1&&_z1 < (z1 + z2) / 2) { center[2] = z1; eye[2] = z1; } else if (_z1 >(z1 + z2) / 2 && _z1 < z2) { center[2] = z2; eye[2] = z2; } } } void drawRect(GLuint texture) { glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, texture); //选择纹理texture[status] const GLfloat x1 = -0.5, x2 = 0.5; const GLfloat y1 = -0.5, y2 = 0.5; const GLfloat point[4][2] = { { x1,y1 },{ x1,y2 },{ x2,y2 },{ x2,y1 } }; int dir[4][2] = { { 1,1 },{ 1,0 },{ 0,0 },{ 0,1 } }; glBegin(GL_QUADS); for (int i = 0; i < 4; i++) { glTexCoord2iv(dir[i]); glVertex2fv(point[i]); } glEnd(); glDisable(GL_TEXTURE_2D); } void drawCube(GLuint texture) { glEnable(GL_TEXTURE_2D); int i, j; const GLfloat x1 = -0.5, x2 = 0.5; const GLfloat y1 = -0.5, y2 = 0.5; const GLfloat z1 = -0.5, z2 = 0.5; //指定六个面的四个顶点,每个顶点用3个坐标值表示 //前 后 上 下 左 右 GLfloat point[6][4][3] = { { { x1,y1,z1 },{ x1,y2,z1 },{ x2,y2,z1 },{ x2,y1,z1 } }, { { x1,y1,z2 },{ x2,y1,z2 },{ x2,y2,z2 },{ x1,y2,z2 } }, { { x1,y2,z1 },{ x1,y2,z2 },{ x2,y2,z2 },{ x2,y2,z1 } }, { { x1,y1,z1 },{ x2,y1,z1 },{ x2,y1,z2 },{ x1,y1,z2 } }, { { x2,y1,z1 },{ x2,y2,z1 },{ x2,y2,z2 },{ x2,y1,z2 } }, { { x1,y1,z1 },{ x1,y1,z2 },{ x1,y2,z2 },{ x1,y2,z1 } }, }; int dir[6][4][2] = { { { 0,0 },{ 0,1 },{ 1,1 },{ 1,0 } }, { { 0,0 },{ 1,0 },{ 1,1 },{ 0,1 } }, { { 0,1 },{ 0,0 },{ 1,0 },{ 1,1 } }, { { 1,1 },{ 0,1 },{ 0,0 },{ 1,0 } }, { { 1,0 },{ 1,1 },{ 0,1 },{ 0,0 } }, { { 0,0 },{ 1,0 },{ 1,1 },{ 0,1 } }, }; for (i = 0; i < 6; i++) { glBindTexture(GL_TEXTURE_2D, texture); glBegin(GL_QUADS); for (j = 0; j < 4; j++) { glTexCoord2iv(dir[i][j]); glVertex3fv(point[i][j]); } glEnd(); } glDisable(GL_TEXTURE_2D); }
main.cpp
// glutEx1.cpp : 定义控制台应用程序的入口点。 // #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include"test.h" #include<io.h> #include <math.h> /* for cos(), sin(), and sqrt() */ #define roomSizeX 100 #define roomSizeY 15 #define roomSizeZ 100 GLuint texture[3]; //视区 float whRatio; int wHeight = 0; int wWidth = 0; //视点 float center[] = { 0, 0, 35 }; float eye[] = { 0, 0, 40 }; void drawScene() { //地板 glPushMatrix(); glTranslatef(0.0f, -1.0f*roomSizeY / 2.0f, 0.0f); glRotatef(90, 1, 0, 0); glScalef(roomSizeX, roomSizeZ, 1); drawRect(texture[0]); glPopMatrix(); //天花板 glPushMatrix(); glTranslatef(0.0f, 1.0f*roomSizeY / 2.0f, 0.0f); glRotatef(270, 1, 0, 0); glScalef(roomSizeX, roomSizeZ, 1); drawRect(texture[0]); glPopMatrix(); //墙壁(前) glPushMatrix(); glTranslatef(0.0f, 0.0f, -1.0f*roomSizeZ / 2.0); glRotatef(180, 1, 0, 0); glRotatef(180, 0, 0, 1); glScalef(roomSizeX, roomSizeY, 1); drawRect(texture[1]); glPopMatrix(); //墙壁(后) glPushMatrix(); glTranslatef(0.0f, 0.0f, 1.0f*roomSizeZ / 2.0f); glScalef(roomSizeX, roomSizeY, 1); drawRect(texture[1]); glPopMatrix(); //墙壁(左) glPushMatrix(); glTranslatef(-1.0f*roomSizeX / 2.0f, 0.0f, 0.0f); glRotatef(270, 0, 1, 0); glScalef(roomSizeZ, roomSizeY, 1); drawRect(texture[1]); glPopMatrix(); //墙壁(右) glPushMatrix(); glTranslatef(1.0f*roomSizeX / 2.0f, 0.0f, 0.0f); glRotatef(90, 0, 1, 0); glScalef(roomSizeZ, roomSizeY, 1); drawRect(texture[1]); glPopMatrix(); //中间墙壁 glPushMatrix(); glScalef(50, 15, 50); drawCube(texture[1]); glPopMatrix(); //箱子 glPushMatrix(); glTranslatef(-1.0f*roomSizeX / 2.0f+2.5f, -1.0f*roomSizeY / 2.0f + 2.5f, -1.0f*roomSizeZ / 2.0f + 5.0f); glScalef(5, 5, 5); drawCube(texture[2]); glPopMatrix(); glPushMatrix(); glTranslatef(-1.0f*roomSizeX / 2.0f + 2.5f, -1.0f*roomSizeY / 2.0f + 7.5f, -1.0f*roomSizeZ / 2.0f + 5.0f); glScalef(5, 5, 5); drawCube(texture[2]); glPopMatrix(); glPushMatrix(); glTranslatef(-1.0f*roomSizeX / 2.0f + 7.5f, -1.0f*roomSizeY / 2.0f + 2.5f, -1.0f*roomSizeZ / 2.0f + 5.0f); glScalef(5, 5, 5); drawCube(texture[2]); glPopMatrix(); glPushMatrix(); glTranslatef(-1.0f*roomSizeX / 2.0f + 2.5f, -1.0f*roomSizeY / 2.0f +2.5f, -1.0f*roomSizeZ / 2.0f + 10.0f); glScalef(5, 5, 5); drawCube(texture[2]); glPopMatrix(); } void updateView(int height, int width) { glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION);//设置矩阵模式为投影 glLoadIdentity(); //初始化矩阵为单位矩阵 whRatio = (GLfloat)width / (GLfloat)height; //设置显示比例 gluPerspective(45.0f, whRatio, 1.0f, 150.0f); //透视投影 //glFrustum(-3, 3, -3, 3, 3,100); glMatrixMode(GL_MODELVIEW); //设置矩阵模式为模型 } void reshape(int width, int height) { if (height == 0) //如果高度为0 { height = 1; //让高度为1(避免出现分母为0的现象) } wHeight = height; wWidth = width; updateView(wHeight, wWidth); //更新视角 } void idle() { glutPostRedisplay(); } void init() { glEnable(GL_DEPTH_TEST);//开启深度测试 glEnable(GL_LIGHTING); //开启光照模式 glGenTextures(3, texture); loadTex(0, "1.bmp", texture); loadTex(1, "6.bmp", texture); loadTex(2, "8.bmp", texture); } void key(unsigned char k, int x, int y) { switch (k) { case 27: case 'q': {exit(0); break; } //退出 case 'a': { //左移 move(eye, center, left); break; } case 'd': { //右移 move(eye, center, right); break; } case 'w': { //前移 move(eye, center, front); break; } case 's': { //后移 move(eye, center, back); break; } case 'j': {//视角左移 rotate(eye, center, left); break; } case 'l': {//视角右移 rotate(eye, center, right); break; } case 'i': {//视角上移 center[1] += 0.4f; break; } case 'k': {//视角上移 center[1] -= 0.4f; break; } } //与墙壁的碰撞检测 outCollisionTest(eye, center, -roomSizeX/2, roomSizeX / 2,-roomSizeZ/2, roomSizeZ / 2); inCollisionTest(eye, center, -30, -30, 30, 30); inCollisionTest(eye, center, -50, -45, -42, -37); inCollisionTest(eye, center, -45, -50, -37, -42); updateView(wHeight, wWidth); //更新视角 } void redraw() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//清除颜色和深度缓存 glMatrixMode(GL_MODELVIEW); glLoadIdentity(); //初始化矩阵为单位矩阵 gluLookAt(eye[0], eye[1], eye[2], center[0], center[1], center[2], 0, 1, 0); // 场景(0,0,0)的视点中心 (0,5,50),Y轴向上 glPolygonMode(GL_FRONT, GL_FILL); glFrontFace(GL_CCW); glEnable(GL_CULL_FACE); // 启用光照计算 glEnable(GL_LIGHTING); // 指定环境光强度(RGBA) GLfloat ambientLight[] = { 2.0f, 2.0f, 2.0f, 1.0f }; // 设置光照模型,将ambientLight所指定的RGBA强度值应用到环境光 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLight); // 启用颜色追踪 glEnable(GL_COLOR_MATERIAL); // 设置多边形正面的环境光和散射光材料属性,追踪glColor glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); drawScene();//绘制场景 glutSwapBuffers();//交换缓冲区 } int main(int argc, char *argv[]) { glutInit(&argc, argv);//对glut的初始化 glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE); //初始化显示模式:RGB颜色模型,深度测试,双缓冲 glutInitWindowSize(600, 600);//设置窗口大小 int windowHandle = glutCreateWindow("Simple GLUT App");//设置窗口标题 glutDisplayFunc(redraw); //注册绘制回调函数 glutReshapeFunc(reshape); //注册重绘回调函数 glutKeyboardFunc(key); //注册按键回调函数 glutIdleFunc(idle);//注册全局回调函数:空闲时调用 init(); glutMainLoop(); // glut事件处理循环 return 0; }