实验名称:二维卡通人脸交互设计与控制
实验要求:
- 根据OpenGL提供的直线,多边形绘制算法,实现基于鼠标交互的卡通人物设计与绘制。
- 使用颜色填充与反走样技术对人脸进行绘制。
- 实现对卡通人脸的交互控制,点击鼠标左键可以对人脸进行拖拽移动。
- 按“↑”按键能够实现卡通人脸绕坐标原点进行旋转。
- 附加要求:选中其中的一个多边形区域,点击鼠标右键,弹出一个菜单,可以对该区域进行不同颜色的选择。
实验步骤:左击选择对象,右击染色。按住向上箭头逆时针旋转,按住向下箭头顺时针旋转。
实验截图:
实验源码:
#include <Windows.h> #include <gl\glut.h> #include <stdio.h> #include<math.h> #define PI 3.14 #define SIZE 512 #define FACE 1 #define NOSE 2 #define MOUTH 3 #define HAIR 4 #define BROW 5 #define EYES 6 static int FACE_COLOR = 7; static int NOSE_COLOR = 6; static int MOUTH_COLOR = 1; static int HAIR_COLOR = 4; static int BROW_COLOR = 5; static int EYES_COLOR = 0; static GLfloat theta = 0; static GLfloat t_x = 0; static GLfloat t_y = 0; int select_part = 0; static int o_x = 0; static int o_y = 0; #define WIN_WIDTH 500 #define WIN_HEIGHT 500 #define VIEW_WIDTH 2.2 #define VIEW_HEIGHT 2.2 static GLfloat colors[8][3] = { { 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 }, { 0.0, 0.0, 1.0 }, { 0.0, 1.0, 1.0 }, { 1.0, 0.0, 1.0 }, { 1.0, 1.0, 0.0 }, { 1.0, 1.0, 1.0 } }; //画眼睛 void drawEyes(){ glBegin(GL_POLYGON); glVertex2f( -0.27, 0.12); glVertex2f( -0.27, 0.18); glVertex2f( -0.33, 0.18); glVertex2f( -0.33, 0.12); glEnd(); glBegin(GL_POLYGON); glVertex2f( 0.27, 0.12); glVertex2f( 0.27, 0.18); glVertex2f( 0.33, 0.18); glVertex2f( 0.33, 0.12); glEnd(); } //画眉毛 void drawBrow(){ glLineWidth(5); glBegin(GL_LINES); glVertex2f( -0.4, 0.3); glVertex2f( -0.2, 0.2); glVertex2f( 0.2, 0.2); glVertex2f( 0.4, 0.3); glEnd(); } //画头发 void drawHair(){ glBegin( GL_TRIANGLE_FAN); glVertex2f( 0.4, 0.9); glVertex2f( -0.5, 0.8); glVertex2f( -0.8, 0.3); glVertex2f( 0.1, 0.5); glVertex2f( 0.2, 0.3); glVertex2f( 0.5, 0.5); glVertex2f( 0.8, 0.4); glEnd(); } //画脸 void drawFace(){ glBegin(GL_POLYGON); glVertex2f( -0.5 , 0.5); glVertex2f( -0.4 , -0.5); glVertex2f( 0.0 , -0.8); glVertex2f( 0.4 , -0.5); glVertex2f( 0.5 , 0.5); glEnd(); } //画嘴巴 void drawMouth(){ glBegin( GL_POLYGON); glVertex2f( -0.2, -0.4); glVertex2f( -0.1, -0.6); glVertex2f( 0.1, -0.6); glVertex2f( 0.2, -0.4); glEnd(); } //画鼻子 void drawNose(){ glBegin( GL_TRIANGLES); glVertex2f( 0, 0.1); glVertex2f( -0.1, -0.3); glVertex2f( 0.1, -0.3); glEnd(); } //绘制函数 void drawObjects(GLenum mode) { if(mode == GL_SELECT) glLoadName(FACE); //画脸 glColor3f(colors[FACE_COLOR][0],colors[FACE_COLOR][1],colors[FACE_COLOR][2]); drawFace(); if(mode == GL_SELECT) glLoadName(NOSE); //画鼻子 glColor3f(colors[NOSE_COLOR][0],colors[NOSE_COLOR][1],colors[NOSE_COLOR][2]); drawNose(); if(mode == GL_SELECT) glLoadName(MOUTH); //画嘴巴 glColor3f(colors[MOUTH_COLOR][0],colors[MOUTH_COLOR][1],colors[MOUTH_COLOR][2]); drawMouth(); if(mode == GL_SELECT) glLoadName(HAIR); //画头发 glColor3f(colors[HAIR_COLOR][0],colors[HAIR_COLOR][1],colors[HAIR_COLOR][2]); drawHair(); if(mode == GL_SELECT) glLoadName(BROW); //画眉毛 glColor3f(colors[BROW_COLOR][0],colors[BROW_COLOR][1],colors[BROW_COLOR][2]); drawBrow(); if(mode == GL_SELECT) glLoadName(EYES); //画眼睛 glColor3f(colors[EYES_COLOR][0],colors[EYES_COLOR][1],colors[EYES_COLOR][2]); drawEyes(); } void myDisplay(){ //清除缓存 glClear(GL_COLOR_BUFFER_BIT); //旋转 glLoadIdentity(); //如果是绕人脸原点 //glTranslatef(t_x, t_y, 0.0); //glRotatef(theta, 0.0, 0.0, 1.0); //如果是绕系统原点 glRotatef(theta, 0.0, 0.0, 1.0); glTranslatef(t_x, t_y, 0.0); //RANDER模式绘制物体 drawObjects(GL_RENDER); //绘制 glFlush(); } void myInit(){ glClearColor(0.0, 0.0, 0.0, 1.0); } void myRreshape(int w, int h){ glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(-VIEW_WIDTH/2,VIEW_WIDTH/2,-VIEW_HEIGHT/2,VIEW_HEIGHT/2); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); //开启反走样 glEnable( GL_BLEND); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glHint( GL_POLYGON_SMOOTH_HINT, GL_NICEST); glEnable( GL_POLYGON_SMOOTH); glEnable( GL_POINT_SMOOTH); glEnable( GL_LINE_SMOOTH); } //处理点击事件 void processHits (GLint hits, GLuint buffer[]) { unsigned int i, j; GLuint names, *ptr; printf("一共打中%d个!\n", hits); ptr=(GLuint *) buffer; for (i = 0; i < hits; i++) {/* for each hit */ names = *ptr; ptr+=3; for (j = 0; j < names; j++) { /* for each name */ if(*ptr==1){ printf ("打脸\n"); } else if(*ptr==2){ printf ("鼻子\n"); select_part = NOSE; } else if(*ptr==3){ printf ("嘴巴\n"); select_part = MOUTH; } else if(*ptr==4){ printf ("头发\n"); select_part = HAIR; } else if(*ptr==5){ printf ("眉毛\n"); select_part = BROW; } else if(*ptr==6){ printf ("眼睛\n"); select_part = EYES; } ptr++; } } printf ("select_part:%d\n",select_part); } static bool left_down = false; //脸移动 void myMouseMove(int x,int y){ if(left_down){ GLfloat d_x = (x - o_x) * VIEW_WIDTH / WIN_WIDTH; GLfloat d_y = (o_y - y) * VIEW_HEIGHT / WIN_HEIGHT; //如果绕着脸中心转 //t_x += d_x; //t_y += d_y; //将鼠标偏移量旋转-theta t_x += d_x*cos(-2*PI*theta/360)-d_y*sin(-2*PI*theta/360); t_y += d_x*sin(-2*PI*theta/360)+d_y*cos(-2*PI*theta/360); //记录下鼠标的坐标 o_x = x; o_y = y; glutPostRedisplay(); } } //鼠标响应 void myMouse(int button, int state, int x, int y){ GLuint selectBuf[SIZE]; GLint hits; GLint viewport[4]; if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) { left_down = true; o_x = x; o_y = y; } if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) { left_down = false; glGetIntegerv(GL_VIEWPORT, viewport); glSelectBuffer (SIZE, selectBuf); glRenderMode(GL_SELECT); glInitNames(); glPushName(0); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluPickMatrix((GLdouble) x, (GLdouble) (viewport[3] - y),3.0, 3.0, viewport); gluOrtho2D(-VIEW_WIDTH/2,VIEW_WIDTH/2,-VIEW_HEIGHT/2,VIEW_HEIGHT/2); drawObjects(GL_SELECT); glPopMatrix(); glMatrixMode(GL_MODELVIEW); hits = glRenderMode(GL_RENDER); processHits(hits, selectBuf); glutPostRedisplay(); } } void mySpecial(int key, int x, int y){ switch (key) { case GLUT_KEY_UP: theta = (theta+10); glutPostRedisplay(); break; case GLUT_KEY_DOWN: theta = (theta-10); glutPostRedisplay(); break; } } void myKeyboard(unsigned char key, int x, int y){ switch (key) { } } void main_menu(int index) { if(index == -1) return; switch (select_part) { case FACE: FACE_COLOR = index; break; case NOSE: NOSE_COLOR = index; break; case MOUTH: MOUTH_COLOR = index; break; case HAIR: HAIR_COLOR = index; break; case BROW: BROW_COLOR = index; break; case EYES: EYES_COLOR = index; break; } glutPostRedisplay(); } void main(int argc,char** argv){ glutInit(&argc,argv); glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB); glutInitWindowSize(500,500); glutInitWindowPosition(0,0); glutCreateWindow("OpenGL_01"); myInit(); glutReshapeFunc(myRreshape); glutDisplayFunc(myDisplay); glutMouseFunc(myMouse); glutKeyboardFunc(myKeyboard); glutSpecialFunc(mySpecial); glutMotionFunc(myMouseMove); //右击事件 glutCreateMenu(main_menu); glutAddMenuEntry("左击选择染色对象", -1); glutAddMenuEntry("黑色", 0); glutAddMenuEntry("红色", 1); glutAddMenuEntry("绿色", 2); glutAddMenuEntry("蓝色", 3); glutAddMenuEntry("青色", 4); glutAddMenuEntry("紫色", 5); glutAddMenuEntry("黄色", 6); glutAddMenuEntry("白色", 7); glutAttachMenu(GLUT_RIGHT_BUTTON); glutMainLoop(); }