linux环境下基于opengl的3*3可控魔方绘制
一、 前言
本程序设计使用opengl函数库,在linux环境下运行,绘制一个3*3的魔方,可以通过键盘控制任意层的旋转,达到魔方转动的效果。(参考很多年前一毕业论文,个人觉得写的好)
二、 功能设计方案
1.魔方的绘制采用等效替代的思路,一个大魔方是由27块小正方体组成的,那么绘制一个标准正方体后通过空间中的移位来移动到预先设定的位置,而不是整体绘制。
2.首先对立方体建模,一个小正方体由8个点组成,有6个面,那么对正方体的几何操作本质上对6个面操作,也就是对8个点操作。正方体的空间旋转,归根到底还是顶点的旋转.
3.当键盘触发旋转,单层进行了旋转,需要更新小正方体的索引号,首先在小正方体模型池中遍历进行比对,更新出现在的该层索引号,如果不更新,旋转该层将发生扭曲错误,这和程序单层旋转的设计方案有关,本设计是通过索引号来实现任意层次的旋转的,所以旋转后要更新旋转,来知道此时此刻该层都是哪些小正方体,如果是其他设计方案,自然不用。
旋转代码片段和模型对比代码片段:
void Rotate_ZM() { for(int i=0;i<8;i++) Rotate(&Cube[ZM[i]],rotAngle,0.0,0.0,1.0); if(rotCount++==CYCLE_COUNT) { Update_Cube_index(); rotAngle=0; rotZ=0; }
int is_equal(stCube *pc1,stCube *pc2) { float x1,x2,y1,y2,z1,z2; int isFind=0; for(int i=0;i<8;i++) { x1=pc1->CubePoint[i].p[0]; y1=pc1->CubePoint[i].p[1]; z1=pc1->CubePoint[i].p[2]; isFind=0; for(int j=0;j<8;j++) { x2=pc2->CubePoint[j].p[0]; y2=pc2->CubePoint[j].p[1]; z2=pc2->CubePoint[j].p[2]; if(fabs(x1-x2)<1e-1 && fabs(y1-y2)<1e-1 && fabs(z1-z2)<1e-1) { pc1->CubePoint[i].p[0]=pc2->CubePoint[j].p[0]; pc1->CubePoint[i].p[1]=pc2->CubePoint[j].p[1]; pc1->CubePoint[i].p[2]=pc2->CubePoint[j].p[2]; isFind=1; break; } } if(isFind==0) return 0; } return 1; }
下面是demo的实现代码,因为不是最终用的版本,如果有问题也是小问题,稍作修改即可编译运行,懒得检查了。
#include <GL/gl.h> #include <GL/glu.h> #include <GL/glut.h> #include <math.h> #include <stdlib.h> #include <string.h> #define PI 3.1415926 #define CYCLE_COUNT 90 int rotate=0; int rotAngle=0; int rotCount=0; int rotX,rotY,rotZ; typedef struct { GLfloat vx,vy,vz; }CubeVertex; typedef struct { GLfloat p[3]; }stPoint; typedef struct { stPoint CubePoint[8]; }stCube; static stPoint CubePoint[8]= { {-1.0f,-1.0f,1.0f}, {1.0f,-1.0f,1.0f}, {1.0f,1.0f,1.0f}, {-1.0f,1.0f,1.0f}, {-1.0f,-1.0f,-1.0f}, {-1.0f,1.0f,-1.0f}, {1.0f,1.0f,-1.0f}, {1.0f,-1.0f,-1.0f} }; stCube Cube[27]; stCube Static_Cube[27]; int ZP[9]={0,1,2,3,4,5,6,7,8}; int ZZ[9]={9,10,11,12,13,14,15,16,17}; int ZM[9]={18,19,20,21,22,23,24,25,26}; int YM[9]={0,1,2,11,10,9,18,19,20}; int YZ[9]={3,4,5,14,13,12,21,22,23}; int YP[9]={6,7,8,17,16,15,24,25,26}; int XM[9]={2,3,8,17,12,11,20,21,26}; int XZ[9]={1,4,7,16,13,10,19,22,25}; int XP[9]={0,5,6,15,14,9,18,23,24}; const int SZP[9]={0,1,2,3,4,5,6,7,8}; const int SZZ[9]={9,10,11,12,13,14,15,16,17}; const int SZM[9]={18,19,20,21,22,23,24,25,26}; const int SYM[9]={0,1,2,11,10,9,18,19,20}; const int SYZ[9]={3,4,5,14,13,12,21,22,23}; const int SYP[9]={6,7,8,17,16,15,24,25,26}; const int SXM[9]={2,3,8,17,12,11,20,21,26}; const int SXZ[9]={1,4,7,16,13,10,19,22,25}; const int SXP[9]={0,5,6,15,14,9,18,23,24}; void Rotate(stCube *pCube,float angle,float x0,float y0,float z0) { int i; double a = PI*2.0*angle/360.0; double cosa = cos(a); double sina=sin(a); if(fabs(x0)>1e-2) { for(i=0;i<8;i++) { float y,z; y=pCube->CubePoint[i].p[1]; z=pCube->CubePoint[i].p[2]; pCube->CubePoint[i].p[1]=y*cosa-z*sina; pCube->CubePoint[i].p[2]=y*sina+z*cosa; } } if(fabs(y0)>1e-2) { for(i=0;i<8;i++) { float x,z; x=pCube->CubePoint[i].p[0]; z=pCube->CubePoint[i].p[2]; pCube->CubePoint[i].p[0]=x*cosa-z*sina; pCube->CubePoint[i].p[2]=x*sina+z*cosa; } } if(fabs(z0)>1e-2) { for(i=0;i<8;i++) { float x,y; x=pCube->CubePoint[i].p[0]; y=pCube->CubePoint[i].p[1]; pCube->CubePoint[i].p[0]=x*cosa-y*sina; pCube->CubePoint[i].p[1]=x*sina+y*cosa; } } } int is_equal(stCube *pc1,stCube *pc2) { float x1,x2,y1,y2,z1,z2; int isFind=0; for(int i=0;i<8;i++) { x1=pc1->CubePoint[i].p[0]; y1=pc1->CubePoint[i].p[1]; z1=pc1->CubePoint[i].p[2]; isFind=0; for(int j=0;j<8;j++) { x2=pc2->CubePoint[j].p[0]; y2=pc2->CubePoint[j].p[1]; z2=pc2->CubePoint[j].p[2]; if(fabs(x1-x2)<1e-1 && fabs(y1-y2)<1e-1 && fabs(z1-z2)<1e-1) { pc1->CubePoint[i].p[0]=pc2->CubePoint[j].p[0]; pc1->CubePoint[i].p[1]=pc2->CubePoint[j].p[1]; pc1->CubePoint[i].p[2]=pc2->CubePoint[j].p[2]; isFind=1; break; } } if(isFind==0) return 0; } return 1; } void Update_Cube_index() { int i,j,k=0; for(i=0;i<9;i++) { for(j=0;j<27;j++) if(is_equal(&Cube[j],&Static_Cube[SZM[i]])) ZM[k++]=j; } k=0; for(i=0;i<9;i++) { for(j=0;j<27;j++) if(is_equal(&Cube[j],&Static_Cube[SZZ[i]])) ZZ[k++]=j; } k=0; for(i=0;i<9;i++) { for(j=0;j<27;j++) if(is_equal(&Cube[j],&Static_Cube[SZP[i]])) ZP[k++]=j; } k=0; for(i=0;i<9;i++) { for(j=16;j<27;j++) if(is_equal(&Cube[j],&Static_Cube[SXM[i]])) XM[k++]=j; } k=0; for(i=0;i<9;i++) { for(j=0;j<27;j++) if(is_equal(&Cube[j],&Static_Cube[SXZ[i]])) XZ[k++]=j; } k=0; for(i=0;i<9;i++) { for(j=0;j<27;j++) if(is_equal(&Cube[j],&Static_Cube[SXP[i]])) XP[k++]=j; } k=0; for(i=0;i<9;i++) { for(j=0;j<27;j++) if(is_equal(&Cube[j],&Static_Cube[SYM[i]])) YM[k++]=j; } k=0; for(i=0;i<9;i++) { for(j=0;j<27;j++) if(is_equal(&Cube[j],&Static_Cube[SYZ[i]])) YZ[k++]=j; } k=0; for(i=0;i<9;i++) { for(j=0;j<27;j++) if(is_equal(&Cube[j],&Static_Cube[SYP[i]])) YP[k++]=j; } } void Rotate_ZM() { for(int i=0;i<8;i++) Rotate(&Cube[ZM[i]],rotAngle,0.0,0.0,1.0); if(rotCount++==CYCLE_COUNT) { Update_Cube_index(); rotAngle=0; rotZ=0; } } void Rotate_ZZ() { for(int i=0;i<8;i++) Rotate(&Cube[ZZ[i]],rotAngle,0.0,0.0,1.0); if(rotCount++==CYCLE_COUNT) { Update_Cube_index(); rotAngle=0; rotZ=0; } } void Rotate_ZP() { for(int i=0;i<9;i++) Rotate(&Cube[ZP[i]],rotAngle,0.0,0.0,1.0); if(rotCount++==CYCLE_COUNT) { Update_Cube_index(); rotAngle=0; rotZ=0; } } void Rotate_XM() { for(int i=0;i<9;i++) Rotate(&Cube[XM[i]],rotAngle,1.0,0.0,0.0); if(rotCount++==CYCLE_COUNT) { Update_Cube_index(); rotAngle=0; rotX=0; } } void Rotate_XZ() { for(int i=0;i<9;i++) Rotate(&Cube[XZ[i]],rotAngle,1.0,0.0,0.0); if(rotCount++==CYCLE_COUNT) { Update_Cube_index(); rotAngle=0; rotX=0; } } void Rotate_XP() { rotAngle=45; for(int i=0;i<9;i++) Rotate(&Cube[XP[i]],rotAngle,1.0,0.0,0.0); } void Rotate_YM() { for(int i=0;i<9;i++) Rotate(&Cube[YM[i]],rotAngle,0.0,1.0,0.0); if(rotCount++==CYCLE_COUNT) { Update_Cube_index(); rotAngle=0; rotY=0; } } void Rotate_YZ() { for(int i=0;i<9;i++) Rotate(&Cube[YZ[i]],rotAngle,0.0,1.0,0.0); if(rotCount++==CYCLE_COUNT) { Update_Cube_index(); rotAngle=0; rotY=0; } } void Rotate_YP() { for(int i=0;i<9;i++) Rotate(&Cube[YP[i]],rotAngle,0.0,1.0,0.0); if(rotCount++==CYCLE_COUNT) { Update_Cube_index(); rotAngle=0; rotY=0; } } void Rotate_Z(int ii) { switch(ii) { case 0: Rotate_ZP(); break; case 1: Rotate_ZZ(); break; case 2: Rotate_ZM(); break; } } void Rotate_Y(int ii) { switch(ii) { case 0: Rotate_YP(); break; case 1: Rotate_YZ(); break; case 2: Rotate_YM(); break; } } void Rotate_X(int ii) { switch(ii) { case 0: Rotate_XP(); break; case 1: Rotate_XZ(); break; case 2: Rotate_XM(); break; } } void glKeyboard(unsigned char key, int x, int y) { switch (key) { case 'a': Rotate_X(0); glutPostRedisplay(); break; case 'd': rotate+=3; glutPostRedisplay(); break; case 'w': Rotate_Y(0) ; glutPostRedisplay(); break; case 's': rotate+=3; glutPostRedisplay(); break; } }
void rest_model() { int i; for(i=0;i<8;i++) { Cube[0].CubePoint[i].p[0]=CubePoint[i].p[0]-2.0f; Cube[0].CubePoint[i].p[1]=CubePoint[i].p[1]-2.0f; Cube[0].CubePoint[i].p[2]=CubePoint[i].p[2]+2.0f; } for(i=0;i<8;i++) { Cube[1].CubePoint[i].p[0]=CubePoint[i].p[0]+0.0f; Cube[1].CubePoint[i].p[1]=CubePoint[i].p[1]-2.0f; Cube[1].CubePoint[i].p[2]=CubePoint[i].p[2]+2.0f; } for(i=0;i<8;i++) { Cube[2].CubePoint[i].p[0]=CubePoint[i].p[0]+2.0f; Cube[2].CubePoint[i].p[1]=CubePoint[i].p[1]-2.0f; Cube[2].CubePoint[i].p[2]=CubePoint[i].p[2]+2.0f; } for(i=0;i<8;i++) { Cube[3].CubePoint[i].p[0]=CubePoint[i].p[0]+2.0f; Cube[3].CubePoint[i].p[1]=CubePoint[i].p[1]+0.0f; Cube[3].CubePoint[i].p[2]=CubePoint[i].p[2]+2.0f; } for(i=0;i<8;i++) { Cube[4].CubePoint[i].p[0]=CubePoint[i].p[0]+0.0f; Cube[4].CubePoint[i].p[1]=CubePoint[i].p[1]+0.0f; Cube[4].CubePoint[i].p[2]=CubePoint[i].p[2]+2.0f; } for(i=0;i<8;i++) { Cube[5].CubePoint[i].p[0]=CubePoint[i].p[0]-2.0f; Cube[5].CubePoint[i].p[1]=CubePoint[i].p[1]+0.0f; Cube[5].CubePoint[i].p[2]=CubePoint[i].p[2]+2.0f; } for(i=0;i<8;i++) { Cube[6].CubePoint[i].p[0]=CubePoint[i].p[0]-2.0f; Cube[6].CubePoint[i].p[1]=CubePoint[i].p[1]+2.0f; Cube[6].CubePoint[i].p[2]=CubePoint[i].p[2]+2.0f; } for(i=0;i<8;i++) { Cube[7].CubePoint[i].p[0]=CubePoint[i].p[0]+0.0f; Cube[7].CubePoint[i].p[1]=CubePoint[i].p[1]+2.0f; Cube[7].CubePoint[i].p[2]=CubePoint[i].p[2]+2.0f; } for(i=0;i<8;i++) { Cube[8].CubePoint[i].p[0]=CubePoint[i].p[0]+2.0f; Cube[8].CubePoint[i].p[1]=CubePoint[i].p[1]+2.0f; Cube[8].CubePoint[i].p[2]=CubePoint[i].p[2]+2.0f; } for(i=0;i<8;i++) { Cube[9].CubePoint[i].p[0]=CubePoint[i].p[0]-2.0f; Cube[9].CubePoint[i].p[1]=CubePoint[i].p[1]-2.0f; Cube[9].CubePoint[i].p[2]=CubePoint[i].p[2]+0.0f; } for(i=0;i<8;i++) { Cube[10].CubePoint[i].p[0]=CubePoint[i].p[0]+0.0f; Cube[10].CubePoint[i].p[1]=CubePoint[i].p[1]-2.0f; Cube[10].CubePoint[i].p[2]=CubePoint[i].p[2]+0.0f; } for(i=0;i<8;i++) { Cube[11].CubePoint[i].p[0]=CubePoint[i].p[0]-2.0f; Cube[11].CubePoint[i].p[1]=CubePoint[i].p[1]+0.0f; Cube[11].CubePoint[i].p[2]=CubePoint[i].p[2]+2.0f; } for(i=0;i<8;i++) { Cube[12].CubePoint[i].p[0]=CubePoint[i].p[0]+2.0f; Cube[12].CubePoint[i].p[1]=CubePoint[i].p[1]+0.0f; Cube[12].CubePoint[i].p[2]=CubePoint[i].p[2]+0.0f; } for(i=0;i<8;i++) { Cube[13].CubePoint[i].p[0]=CubePoint[i].p[0]+0.0f; Cube[13].CubePoint[i].p[1]=CubePoint[i].p[1]+0.0f; Cube[13].CubePoint[i].p[2]=CubePoint[i].p[2]+0.0f; } for(i=0;i<8;i++) { Cube[14].CubePoint[i].p[0]=CubePoint[i].p[0]-2.0f; Cube[14].CubePoint[i].p[1]=CubePoint[i].p[1]+0.0f; Cube[14].CubePoint[i].p[2]=CubePoint[i].p[2]+0.0f; } for(i=0;i<8;i++) { Cube[15].CubePoint[i].p[0]=CubePoint[i].p[0]-2.0f; Cube[15].CubePoint[i].p[1]=CubePoint[i].p[1]+2.0f; Cube[15].CubePoint[i].p[2]=CubePoint[i].p[2]+0.0f; } for(i=0;i<8;i++) { Cube[16].CubePoint[i].p[0]=CubePoint[i].p[0]+0.0f; Cube[16].CubePoint[i].p[1]=CubePoint[i].p[1]+2.0f; Cube[16].CubePoint[i].p[2]=CubePoint[i].p[2]+0.0f; } for(i=0;i<8;i++) { Cube[17].CubePoint[i].p[0]=CubePoint[i].p[0]+2.0f; Cube[17].CubePoint[i].p[1]=CubePoint[i].p[1]+2.0f; Cube[17].CubePoint[i].p[2]=CubePoint[i].p[2]+0.0f; } for(i=0;i<8;i++) { Cube[18].CubePoint[i].p[0]=CubePoint[i].p[0]-2.0f; Cube[18].CubePoint[i].p[1]=CubePoint[i].p[1]-2.0f; Cube[18].CubePoint[i].p[2]=CubePoint[i].p[2]-2.0f; } for(i=0;i<8;i++) { Cube[19].CubePoint[i].p[0]=CubePoint[i].p[0]+0.0f; Cube[19].CubePoint[i].p[1]=CubePoint[i].p[1]-2.0f; Cube[19].CubePoint[i].p[2]=CubePoint[i].p[2]-2.0f; } for(i=0;i<8;i++) { Cube[20].CubePoint[i].p[0]=CubePoint[i].p[0]+2.0f; Cube[20].CubePoint[i].p[1]=CubePoint[i].p[1]-2.0f; Cube[20].CubePoint[i].p[2]=CubePoint[i].p[2]-2.0f; } for(i=0;i<8;i++) { Cube[21].CubePoint[i].p[0]=CubePoint[i].p[0]+2.0f; Cube[21].CubePoint[i].p[1]=CubePoint[i].p[1]+0.0f; Cube[21].CubePoint[i].p[2]=CubePoint[i].p[2]-2.0f; } for(i=0;i<8;i++) { Cube[22].CubePoint[i].p[0]=CubePoint[i].p[0]+0.0f; Cube[22].CubePoint[i].p[1]=CubePoint[i].p[1]+0.0f; Cube[22].CubePoint[i].p[2]=CubePoint[i].p[2]-2.0f; } for(i=0;i<8;i++) { Cube[23].CubePoint[i].p[0]=CubePoint[i].p[0]-2.0f; Cube[23].CubePoint[i].p[1]=CubePoint[i].p[1]+0.0f; Cube[23].CubePoint[i].p[2]=CubePoint[i].p[2]-2.0f; } for(i=0;i<8;i++) { Cube[24].CubePoint[i].p[0]=CubePoint[i].p[0]-2.0f; Cube[24].CubePoint[i].p[1]=CubePoint[i].p[1]+2.0f; Cube[24].CubePoint[i].p[2]=CubePoint[i].p[2]-2.0f; } for(i=0;i<8;i++) { Cube[25].CubePoint[i].p[0]=CubePoint[i].p[0]+0.0f; Cube[25].CubePoint[i].p[1]=CubePoint[i].p[1]+2.0f; Cube[25].CubePoint[i].p[2]=CubePoint[i].p[2]-2.0f; } for(i=0;i<8;i++) { Cube[26].CubePoint[i].p[0]=CubePoint[i].p[0]+2.0f; Cube[26].CubePoint[i].p[1]=CubePoint[i].p[1]+2.0f; Cube[26].CubePoint[i].p[2]=CubePoint[i].p[2]-2.0f; } for(i=0;i<27;i++) Static_Cube[i]=Cube[i]; } void DrawCube(int ID) { stPoint *CubePoint=Cube[ID].CubePoint; glColor3f(1, 0, 0); glBegin(GL_QUADS); //glNormal3f(0.0f,1.0f,0.0f); glVertex3f(CubePoint[0].p[0],CubePoint[0].p[1],CubePoint[0].p[2]); glVertex3f(CubePoint[1].p[0],CubePoint[1].p[1],CubePoint[1].p[2]); glVertex3f(CubePoint[2].p[0],CubePoint[2].p[1],CubePoint[2].p[2]); glVertex3f(CubePoint[3].p[0],CubePoint[3].p[1],CubePoint[3].p[2]); glEnd(); glColor3f(1, 1, 0); glBegin(GL_QUADS); // glNormal3f(0.0f,-1.0f,0.0f); glVertex3f(CubePoint[4].p[0],CubePoint[4].p[1],CubePoint[4].p[2]); glVertex3f(CubePoint[5].p[0],CubePoint[5].p[1],CubePoint[5].p[2]); glVertex3f(CubePoint[6].p[0],CubePoint[6].p[1],CubePoint[6].p[2]); glVertex3f(CubePoint[7].p[0],CubePoint[7].p[1],CubePoint[7].p[2]); glEnd(); glColor3f(1, 0, 1); glBegin(GL_QUADS); // glNormal3f(0.0f,0.0f,1.0f); glVertex3f(CubePoint[5].p[0],CubePoint[5].p[1],CubePoint[5].p[2]); glVertex3f(CubePoint[3].p[0],CubePoint[3].p[1],CubePoint[3].p[2]); glVertex3f(CubePoint[2].p[0],CubePoint[2].p[1],CubePoint[2].p[2]); glVertex3f(CubePoint[6].p[0],CubePoint[6].p[1],CubePoint[6].p[2]); glEnd(); glColor3f(1, 1, 1); glBegin(GL_QUADS); //glNormal3f(0.0f,0.0f,-1.0f); glVertex3f(CubePoint[4].p[0],CubePoint[4].p[1],CubePoint[4].p[2]); glVertex3f(CubePoint[7].p[0],CubePoint[7].p[1],CubePoint[7].p[2]); glVertex3f(CubePoint[1].p[0],CubePoint[1].p[1],CubePoint[1].p[2]); glVertex3f(CubePoint[0].p[0],CubePoint[0].p[1],CubePoint[0].p[2]); glEnd(); glColor3f(0.5, 0.5, 0); glBegin(GL_QUADS); //glNormal3f(-1.0f,0.0f,0.0f); glVertex3f(CubePoint[7].p[0],CubePoint[7].p[1],CubePoint[7].p[2]); glVertex3f(CubePoint[6].p[0],CubePoint[6].p[1],CubePoint[6].p[2]); glVertex3f(CubePoint[2].p[0],CubePoint[2].p[1],CubePoint[2].p[2]); glVertex3f(CubePoint[1].p[0],CubePoint[1].p[1],CubePoint[1].p[2]); glEnd(); glColor3f(1, 0, 0.5); glBegin(GL_QUADS); //glNormal3f(1.0f,0.0f,0.0f); glVertex3f(CubePoint[4].p[0],CubePoint[4].p[1],CubePoint[4].p[2]); glVertex3f(CubePoint[0].p[0],CubePoint[0].p[1],CubePoint[0].p[2]); glVertex3f(CubePoint[3].p[0],CubePoint[3].p[1],CubePoint[3].p[2]); glVertex3f(CubePoint[5].p[0],CubePoint[5].p[1],CubePoint[5].p[2]); glEnd(); } void renderScene(void) { // glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT ); glEnable(GL_DEPTH_TEST); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glPushMatrix(); glTranslatef(-0.1,0.0,-0.0); glScalef(0.1, 0.1, 0.1); gluLookAt (0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 1.0, 1.0,0.0); glRotatef(rotate, 0, 0, 1); glRotatef(rotate, 1, 0, 0); for(int j=0;j<27;j++) DrawCube(j); glPopMatrix(); glutSwapBuffers(); } void main(int argc, char **argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); glShadeModel(GL_SMOOTH); glClearColor(1.0f, 0.0f, 0.0f, 0.0f); glClearDepth(1.0f); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); glutInitWindowPosition(100,100); glutInitWindowSize(1000, 1000); rest_model(); gluLookAt (2.0, 2.0, 0.0, 2.0, 1.0, 5.0, 2.0, 1.0, 5.0); glutCreateWindow("Cube_Demo"); glutDisplayFunc(renderScene); glutKeyboardFunc(glKeyboard); glutIdleFunc(renderScene); glutMainLoop(); }