图形学之C语言OpenGL实现三角形绕其中心旋转,点击右键菜单改变大小和颜色,键盘按键控制旋转的开始和暂停等功能

一、  实验要求

1.使用鼠标选择窗口内任意位置画N个等腰三角形。

2.要画的三角形大小及颜色通过右键弹出菜单选定(任选M个颜色)。

3.设定三角形绕其中心旋转的开始、停止、旋转方向的功能键,并通过相应按键控制三角形旋转。

 

二、  完成情况

由于没能实现在鼠标任意选定的位置画三角形并且让其旋转(分开很好实现),于是便简化了一下,在固定位置画N个三角形,并让其绕中心点旋转。可以通过右键菜单退出、改变大小和改变颜色。同时还可以通过空格键控制旋转的开始和停止,通过C字母键控制旋转的方向(顺时针或逆时针)。

 

三、   各功能介绍

1. 画等腰三角形并旋转:

为了方便确定三角形的中点,我画的是特殊的等腰三角形——等边三角形。设其一顶点的坐标为 ( cos(spin) , sin(spin) ),则另外两点的坐标为 ( cos(spin-120) ,sin(spin-120) ) 和 (cos(spin+120) , sin(spin+120) ),其中spin为转过的角度。旋转时只要改变 spin 的值即可。

             

       代码:

       void display()

{

    glClear (GL_COLOR_BUFFER_BIT);

         glPushMatrix();//将当前矩阵压栈(保存现场)

         glBegin(GL_TRIANGLES);

         //设顶点坐标为(cos(spin),sin(spin)),其他两点坐标可由spin +/- 120°后得到

                  glVertex2f(cos(DR*spin)*size+30,sin(DR*spin)*size+30);

                  glVertex2f(cos(DR*(spin+120))*size+30,sin(DR*(spin+120))*size+30);

                  glVertex2f(cos(DR*(spin-120))*size+30,sin(DR*(spin-120))*size+30);

                  glVertex2f(cos(DR*spin)*size+10,sin(DR*spin)*size-30);

                  glVertex2f(cos(DR*(spin+120))*size+10,sin(DR*(spin+120))*size-30);

                  glVertex2f(cos(DR*(spin-120))*size+10,sin(DR*(spin-120))*size-30);

                  glVertex2f(cos(DR*spin)*size-20,sin(DR*spin)*size+20);

                  glVertex2f(cos(DR*(spin+120))*size-20,sin(DR*(spin+120))*size+20);

                  glVertex2f(cos(DR*(spin-120))*size-20,sin(DR*(spin-120))*size+20);

                  glVertex2f(cos(DR*spin)*size-35,sin(DR*spin)*size-20);

                  glVertex2f(cos(DR*(spin+120))*size-35,sin(DR*(spin+120))*size-20);

                  glVertex2f(cos(DR*(spin-120))*size-35,sin(DR*(spin-120))*size-20);

         glEnd();

         glPopMatrix();

         glutSwapBuffers();//双缓存技术的函数,作用为交换两个缓冲区的指针

}

      

       效果:

   《图形学之C语言OpenGL实现三角形绕其中心旋转,点击右键菜单改变大小和颜色,键盘按键控制旋转的开始和暂停等功能》

      

2. 右键弹出菜单:

要设置一个退出选项以及改变大小子菜单和颜色子菜单,直接利用代码写出即可。改变大小时,可以让全局变量 size 增大或缩小一倍。改变颜色时可以用glColor3f 函数将前景色改变为相应的颜色。

 

       代码:

       /*右键菜单*/

         /*大小子菜单*/

         int sub_menu1= glutCreateMenu(size_menu);

         glutAddMenuEntry(“Increasesize”,2);

         glutAddMenuEntry(“Decreasesize”,3);

         /*颜色子菜单*/

         intsub_menu2 = glutCreateMenu(color_menu);

         glutAddMenuEntry(“red”,4);

         glutAddMenuEntry(“blue”,5);       

         glutAddMenuEntry(“yellow”,6);

         /*主菜单*/

         glutCreateMenu(main_menu);

         glutAddMenuEntry(“Quit”,1);

         glutAddSubMenu(“Size”,sub_menu1); //添加子菜单

         glutAddSubMenu(“Color”,sub_menu2);       //添加子菜单

       glutAttachMenu(GLUT_RIGHT_BUTTON);

 

    效果:

   《图形学之C语言OpenGL实现三角形绕其中心旋转,点击右键菜单改变大小和颜色,键盘按键控制旋转的开始和暂停等功能》

 

3. 键盘控制旋转的开始停止以及旋转方向:

分别设了两个全局变量:flag和dir,取值为 0 或 1,按键一次值就随之改变一次。分别用来控制旋转的开始和停止以及旋转的方向。旋转的开始和结束可以用glutIdleFunc函数传入不同的参数实现。旋转的方向可以通过改变 spin 角度增加还是减少来实现。

 

代码:
       void myKey(unsigned char key,intx,int y)

{ //键盘

         if(key==”)

         {//如果按下空格键,则控制旋转和暂停

                  flag^=1;

                  if(flag)glutIdleFunc(spinDisplay);

                  elseglutIdleFunc(NULL);

         }

         //按下C字母改变旋转方向

         elseif(key==’c’||key==’C’) dir^=1;

}

 

 

四、  难点分析

最困难的部分就是用鼠标点击N个位置画三角形和三角形旋转分别都好实现,但是一旦放到一起就会出各种错误,只能简化了一下要求。

 

其次就是三角形绕其中心旋转的实现,一开始是从网上找的一个函数,调用之后可以绕x、y、z轴旋转,但是效果不好,不是绕中心旋转,后来自己模仿PPT上面正方形旋转的案例自己改动了一下。

 

其他的之前的代码中都有类似的案例,不算太难,模仿一下就可以了。

五、  总代码

#include <stdlib.h>
#include <GL/glut.h>
#include <math.h>

#define DR 3.14159/180.0

int N=4;
int num=0;
int dir=1;
int flag=1;
double size=10;
static GLfloat spin = 0.0;
GLfloat x, y;
int doubleb;

void triangle(GLfloat x,GLfloat y)
{ //画三角形,实际没用到……
	glPushMatrix();//将当前矩阵压栈(保存现场)
	glBegin(GL_TRIANGLES);
		glVertex2f(x,y+size/2);
		glVertex2f(x-size/2,y-size/2);
		glVertex2f(x+size/2,y-size/2);
	glEnd();
	glPopMatrix();
	glutSwapBuffers();//双缓存技术的函数,作用为交换两个缓冲区的指针
}

void display()
{
    glClear (GL_COLOR_BUFFER_BIT);
	glPushMatrix();//将当前矩阵压栈(保存现场)
	glBegin(GL_TRIANGLES);
	//设顶点坐标为(cos(spin),sin(spin)),其他两点坐标可由spin +/- 120°后得到
		glVertex2f(cos(DR*spin)*size+30,sin(DR*spin)*size+30);
		glVertex2f(cos(DR*(spin+120))*size+30,sin(DR*(spin+120))*size+30);
		glVertex2f(cos(DR*(spin-120))*size+30,sin(DR*(spin-120))*size+30);
		glVertex2f(cos(DR*spin)*size+10,sin(DR*spin)*size-30);
		glVertex2f(cos(DR*(spin+120))*size+10,sin(DR*(spin+120))*size-30);
		glVertex2f(cos(DR*(spin-120))*size+10,sin(DR*(spin-120))*size-30);
		glVertex2f(cos(DR*spin)*size-20,sin(DR*spin)*size+20);
		glVertex2f(cos(DR*(spin+120))*size-20,sin(DR*(spin+120))*size+20);
		glVertex2f(cos(DR*(spin-120))*size-20,sin(DR*(spin-120))*size+20);
		glVertex2f(cos(DR*spin)*size-35,sin(DR*spin)*size-20);
		glVertex2f(cos(DR*(spin+120))*size-35,sin(DR*(spin+120))*size-20);
		glVertex2f(cos(DR*(spin-120))*size-35,sin(DR*(spin-120))*size-20);
	glEnd();
	glPopMatrix();
	glutSwapBuffers();//双缓存技术的函数,作用为交换两个缓冲区的指针
}

void spinDisplay (void)
{ //角度变化
	if(dir) spin = spin + 0.05;
	else spin=spin - 0.05;
    if (spin > 360.0) spin = spin - 360.0;
	glutSetWindow(doubleb);
    glutPostRedisplay(); 
}

void myinit ()
{ //初始化
	glViewport(0,0,500,500);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(0.0,(GLdouble)500,0.0,(GLdouble)500,-1.0,1.0);
	glMatrixMode(GL_MODELVIEW);
	glClearColor(0.0,0.0,0.0,1.0);
	glColor3f(1.0,1.0,1.0); //前景色为白色

}

void myMouse(int btn,int state,int x,int y)
{ //鼠标
	if(btn==GLUT_LEFT_BUTTON && state==GLUT_UP)
	{//点击鼠标左键画三角形,但没起到作用
		if(num<N) triangle(x,y);
		num++;
	}
}

void myKey(unsigned char key,int x,int y)
{ //键盘
	if(key==' ')
	{ //如果按下空格键,则控制旋转和暂停
		flag^=1;
		if(flag) glutIdleFunc(spinDisplay);
		else glutIdleFunc(NULL);
	}
	//按下C字母改变旋转方向
	else if(key=='c'||key=='C') dir^=1;
}

void myReshape(int w, int h)
{
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w <= h) 
	glOrtho (-50.0, 50.0, -50.0*(GLfloat)h/(GLfloat)w, 
	    50.0*(GLfloat)h/(GLfloat)w, -10.0, 10.0);
    else 
	glOrtho (-50.0*(GLfloat)w/(GLfloat)h, 
	    50.0*(GLfloat)w/(GLfloat)h, -50.0, 50.0, -10.0, 10.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity ();
}

void myTimer(int v)
{	
	glutSetWindow(doubleb);
    glutPostRedisplay(); 
	glutTimerFunc(100, myTimer, v);
}

void main_menu(int id)
{ //主菜单
	switch(id)
	{
		case 1: exit(0);
		break;
	}
}

void size_menu(int id)
{ //大小菜单
	switch(id)
	{
		case 2: size = 2*size;
		break;
		case 3: if(size>1) size = size/2;
		break;
	}
}

void color_menu(int id)
{ //颜色菜单
	switch(id)
	{
		case 4: glColor3f(1.0,0.0,0.0); //红色 
		break;
		case 5: glColor3f(0.0,0.0,1.0); //蓝色 
		break;
		case 6: glColor3f(1.0,1.0,0.0); //黄色 
		break;
	}
}

int main(int argc, char** argv)
{
	glutInit(&argc,argv);
	glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
	glutInitWindowSize(800,800);
	glutInitWindowPosition(0,0);
	doubleb=glutCreateWindow("Triangle");	
	/*右键菜单*/
	/*大小子菜单*/
	int sub_menu1 = glutCreateMenu(size_menu);
	glutAddMenuEntry("Increase size",2);
	glutAddMenuEntry("Decrease size",3);	
	/*颜色子菜单*/
	int sub_menu2 = glutCreateMenu(color_menu);
	glutAddMenuEntry("red",4);
	glutAddMenuEntry("blue",5);	
	glutAddMenuEntry("yellow",6);
	/*主菜单*/
	glutCreateMenu(main_menu);
	glutAddMenuEntry("Quit",1);
	glutAddSubMenu("Size", sub_menu1); //添加子菜单 
	glutAddSubMenu("Color", sub_menu2);	//添加子菜单
	glutAttachMenu(GLUT_RIGHT_BUTTON);

    myinit ();	
	glutDisplayFunc(display);	
	glutMouseFunc (myMouse); //鼠标事件
	glutKeyboardFunc(myKey); //键盘事件
    glutReshapeFunc (myReshape);
    glutIdleFunc (spinDisplay);    
    glutTimerFunc(100,myTimer,60);

	glutMainLoop();
	return 0;
}

    原文作者:棉花糖灬
    原文地址: https://blog.csdn.net/zuzhiang/article/details/80794898
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞