交互式卡通人物

来源:互联网 发布:java一本糊涂账编写 编辑:程序博客网 时间:2024/04/29 09:45

计算机图形学实验一,参考了汪海学长的逻辑结构吐舌头吐舌头,膜拜大佬,抱拳!
觉得学到的最有意思的就是OpenGL的拾取模式,各个模式之间的切换并且互不打扰很厉害。 看到的讲的比较清楚的文章:链接1,链接2


#include "stdafx.h"#include <Windows.h>  #include <gl/glut.h>  #include <stdio.h>    #include <math.h>  #define PI 3.14  #define SIZE 512    #define BODY 1#define EYES 2 #define NOSE 3 #define MOUTH 4  #define SKIMMER 5static bool EYE_STATE = FALSE;static bool NOSE_STATE = FALSE;static bool MOUTH_STATE = FALSE;static bool SKIMMER_STATE = FALSE;//左眼和鼻子的拖动会用到static float eye[2] = { -0.12, 0.9 };static float nose[2] = { 0.0, 0.7 };static float skimmer[2] = { 1.6f, 0.7f };static int select_part = -1;static int NOSE_COLOR = 1;static int MOUTH_COLOR = 0;static int EYES_COLOR = 7;static GLfloat theta = 0;static GLfloat t_x = 0;static GLfloat t_y = 0;static int o_x = 0;static int o_y = 0;//这里为什么这样修改?#define VIEW_WIDTH  4#define VIEW_HEIGHT  4#define WIN_WIDTH 500  #define WIN_HEIGHT 500  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 drawEllipseCircle(float dx, float dy, GLfloat r1, GLfloat r2, int num){glBegin(GL_TRIANGLE_FAN);for (int i = 1; i <= num; i++){glVertex2f(r1*cos(2 * PI / i*num) + dx, r2*sin(2 * PI / i*num) + dy);}glEnd();}//椭圆描线void drawLineCircle(float dx, float dy, GLfloat r1, GLfloat r2, int num){glLineWidth(2);glColor3f(0.0f, 0.0f, 0.0f);glBegin(GL_LINE_LOOP);for (int i = 0; i<num; i++)glVertex2f(dx + r1*cos(2 * PI / num*i), dy + r2*sin(2 * PI / num*i));glEnd();}//画圆弧void drawCirLine(float lx,float ly,float bx,float ex,float base){GLfloat x = -1.0;glBegin(GL_LINE_STRIP);glColor3f(0.0f, 0.0f, 0.0f);for (float x = bx*PI; x < ex*PI; x += 0.1f){glVertex2f(lx + x / (base*PI), ly + sin(x));}glEnd();}/*****************画五官*****************///画眼睛void drawEye(){//左眼glPopMatrix();//glColor3f(1.0f, 1.0f, 1.0f);drawEllipseCircle(eye[0], eye[1], 0.12, 0.17, 50);drawLineCircle(eye[0], eye[1], 0.12, 0.17, 50);//左眼珠glColor3f(0.0f, 0.0f, 0.0f);drawEllipseCircle(eye[0], eye[1], 0.04, 0.05, 50);//右眼glColor3f(1.0f, 1.0f, 1.0f);drawEllipseCircle(0.12, 0.9, 0.12, 0.17, 50);drawLineCircle(0.12, 0.9, 0.12, 0.17, 50);//右眼微笑,圆弧drawCirLine(-0.2, -0.05, 0.4, 0.6, 1.6);}//画鼻子void drawNose(){//glColor3f(1.0f, 0.0f, 0.0f);drawEllipseCircle(nose[0],nose[1], 0.08, 0.08, 50);drawLineCircle(nose[0], nose[1], 0.08, 0.08, 50);//鼻子下面的线glBegin(GL_LINES);glColor3f(0.0f, 0.0f, 0.0f);glVertex2f(0.0f, 0.63f); glVertex2f(0.0f, 0.3f);glEnd();}//画嘴void drawMouth(){drawCirLine(0.83, 1.3, -0.7, -0.28, 0.6);glPushMatrix();}/*************画身体*****************///画胳膊void drawLegs(){glPushMatrix();glColor3f(0.0f, 0.435f, 0.886f);//左臂glRotatef(15.0, 0.0, 0.0, 1.0);drawEllipseCircle(-0.5, 0.17, 0.37, 0.13, 50);//左手glColor3f(1.0f, 1.0f, 1.0f);drawEllipseCircle(-0.8, 0.13, 0.13, 0.13, 50);drawLineCircle(-0.8, 0.13, 0.13, 0.13, 50);//右臂glColor3f(0.0f, 0.435f, 0.886f);glRotatef(-30.0, 0.0, 0.0, 1.0);drawEllipseCircle(0.5, 0.17, 0.37, 0.13, 50);//右手glColor3f(1.0f, 1.0f, 1.0f);drawEllipseCircle(0.8, 0.13, 0.13, 0.13, 50);drawLineCircle(0.8, 0.13, 0.13, 0.13, 50);}//画个竹蜻蜓,作为装饰物void drawSkimmer(){glPopMatrix();glBegin(GL_LINES);glLineWidth(3.5);glColor3f(1.0f, 0.960f, 0.0f);glVertex2f(skimmer[0],skimmer[1]);glVertex2f(skimmer[0], skimmer[1]-0.4f);glEnd();drawEllipseCircle(skimmer[0]-0.15f, skimmer[1], 0.2f, 0.035f, 50);drawEllipseCircle(skimmer[0]+0.15f, skimmer[1], 0.2f, 0.035f,50);drawLineCircle(skimmer[0] - 0.15f, skimmer[1], 0.2f, 0.035f, 50);drawLineCircle(skimmer[0] + 0.15f, skimmer[1], 0.2f, 0.035f, 50);}void drawBody(){glEnable(GL_BLEND);             //启用混合功能,将图形颜色同周围颜色相混合    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);glEnable(GL_POINT_SMOOTH);       //点抗锯齿    glEnable(GL_LINE_SMOOTH);        //线抗锯齿    glEnable(GL_POLYGON_SMOOTH);     //多边形抗锯齿  glBegin(GL_TRIANGLE_FAN);//画头int n = 200;GLfloat a = 0.62f, b = 0.6f;glBegin(GL_TRIANGLE_FAN);glColor3f(0.0f, 0.435f, 0.886f);for (int i = 1; i <= n; i++){glVertex2f(a*cos(2 * PI / i*n), b*sin(2 * PI / i*n)+0.7);}glEnd();//画内头glColor3f(1.0f, 1.0f, 1.0f);drawEllipseCircle(0, 0.55, 0.47, 0.44, 50);//内头描边drawLineCircle(0, 0.55, 0.47, 0.44, 50);//躯干,长方形glBegin(GL_POLYGON);glColor3f(0.0f, 0.435f, 0.886f);glVertex2f(-0.45, 0.15);glVertex2f(0.45, 0.15);glVertex2f(0.45, -0.7);glVertex2f(-0.45, -0.7);glEnd();//画脚//左脚glColor3f(1.0f, 1.0f, 1.0f);drawEllipseCircle(-0.27, -0.75, 0.27, 0.08, 50);//左脚描边drawLineCircle(-0.27, -0.75, 0.27, 0.08, 50);//左脚glColor3f(1.0f, 1.0f, 1.0f);drawEllipseCircle(0.27, -0.75, 0.27, 0.08, 50);//左脚描边drawLineCircle(0.27, -0.75, 0.27, 0.08, 50);//肚子glColor3f(1.0f, 1.0f, 1.0f);drawEllipseCircle(0.02, -0.2, 0.36, 0.35, 50);//肚子描边drawLineCircle(0.02,-0.2, 0.36, 0.35, 50);//画领带glBegin(GL_POLYGON);glColor3f(1.0f, 0.0f, 0.0f);glVertex2f(-0.35, 0.2);glVertex2f(0.35, 0.2);glVertex2f(0.40, 0.1);glVertex2f(-0.40, 0.1);glEnd();//画铃铛glColor3f(1.0f, 0.960f, 0.0f);drawEllipseCircle(0.02, 0.15, 0.07, 0.07, 50);//铃铛描边drawLineCircle(0.02, 0.15, 0.07, 0.07, 50);//画口袋glBegin(GL_POLYGON);glColor3f(1.0f, 0.960f, 0.0f);glVertex2f(-0.25, -0.1);glVertex2f(0.25, -0.1);glVertex2f(0.15, -0.38);glVertex2f(-0.15, -0.38);glEnd();glBegin(GL_LINES);glColor3f(0.0f, 0.0f, 0.0f);glVertex2f(0.0f, -0.55f);glVertex2f(0.0f, -0.69f);glEnd();//画胳膊drawLegs();//画一条线glPopMatrix();glPushMatrix();}void DrawLine(){glLoadIdentity();glBegin(GL_LINES);glLineWidth(2);glColor3f(1.0f, 1.0f, 1.0f);glVertex2f(1.2f, 4.0f);glVertex2f(1.2f, -4.0f);glEnd();}void drawGraph(GLenum mode){if (mode == GL_SELECT)glLoadName(BODY);//画脸  drawBody();if (mode == GL_SELECT)glLoadName(EYES);//画眼睛glColor3f(colors[EYES_COLOR][0], colors[EYES_COLOR][1], colors[EYES_COLOR][2]);drawEye();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(SKIMMER);drawSkimmer();DrawLine();}//指定绘制的永久环境,在开始的时候被调用一次void myInit(){glClearColor(0.0, 0.333, 0.243, 0.0);}void myDisplay(){//清除缓存  glClear(GL_COLOR_BUFFER_BIT);//glClearColor(0.0, 0.333, 0.243, 0.0);glLoadIdentity();glRotatef(theta, 0.0, 0.0, 1.0);//旋转//glTranslatef(t_x, t_y, 0.0);//平移//RANDER模式绘制物体  drawGraph(GL_RENDER);//绘制  glFlush();}//重新定义大小,使得视口坐标系和世界坐标系有相同的缩放比void myReshape(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);//表示把渲染的图像融合到目标区域。也就是说源的每一个像素的alpha都等于自己的alpha,//目标的每一个像素的alpha等于1减去该位置源像素的alpha。 因此不论叠加多少次,亮度是不变的。glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);//指示是锯消除多边形的采样质量 glEnable(GL_POLYGON_SMOOTH);//执行后,过滤多边形的锯齿glEnable(GL_POINT_SMOOTH);glEnable(GL_LINE_SMOOTH);}void processMenuEvents(int index){if (index == -1)return;switch (select_part) {case EYES:EYES_COLOR = index;break;case NOSE:NOSE_COLOR = index;break;case MOUTH:MOUTH_COLOR = index;break;}glutPostRedisplay();//标记当前窗口需要重新绘制 }void processHits(GLint hits, GLuint buffer[]){unsigned int i, j;GLuint names, *ptr;//printf("一共选中%d个!\n", hits);ptr = (GLuint *)buffer;for (i = 1; 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 = EYES;}else if (*ptr == 3){//printf("鼻子\n");select_part = NOSE;}else if (*ptr == 4){//printf("嘴巴\n");select_part = MOUTH;}else if (*ptr == 5){//printf("嘴巴\n");select_part = SKIMMER;}ptr++;}}//printf("select_part:%d\n", select_part);}static bool left_down = false;//处理鼠标响应事件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;//printf("select_part:%d\n", select_part);glGetIntegerv(GL_VIEWPORT, viewport); //获得viewport  glSelectBuffer(SIZE, selectBuf); //告诉OpenGL初始化selectbuffer  glRenderMode(GL_SELECT); //进入选择模式  glInitNames();//初始化名字栈  glPushName(0);//在名字栈中放入一个初始化名字,这里为‘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);  //拾取矩阵乘以投影矩阵,这样就可以让选择框放大为和视体一样大  drawGraph(GL_SELECT);//该函数中渲染物体,并且给物体设定名字glPopMatrix();//退出选择模式glMatrixMode(GL_MODELVIEW);//这里有一个修改??hits = glRenderMode(GL_RENDER);//从选择模式返回正常模式,该函数返回选择到对象的个数//glFlush();processHits(hits, selectBuf);//选择结果处理//glPopName();glutPostRedisplay();}}void myMouseMove(int x, int y){if (left_down){GLfloat d_x = 2.2*(x - o_x) * VIEW_WIDTH / WIN_WIDTH / 4;GLfloat d_y = 2.2*(o_y - y) * VIEW_HEIGHT / WIN_HEIGHT / 4;//将鼠标偏移量旋转-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;//鼻子if (select_part == NOSE){nose[0] += d_x;nose[1] += d_y;drawNose();}//左眼if (select_part == EYES){eye[0] += d_x;eye[1] += d_y;drawEye();}if (select_part == SKIMMER){skimmer[0] += d_x;skimmer[1] += d_y;drawSkimmer();}}glutPostRedisplay();}void myKeyboard(unsigned char key, int x, int y) {switch (key){}}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;}}int main(int argc, char** argv){glutInit( &argc, argv);//初始化openglglutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);glutInitWindowSize(500,500);glutInitWindowPosition(0, 0);glutCreateWindow("OpenGL-exp1");glutReshapeFunc(myReshape);//glutReshapeFunc是窗口改变的时候调用的函数,在这个里面可以根据缩放后的窗口重新设置camera的内部参数,比如横纵比啥的,而glutDisplayFunc是显示的时候调用,可见改变窗口后调用glutReshapeFunc后还是会调用glutDisplayFunc进行显示的。glutDisplayFunc(myDisplay);glutMouseFunc(myMouse);glutMotionFunc(myMouseMove);glutKeyboardFunc(myKeyboard);glutSpecialFunc(mySpecial);glutCreateMenu(processMenuEvents);glutAddMenuEntry("选项", -1);glutAddMenuEntry("黑色", 0);glutAddMenuEntry("红色", 1);glutAddMenuEntry("蓝色", 3);glutAddMenuEntry("紫色", 5);glutAddMenuEntry("黄色", 6);glutAddMenuEntry("白色", 7);glutAttachMenu(GLUT_RIGHT_BUTTON);myInit();//指定绘制的永久环境glutMainLoop();}


其实为了完成实验,中间有一些投机取巧的地方,比如附加功能二,哎,罪过罪过。。。。

不过觉得自己画的这个是蛮好看的,♪(^∇^*)

实验结果:


0 0