#define GLUT_DISABLE_ATEXIT_HACK #include
#include "gl/glut.h" #pragma comment(lib, "glut32.lib")
#define GL_PI 3.1415f #define RADIUS 50.0f #define SIZE 100.0f
GLboolean bDepth=false; GLboolean bOutline=false; GLfloat fVers[8][3];
void CreatMenu() { glutAddMenuEntry("深度检测",1); //添加菜单项 glutAddMenuEntry("线框或实体",2);
glutAttachMenu(GLUT_RIGHT_BUTTON); //指定菜单事件由右击产生 } //设置光照 void SetupLights() { GLfloat ambientLight[] ={0.2f, 0.2f, 0.2f, 1.0f};//环境光 GLfloat diffuseLight[] ={0.9f, 0.9f, 0.9f, 1.0f};//漫反射 GLfloat lightPos[] ={50.0f, 80.0f, 60.0f, 1.0f};//光源位置 glEnable(GL_LIGHTING); //启用光照 glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight); //设置环境光源 glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight); //设置漫反射光源 glLightfv(GL_LIGHT0, GL_POSITION, lightPos); //设置灯光位置
glEnable(GL_LIGHT0); //打开第一个灯光 glEnable(GL_COLOR_MATERIAL); //启用材质的颜色跟踪 glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);//指定材料着色的面
} //归一化法向量 void Unitlize(GLfloat *vertex) { GLfloat len = GLfloat(sqrt(vertex[0] * vertex[0] + vertex[1] * vertex[1] + vertex[2] * vertex[2])); if (len == 0.0f) { len=1.0f; } vertex[0] /= len; vertex[1] /= len; vertex[2] /= len; } //计算各顶点坐标 void CalaulateVertices(GLfloat vers[8][3]) { GLfloat angle; GLint i = 1;
vers[0][0] = vers[0][1] = 0.0f; vers[0][2] = 75.0f;
for (angle = 0.0f; angle < 2.1f * GL_PI; angle += GL_PI / 3, i++) { vers[i][0] = RADIUS * sin(angle); vers[i][1] = RADIUS * cos(angle); vers[i][2] = 0.0f; } } //计算并归一化法向量 void CalaulateNormal(GLfloat vertices[3][3], GLfloat *normal) { GLfloat v1[3], v2[3];
v1[0] = vertices[0][0] = vertices[1][0]; v1[1] = vertices[0][1] = vertices[1][1]; v1[2] = vertices[0][2] = vertices[1][2]; v2[0] = vertices[1][0] = vertices[2][0]; v2[1] = vertices[1][1] = vertices[2][1]; v2[2] = vertices[1][2] = vertices[2][2];
normal[0] = v1[1] * v2[2] - v1[2] * v2[1]; normal[1] = v1[0] * v2[2] - v1[2] * v2[0]; normal[2] = v1[1] * v2[0] - v1[0] * v2[1];
Unitlize(normal);//归一化 } void OnDisplay(void) { GLint i; GLfloat ver[3][3], nor[3];
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//清除颜色和深度缓冲区 if (bDepth) { glEnable(GL_DEPTH_TEST); //启用深度检测 } else { glDisable(GL_DEPTH_TEST);//关闭深度检测 } if (bOutline) { glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); //以线框形式进行绘制 } else { glPolygonMode(GL_FRONT, GL_FILL); //以实体形式进行绘制 } glPushMatrix(); { glRotatef(75, 1.0f, 0.0f, 0.0f); glRotatef(150, 0.0f, 1.0f, 0.0f); glTranslatef(0.0f, -25.0f, -25.0f);
glFrontFace(GL_CW); //指定多边形成型方式为顺时针 glColor3f(0.0f, 1.0f, 0.0f);//指定绘图颜色为绿色 glBegin(GL_TRIANGLE_FAN); //利用三角扇形绘制六棱锥的六个侧面 { ver[0][0] = fVers[0][0]; ver[0][1] = fVers[0][1]; ver[0][2] = fVers[0][2]; glVertex3f(fVers[0][0], fVers[0][1], fVers[0][2]); for (i = 1; i < 8; i++) { ver[1][0] = fVers[i][0]; ver[1][1] = fVers[i][1]; ver[1][2] = fVers[i][2]; if(i <= 7) { ver[2][0] = fVers[i + 1][0]; ver[2][1] = fVers[i + 1][1]; ver[2][2] = fVers[i + 1][2]; } else { ver[2][0] = fVers[1][0]; ver[2][1] = fVers[1][1]; ver[2][2] = fVers[1][2]; } CalaulateNormal(ver, nor); //计算并归一化法向量 glNormal3fv(nor); //设置法向量 glVertex2f(fVers[i][0], fVers[i][1]); } } glEnd();
glBegin(GL_TRIANGLE_FAN); //利用三角扇形绘制六棱锥的顶面 { glNormal3f(0.0f, 0.0f, 1.0f); //指定法向量 glVertex2f(fVers[0][0], fVers[0][1]); for (i = 7; i > 0; i--) { glNormal3f(0.0f, 0.0f, 1.0f); //指定法向量 glVertex2f(fVers[i][0], fVers[i][1]); } } glEnd(); } glPopMatrix(); glutSwapBuffers(); //交换前后缓冲区(相当于刷新显示) } void OnReshape(int w,int h) { GLfloat aspect = (GLfloat)w / (GLfloat)h; GLfloat nRange = 100.0f;
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION); //将当前矩阵指定为投影模式 glLoadIdentity();
//设置三维投影区
if (w <= h) { glOrtho(-nRange, nRange, -nRange / aspect, nRange / aspect, -nRange, nRange); } else { glOrtho(-nRange, nRange, -nRange * aspect, nRange * aspect, -nRange, nRange); } glMatrixMode(GL_MODELVIEW); //将当前矩阵恢复为模型视图模式 glLoadIdentity(); } void OnMenu(int value) { switch(value) //当前用户选择的菜单项的ID { case 1: bDepth = !bDepth; break; case 2: bOutline = !bOutline; }
glutPostRedisplay(); //强制显示刷新 } int main(int argc, char* argv[]) { glutInit(&argc, argv); //初始化OpenGL glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); //设置显示模式 glutInitWindowSize(600, 480); glutCreateWindow("利用平面图元构造三维实体");
glutCreateMenu(OnMenu); glutReshapeFunc(OnReshape); glutDisplayFunc(OnDisplay);
CreatMenu(); //实际生成菜单(对于windows应用程序,这里的菜单技术是无效的,因为windows有自己的菜单系统) SetupLights(); //设置光照 CalaulateVertices(fVers); //计算所绘实体各顶点的坐标 glutMainLoop(); //进入OpenGL主循环 return 0; }