根据OpenGL提供的直线,多边形绘制算法(橡皮筋效果),实现基于鼠标交互的卡通人物设计与绘制。使用颜色填充与反走样技术对卡通人物外貌以及衣着进行绘制。实现对卡通人物轮廓的交互控制,点击鼠标左键可以对人物五官位置进行拖拽移动调整。按“↑”按键能够实现卡通人物绕坐标原点(或指定点)进行旋转。
附加要求:选中其中的一个多边形区域,点击鼠标右键,弹出一个菜单,可以对该区域进行不同颜色的选择。可以设计发型、衣服的模版,当作文件进行存储,可以在窗口最右边设计一个模板库,显示保存的发型与衣服,拖拽到卡通人物上可以为卡通人物进行发型或者衣服的替换。
#include
#include
#include
#include
#include
#include
#include
using namespace std;#define MAX_CHAR 128int window_width = 600;
int window_height = 400;#define LEFT_EYE 1
#define RIGHT_EYE 2
#define LEFT_ARM 3
#define RIGHT_ARM 4
#define JU_PAI 5
#define MOUTH 6
#define HAIR 7
#define TIE 8#define BUFSIZE 512GLuint selectBuf[BUFSIZE];const double PI = 3.1415926;static GLenum mode = GL_RENDER;//判断被选中的是哪个物体
BOOL leftEye_Selected;
BOOL rightEye_selected;
BOOL leftArm_Selected;
BOOL rightArm_Selected;
BOOL juPai_Selected;
BOOL mouth_Selected;
BOOL hair_Selected;
BOOL tie_Selected;/*
drawJuPai(100, 50);
drawMoxigan(220, 150);
glLoadName(RIGHT_ARM);
drawRightArm(-100, 0);glLoadName(LEFT_ARM);
drawLeftArm(-100, 0);glLoadName(MOUTH);
drawMouth(-100,60);
//画眼睛
glLoadName(LEFT_EYE);
drawLeftEye(-65,50);glLoadName(RIGHT_EYE);
drawRightEye(-135,50);
*/
//物体初始坐标
GLuint leftEye[2] = { -65, 50 };
GLuint rightEye[2] = { -135, 50 };
GLuint leftArm[2] = { -50, 0 };
GLuint rightArm[2] = { -150, 0 };
GLuint juPai[2] = { 100, 50 };
GLuint mouth[2] = { -100, 60 };
GLuint hair[2] = { 220, 150 };
GLuint tie[2] = {100,150};int body[2] = { -100, 50 };
static int theta = 0;//获取被选中改变颜色的物体
int selectedToChangeColor = -1;
//颜色数组
double lefteye_color[3] = { 1., 1., 1. };
double righteye_color[3] = { 1., 1., 1. };
double leftarm_color[3] = { 1., 1., 1. };
double rightarm_color[3] = { 1., 1., 1. };
double mouth_color[3] = { 1, 0.8, 0 };
double jupai_color[3] = { 1., 1., 1. };
double tie_color[3] = { 1.0, 0.5, 0 };
double hair_color[3] = { 0.8, 0.2, 0.8 };//菜单颜色
double black[3] = { 0., 0., 0. };
double pink[3] = { 0.95, 0.62, 0.76 };
double yellowishbrown[3] = { 1, 0.8, 0 };
double oranger[3] = { 1.0, 0.5, 0 };
double brown[3] = {0.5,0.25,0.};
double purple[3] = { 0.8, 0.2, 0.8 };
double white[3] = { 1.0, 1.0, 1.0 };GLfloat fAspect;void drawString(const char* str) {static int isFirstCall = 1;static GLuint lists;if (isFirstCall) { // 如果是第一次调用,执行初始化// 为每一个ASCII字符产生一个显示列表isFirstCall = 0;// 申请MAX_CHAR个连续的显示列表编号lists = glGenLists(MAX_CHAR);// 把每个字符的绘制命令都装到对应的显示列表中wglUseFontBitmaps(wglGetCurrentDC(), 0, MAX_CHAR, lists);}// 调用每个字符对应的显示列表,绘制每个字符for (; *str != '\0'; ++str)glCallList(lists + *str);
}
//画圆(tianchong)
void drawCircle(int N, double radius, int angleStart = 0, int angleEnd = 360, double x = 0,double y=0,double s1=1.,double s2=1.){glBegin(GL_POLYGON);double start = (double)angleStart / 360.0*N;double end = (double)angleEnd / 360 * N;for (int i = start; i
}
//画圆(不填充)
void drawCircle2(int N, double radius, int angleStart = 0, int angleEnd = 360, int x = 0, int y = 0, double s1 = 1., double s2 = 1.){glLineWidth(0.6);glBegin(GL_LINE_STRIP);double start = (double)angleStart / 360.0*N;double end = (double)angleEnd / 360 * N;for (int i = start; i
}//画左眼
void drawLeftEye(int x,int y){glLoadIdentity();glTranslatef(body[0], body[1], 0);glRotatef(theta, 0, 0, 1);glTranslatef(-body[0], -body[1], 0);//睫毛glColor3f(0.0f, 0.0f, 0.0f);glBegin(GL_LINES);glVertex3f(x+0,y+10,0.5);glVertex3f(x+0, y+15, 0.5);glVertex3f(x+5,y + 5*sqrt(3), 0.5);glVertex3f(x+10, y+13, 0.5);glVertex3f(x-5, y+5 * sqrt(3), 0.5);glVertex3f(x-10,y+13, 0.5);glEnd();//眼线drawCircle2(100, 10,0,360,x,y);//眼珠drawCircle(20, 2,0,360,x,y);//眼白glColor3f(lefteye_color[0], lefteye_color[1], lefteye_color[2]);drawCircle(20, 10,0, 360, x, y);
}
//画右眼
void drawRightEye(int x,int y){glLoadIdentity();glTranslatef(body[0], body[1], 0);glRotatef(theta, 0, 0, 1);glTranslatef(-body[0], -body[1], 0);glColor3f(0.0f, 0.0f, 0.0f);//睫毛glColor3f(0.0f, 0.0f, 0.0f);glBegin(GL_LINES);glVertex3f(x+0,y+ 10, 0.5);glVertex3f(x+0, y+15, 0.5);glVertex3f(x+5,y+ 5 * sqrt(3), 0.5);glVertex3f(x+10, y+13, 0.5);glVertex3f(x-5, y+5 * sqrt(3), 0.5);glVertex3f(x-10, y+13, 0.5);glEnd();//画眼线drawCircle2(100,10,0,360,x,y);//眼珠drawCircle(20, 2, 0, 360, x, y);//眼白glColor3f(righteye_color[0], righteye_color[1], righteye_color[2]);//glTranslatef(-40,50, 0);drawCircle(20, 10, 0, 360, x, y);}
//画嘴巴
void drawMouth(int x,int y){glLoadIdentity();glTranslatef(body[0], body[1], 0);glRotatef(theta, 0, 0, 1);glTranslatef(-body[0], -body[1], 0);//描边glColor3f(0,0,0);//下嘴唇//glTranslatef(x,y,0);drawCircle2(50, 40, 235, 305,x, y);//上色glColor3f(mouth_color[0], mouth_color[1], mouth_color[2]);drawCircle(50, 40, 235, 305,x,y);//上嘴唇//glTranslatef(0,-61,0);glColor3f(0, 0, 0);drawCircle2(50,40,55,125,x,y-61);//上色glColor3f(mouth_color[0], mouth_color[1], mouth_color[2]);drawCircle(50, 40, 55, 125,x,y-61);glColor3f(0, 0, 0);//glTranslatef(0, 30, 0);glBegin(GL_LINES);glVertex3f(x-25,y-31,0.5);glVertex3f(x+25, y-31, 0.5);glEnd();}
//画脑袋和身体
void drawHeadandBody(int x,int y){glLoadIdentity();glTranslatef(body[0], body[1], 0);glRotatef(theta, 0, 0, 1);glTranslatef(-body[0], -body[1], 0);////描边glColor3f(0,0,0);drawCircle2(50,60,0,180,x,y);glBegin(GL_LINE_STRIP);glVertex3f(x+60, y, 0.5f);glVertex3f(x+65, y-150, 0.5f);glVertex3f(x-65, y-150, 0.5f);glVertex3f(x-60, y, 0.5f);glEnd();glColor3f(1.0f, 1.0f, 1.0f);//画脑袋drawCircle(50,60,0,360,x,y);//画身体glBegin(GL_POLYGON);glVertex3f(x+60,y,0.5f);glVertex3f(x-60, y, 0.5f);glVertex3f(x-65,y-150, 0.5f);glVertex3f(x+65, y-150, 0.5f);glEnd();
}
void drawLeftArm(int x,int y){glLoadIdentity();glTranslatef(body[0], body[1], 0);glRotatef(theta, 0, 0, 1);glTranslatef(-body[0],-body[1],0);glTranslatef(x,y,0);glRotatef(30, 0, 0, 1);glTranslatef(-x,-y,0);glColor3f(1,1,1);drawCircle(50,50,180,360,x,y,0.25);glColor3f(0, 0, 0);drawCircle2(50, 50, 180, 360,x,y,0.23);drawCircle2(50, 50, 180, 360, x, y, 0.24);drawCircle2(50, 50, 180, 360, x, y, 0.25);drawCircle2(50, 50, 180, 360, x, y, 0.26);}
void drawRightArm(int x, int y){glLoadIdentity();glTranslatef(body[0], body[1], 0);glRotatef(theta, 0, 0, 1);glTranslatef(-body[0], -body[1], 0);glTranslatef(x, y, 0);glRotatef(-30, 0, 0, 1);glTranslatef(-x, -y, 0);glColor3f(1, 1, 1);drawCircle(50, 50, 180, 360, x, y, 0.25);glColor3f(0, 0, 0);drawCircle2(50, 50, 180, 360, x, y, 0.23);drawCircle2(50, 50, 180, 360, x, y, 0.24);drawCircle2(50, 50, 180, 360, x, y, 0.25);drawCircle2(50, 50, 180, 360, x, y, 0.26);}
void drawTie(int x,int y){glLoadIdentity();glTranslatef(x, y, 0);glRotatef(theta, 0, 0, 1);glTranslatef(-x, -y, 0);glTranslatef(x,y,0);glColor3f(tie_color[0],tie_color[1],tie_color[2]);glBegin(GL_POLYGON);glVertex3f(-9, 2, 0.5);glVertex3f(-9, -2, 0.5);glVertex3f(9, -2, 0.5);glVertex3f(9, 2, 0.5);glEnd();glColor3f(0, 0, 0);drawCircle2(20, 10);glColor3f(1, 0.8, 0);drawCircle(20, 10);glTranslatef(0,5,0);glColor3f(tie_color[0], tie_color[1], tie_color[2]);glBegin(GL_POLYGON);glVertex3f(-60,0,0.5);glVertex3f(-60,-10, 0.5);glVertex3f(60, -10, 0.5);glVertex3f(60, 0, 0.5);glEnd();}
void drawJuPai(int x,int y){glLoadIdentity();glTranslatef(x, y, 0);glRotatef(theta, 0, 0, 1);glTranslatef(-x, -y, 0);glTranslatef(x, y, 0);glColor3f(0, 0, 0);//描边(牌子glBegin(GL_LINE_STRIP);glVertex3f(-30, 20, 0.5);glVertex3f(-30, -20, 0.5);glVertex3f(30, -20, 0.5);glVertex3f(30, 20, 0.5);glEnd();glBegin(GL_LINE_STRIP);glVertex3f(-5, -20, 0.5);glVertex3f(-5, -50, 0.5);glVertex3f(5, -50, 0.5);glVertex3f(5, -20, 0.5);glEnd();//牌子glColor3f(jupai_color[0], jupai_color[1], jupai_color[2]);glBegin(GL_POLYGON);glVertex3f(-30, 20, 0.5);glVertex3f(-30, -20, 0.5);glVertex3f(30, -20, 0.5);glVertex3f(30, 20, 0.5);glEnd();glBegin(GL_POLYGON);glVertex3f(-5, -20, 0.5);glVertex3f(-5, -50, 0.5);glVertex3f(5, -50, 0.5);glVertex3f(5, -20, 0.5);glEnd();//手glTranslatef(-40,-70,0);glRotatef(120, 0, 0, 1);glScalef(0.25, 1, 1);glColor3f(1, 1, 1);drawCircle(100, 50, 180, 360);glColor3f(0, 0, 0);drawCircle2(100, 50, 180, 360);}void drawMoxigan(int x,int y){glLoadIdentity();glTranslatef(x, y, 0);glRotatef(theta, 0, 0, 1);glTranslatef(-x, -y, 0);glTranslatef(x,y,0);glRotatef(-50, 0, 0, 1);glColor3f(hair_color[0],hair_color[1],hair_color[2]);drawCircle(50,50,0,90);glTranslatef(50, 0, 0);glRotatef(30, 0, 0, 1);glTranslatef(-50, 0, 0);drawCircle(50, 50, 0, 90);glTranslatef(50, 0, 0);glRotatef(30,0,0,1);glTranslatef(-50,0,0);drawCircle(50, 50, 0, 90);
}void drawClothes(int x,int y){}
void myDisplay()
{/**************伊丽莎白de衣服&#xff08;开始&#xff09;**********************/if (mode&#61;&#61;GL_SELECT)glPushName(TIE);drawTie(tie[0], tie[1]);if (mode &#61;&#61; GL_SELECT)glPushName(JU_PAI);drawJuPai(juPai[0],juPai[1]);if (mode &#61;&#61; GL_SELECT)glPushName(HAIR);drawMoxigan(hair[0], hair[1]);/**************伊丽莎白de衣服&#xff08;结束&#xff09;**********************//**************伊丽莎白&#xff08;开始&#xff09;**********************/glColor3f(1.0f, 1.0f, 1.0f);if (mode &#61;&#61; GL_SELECT)glPushName(RIGHT_ARM);drawRightArm(rightArm[0], rightArm[1]);if (mode &#61;&#61; GL_SELECT)glPushName(LEFT_ARM);drawLeftArm(leftArm[0], leftArm[1]);if (mode &#61;&#61; GL_SELECT)glPushName(MOUTH);drawMouth(mouth[0],mouth[1]);//画眼睛if (mode &#61;&#61; GL_SELECT)glPushName(LEFT_EYE);drawLeftEye(leftEye[0],leftEye[1]);if (mode &#61;&#61; GL_SELECT)glPushName(RIGHT_EYE);drawRightEye(rightEye[0],rightEye[1]);//华脑袋和身体if (mode &#61;&#61; GL_SELECT)glPushName(-1);drawHeadandBody(body[0],body[1]);/**************伊丽莎白&#xff08;结束&#xff09;**********************/glPopMatrix();}void testDisplay(){glColor3f(1.0, 0.0, 0.0);if (mode &#61;&#61; GL_SELECT)glLoadName(100);glPushMatrix();glBegin(GL_QUADS);glVertex3f(-0.1, 0, 0);glVertex3f(0.1, 0, 0);glVertex3f(0.1, 0.1, 0);glVertex3f(-0.1, 0.1, 0);glEnd();glPopMatrix();/*glColor3f(0.0, 0.0, 1.0);if (mode &#61;&#61; GL_SELECT)glLoadName(101);glPushMatrix();glBegin(GL_QUADS);glVertex3f(-0.3, -0.1, 0);glVertex3f(-0.2, -0.1, 0);glVertex3f(-0.2, -0.2, 0);glVertex3f(-0.3, -0.2, 0);glEnd();glPopMatrix();*//*glColor3f(0.0, 0.0, 1.0);if (mode &#61;&#61; GL_SELECT)glLoadName(102);glPushMatrix();glBegin(GL_QUADS);glVertex3f(-0.1, -0.1, 0);glVertex3f(0.1, -0.1, 0);glVertex3f(0.1, -0.2, 0);glVertex3f(-0.1, -0.2, 0);glEnd();glPopMatrix();*///glColor3f(1.0f, 1.0f, 0.0f);//if (mode &#61;&#61; GL_SELECT)//glLoadName(102);//glPushMatrix();drawCircle(10,0.05,0,360,0.5,0.5);///*//glBegin(GL_POLYGON);//for (int i &#61; 0; i <21; i&#43;&#43;){// glVertex3f(0.5 &#43; cos(i * 2 * PI / 20)*0.05, 0.5 &#43; sin(i * 2 * PI / 20) *0.05, 0);//}//glEnd();*///glBegin(GL_POLYGON);//glVertex3f(-0.3, -0.1, 0);//glVertex3f(-0.2, -0.1, 0);//glVertex3f(-0.2, -0.2, 0);//glVertex3f(-0.3, -0.2, 0);//glEnd();//glPopMatrix();//glutSwapBuffers();
}void judegSectedObject(int x,int y){glClear(GL_COLOR_BUFFER_BIT);GLint hits, viewport[4];glGetIntegerv(GL_VIEWPORT, viewport); //获得viewport glSelectBuffer(BUFSIZE, selectBuf); //指定将“图元列表”&#xff08;点击记录&#xff09;返回到selectBuf数组中mode &#61; GL_SELECT;glRenderMode(mode); //进入选择模式glInitNames();glMatrixMode(GL_PROJECTION);//进入投影阶段准备拾取glPushMatrix();//保存原来的投影矩阵glLoadIdentity();gluPickMatrix(x, viewport[3]-y,1,1,viewport);glOrtho(-300, 300, -200, 200, -10, 10);glMatrixMode(GL_MODELVIEW);glLoadIdentity(); myDisplay();//testDisplay();glMatrixMode(GL_PROJECTION);glPopMatrix(); // 返回正常的投影变换 mode &#61; GL_RENDER;hits &#61; glRenderMode(mode);cout <
void mouseClick(int btn, int state, int x, int y){if (btn &#61;&#61; GLUT_LEFT_BUTTON&&state &#61;&#61; GLUT_DOWN){std::cout <<"鼠标落下&#xff1a;" <
}void init(){glEnable(GL_POINT_SMOOTH);glEnable(GL_LINE_SMOOTH);glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); // Make round points, not square points glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); // Antialias the lines glEnable(GL_BLEND);glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);leftEye_Selected &#61; false;rightEye_selected &#61; false;leftArm_Selected &#61; false;rightArm_Selected &#61; false;juPai_Selected &#61; false;mouth_Selected &#61; false;hair_Selected &#61; false;tie_Selected &#61; false;glEnable(GL_DEPTH_TEST);glClearColor(0.5, 0.5, 0.5, 1);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}void display(){glMatrixMode(GL_PROJECTION);glPushMatrix();glLoadIdentity();glOrtho(-300, 300, -200, 200, -10, 10);glMatrixMode(GL_MODELVIEW);//glLoadIdentity();myDisplay();glutSwapBuffers();
}
void upToRotate(int key,int x,int y){if (key &#61;&#61; GLUT_KEY_UP){theta &#43;&#61; 10;glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);display();}if (key &#61;&#61; GLUT_KEY_DOWN){theta -&#61; 10;glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);display();}}
void mouseDrag(int x, int y){std::cout <<"鼠标拖动&#xff1a;" <
}
void menu(int index){double color[3] &#61; { 0., 0., 0. };/*double yellowishbrown[3] &#61; { 1, 0.8, 0 };double oranger[3] &#61; { 1.0, 0.5, 0 };double brown[3] &#61; { 0.5, 0.25, 0. };double purple[3] &#61; { 0.8, 0.2, 0.8 };double white[3] &#61; { 1.0, 1.0, 1.0 };*/switch (index){case 0:color[0] &#61; black[0];color[1] &#61; black[1];color[2] &#61; black[2];break;case 1:color[0] &#61; pink[0];color[1] &#61; pink[1];color[2] &#61; pink[2];break;case 2:color[0] &#61; yellowishbrown[0];color[1] &#61; yellowishbrown[1];color[2] &#61; yellowishbrown[2];break;case 3:color[0] &#61; oranger[0];color[1] &#61; oranger[1];color[2] &#61; oranger[2];break;case 4:color[0] &#61; brown[0];color[1] &#61; brown[1];color[2] &#61; brown[2];break;case 5:color[0] &#61; purple[0];color[1] &#61; purple[1];color[2] &#61; purple[2];break;case 6:color[0] &#61; white[0];color[1] &#61; white[1];color[2] &#61; white[2];break;default:break;}switch (selectedToChangeColor){case LEFT_EYE:cout <<"zuoyan yanse " <
}void ChangeSize(int w, int h)
{window_width &#61; w;window_height &#61; h;if (h &#61;&#61; 0) h &#61; 1;glViewport(0, 0, w, h);fAspect &#61; (GLfloat)w / (GLfloat)h;glMatrixMode(GL_PROJECTION);glLoadIdentity();if (w <&#61; h){glOrtho(-300, 300, -200 * fAspect, 200 * fAspect, -10, 10);}else{glOrtho(-300 * fAspect, 300 * fAspect, -200, 200, -10, 10);}glMatrixMode(GL_MODELVIEW);glLoadIdentity();}
int main(int argc, char* argv[]){glutInit(&argc, argv);glutInitDisplayMode(GLUT_DOUBLE| GLUT_RGB | GLUT_DEPTH);glutInitWindowSize(window_width,window_height);glutCreateWindow("伊丽莎白");init();glutReshapeFunc(ChangeSize);glutDisplayFunc(display);glutMouseFunc(mouseClick);glutMotionFunc(mouseDrag);glutSpecialFunc(upToRotate);glutCreateMenu(menu);glutAddMenuEntry("黑色", 0);glutAddMenuEntry("粉色", 1);glutAddMenuEntry("土黄色", 2);glutAddMenuEntry("橙色",3);glutAddMenuEntry("棕色", 4);glutAddMenuEntry("紫色", 5);glutAddMenuEntry("白色", 6);glutAttachMenu(GLUT_RIGHT_BUTTON);glutMainLoop();return 0;
}
运行效果&#xff1a;