计算机图形学实验一,参考了汪海学长的逻辑结构
,
膜拜大佬,抱拳!
#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 5
static 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);//初始化opengl
glutInitDisplayMode(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();
}
其实为了完成实验,中间有一些投机取巧的地方,比如附加功能二,哎,罪过罪过。。。。
不过觉得自己画的这个是蛮好看的,♪(^∇^*)
实验结果: