基于OpenGL的3D旋转魔方实现汇总
OpenGL实现3DS文件中的模型自由旋转

OpenGL实现3DS文件中的模型自由旋转文章出处:/course/3_program/c++/cppsl/20071119/86921_2.html摘要简述如何在OpenGL中,读入和显示3DS文件中的模型,并着重阐述通过鼠标拖动对其进行自由旋转的数学基础和编程实现的方法。
关键词OpenGL 3DS文件格式VC++ 自由旋转现在已经有很多论文和书籍提到在OpenGL中实现读入和显示3DS文件中的模型。
但是在很多场合,仅读入和显示是不够的。
我们需要从各个角度观察模型,以便更好地理解模型的形态,形成更为直观的感性认识。
例如,在医学髁上骨折诊断中,如果把骨折后,断骨错位旋转的情况用三维模型模拟出来,并仅用鼠标的拖动就能实现从任何角度观看骨折的情况,这将对医生做出正确的诊断大有裨益。
这也是我们为何考虑实现此项功能的初衷。
本文将简要介绍3DS文件格式,怎样读入和显示模型,而重点放在通过鼠标拖动实现模型自由旋转的数学基础和编程实现的方法和经验。
3DS文件的格式以及读入和显示文件中模型的一些经验.3DS文件是由许多块(chunk)组成的(大块中镶嵌子块)。
由于至今为止,没有一个官方的文献说明其格式,所以还有很多未知的块。
不过这并不影响我们读入3DS文件中的模型。
因为我们在读入时,可以根据自己的需要选择性地读入自己需要的块,而忽略掉那些不感兴趣或未知的块。
这正是块结构给我们带来的好处。
一个块由块信息和块数据组成。
块信息又由块的ID(两个字节长的标识,如4D4D)和块的长度(四个字节,其实也就是下一个块的偏移字节数)组成。
用VC++以十六进制方式打开一3DS文件可以很清楚的看到其结构。
在读入这种块结构(大块中嵌套小块,而块的结构固定)的文件时,完全可以用递归的方法实现,而返回上一级(子块读完,返回父块)的条件则是当前已经读入的块的字节数是否等于块的长度。
从父块转向读入其子块,则可用switch语句实现,通过子块的ID判断进入哪个分支。
OpenGL下三维模型的显示和自由旋转

20 世纪 70 年代后期 ,计算机图形工作站的出现推动了基于矢量的 3D 计算机图形学 ( 3D Computer Grap hics) 的迅速发展 . 目前 3D 计算机图形学已经广泛地应用于各个行业和领域 , 如 :3D Max ,Poser 等三维设计软件可以生成复杂的三维模型 . 考虑到软件的通用性 , 本文选 取了图形数据工业标准 — — — DXF 格式的三维模型数据文件作为源文件 , 不仅可以对任意软件 生成的 DXF 格式的三维模型文件进行处理 ,同时还可以处理三维模型和二维模型 . 在三维软件的开发方面 ,目前主要存在 2 种 API : 一个是微软的 Direct 3D ,一个是开放标 准 Open GL . Direct 3D 大量应用于民用产品 ,如游戏领域 ,而 Open GL 作为应用最为广泛的高 性能工业图形标准 ,是开发高质量的二维或三维交互式图形应用程序的首选环境 [ 1 ] . Open GL 提供的应用程序 API 包含了许多现代图形学中的基本功能 , 如 : 图元的绘制 、 颜色指定 、 纹理 映射 、 光照处理 、 双缓存动画和特效等 ; 另外 , 其跨平台的特性也备受用户推崇 ; Open GL 简化 了图形软件的开发过程 ,缩短了产品进入市场的周期 : 因此 ,我们选用 Open GL 作为开发工具 . 在对三维模型的研究中 ,需要对其进行自由旋转 ,以方便从任意角度细致地进行观察 . 本 文提供了一种通过操纵虚拟球实现对模型自由旋转的方法 ,使用户仅通过鼠标的拖动就能从 任何角度观看模型 .
v= b +c , cosβ= c/ v , sinβ= b/ v ;
2 2
1
Rx =
0 0 0
0 β cos sinβ - sinβ cosβ 0 0
openGL+VS2010的例程--旋转立方体(三维)

openGL+VS2010的例程--旋转⽴⽅体(三维)效果图如上:步骤:⾸先,设置模型视⾓往后退,再旋转视⾓;然后,⽤默认绘制⽴⽅体函数绘制;最后,利⽤空闲对模型做⾓度微调。
实现代码如下:1 #include <GL\glut.h>23 GLfloat xRotated, yRotated, zRotated;45void Display(void)6 {7 glClear(GL_COLOR_BUFFER_BIT);8 glLoadIdentity();9 glTranslatef(0.0,0.0,-4.0);10 glRotatef(xRotated,1.0,0.0,0.0);11 glRotatef(yRotated,0.0,1.0,0.0);12 glRotatef(zRotated,0.0,0.0,1.0);13//glScalef(2.0,1.0,1.0);14 glutWireCube(1.5);15 glFlush(); //Finish rendering16 glutSwapBuffers();17 }1819void Reshape(int x, int y)20 {21if (y == 0 || x == 0) return; //Nothing is visible then, so return22//Set a new projection matrix23 glMatrixMode(GL_PROJECTION);24 glLoadIdentity();25//Angle of view:40 degrees26//Near clipping plane distance: 0.527//Far clipping plane distance: 20.028 gluPerspective(40.0,(GLdouble)x/(GLdouble)y,0.5,20.0);29 glMatrixMode(GL_MODELVIEW);30 glViewport(0,0,x,y); //Use the whole window for rendering31 }32static int times = 0;33void Idle(void)34 {35 times++;36if(times >30000)37 times = 0;3839if(times %30000 == 0)40 {41 xRotated += 0.3;42 yRotated += 0.1;43 zRotated += -0.4;44 Display();45 }46 }474849int main (int argc, char **argv)50 {51//Initialize GLUT52 glutInit(&argc, argv);53 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); //For animations you should use double buffering54 glutInitWindowSize(300,300);55//Create a window with rendering context and everything else we need56 glutCreateWindow("Cube example");57 glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);58 xRotated = yRotated = zRotated = 0.0;59 glClearColor(0.0,0.0,0.0,0.0);60//Assign the two used Msg-routines61 glutDisplayFunc(Display);62 glutReshapeFunc(Reshape);63 glutIdleFunc(Idle);64//Let GLUT get the msgs65 glutMainLoop();66return0;67 }。
OpenGL 球面相机旋转算法

旋转作为三维开发的基本功能,在任何3D程序中都需要。
用户通过旋转来实现对模型各个面的浏览,形成直观印象。
球面相机旋转这种旋转方式用户体验方式要优于x轴y轴混合旋转方式,模型旋转的方向和鼠标移动方向保持一致。
下面给出一种“球面相机”实现旋转的方法。
原理:移动鼠标时,通过gluLookAt来改变视点的位置(采用增量的方式),而模型保持不动。
即:只进行视点变换,不进行模型变换。
下图是用户按下左键,在屏幕上移动的一段距离(从A移动到B)。
由于屏幕坐标y轴向下,为了与投影平面坐标系(传统笛卡尔坐标)保持一致。
AM = y1-y2; /*将消息代码描述*/BM = x2-x1;建立屏幕和投影变换近裁截面之间的对应关系(如下图)。
代码实现:1 void setSphereCameraPos()2 {3 // 左键未按下,直接返回4 if (!is_left_button_down)5 return;67 // 从聚焦点指向视点的向量 OA向量8 vector3dd a(eye-target);910 // 计算球面相机半径11 radius = a.getLength();1213 // 将其单位化14 a.normailize();1516 // 当前相机向上方向与a做叉乘,计算投影面水平向右方向向量u17 vector3dd u = upvector.crossProduct(a);18 // 将其单位化19 u.normailize();2021 // 计算相机向上方向在投影面上的投影向量即垂直向上的方向向量v22 vector3dd v = a.crossProduct(u);23 // 将其单位化24 v.normailize();2526 // 计算屏幕AB在投影面上对应的向量 AB向量27 vector3dd m = u*delta_point.x + v*delta_point.y;2829 // 计算m向量的长度30 double len = m.getLength();31 // 降低灵敏度32 len /= 20.0;3334 if (len>0.0)35 {36 // 角度AOB 弧度表示弧长/半径37 double x = len/radius;38 // 将AB向量单位化39 m.normailize();4041 // 按相反方向转动视点到C 从而使得按与鼠标移动一致的方向转动模型42 x = -1*x;43 // 计算新的相机位置 C44 eye = target+(a*cos(x) + m*sin(x))*radius;4546 // 计算新的相机向上方向47 upvector = v;48 }49 }消息代码1 LRESULT CALLBACK WndProc( HWND hWnd, // Handle For This Window2 UINT uMsg,// Message For This Window3 WPARAM wParam,// Additional Message Information4 LPARAM lParam)// Additional Message Information5 {6 switch(uMsg) // Check For Windows Messages7 {8 case WM_LBUTTONDOWN:9 {10 is_left_button_down = true;11 pre_point.x = LOWORD(lParam);12 pre_point.y = HIWORD(lParam);1314 return 0;15 }1617 case WM_MOUSEMOVE:18 {19 if (is_left_button_down)20 {21 cur_pt.x = LOWORD(lParam);22 cur_pt.y = HIWORD(lParam);// delta_point为增量点23 delta_point.x= cur_pt.x-pre_point.x);// 保持屏幕坐标系和投影平面坐标系一致24 delta_point.y =-1*(cur_pt.y-pre_point.y);// 将当前点赋值给前一个点25 pre_point = cur_pt;26// 计算相机新的位置27 setSphereCameraPos();28 }30 return 0;31 }3233 case WM_LBUTTONUP:34 {35 is_left_button_down = false;36 return 0;37 }38 }3940 // Pass All Unhandled Messages To DefWindowProc41 return DefWindowProc(hWnd,uMsg,wParam,lParam);42 }43vector3dd类vector3dd1 class vector3dd2 {3 private:4 double x,y,z;56 public:7 vector3dd(){};8 vector3dd(double a, double b, double c){x=a;y=b;z=c;}9 vector3dd(const vector3dd& v){*this=v;}11 public:12 void operator=(const vector3dd& v){x=v.x;y=v.y;z=v.z;}13 vector3dd operator*(double a)14 {15 return vector3dd(a*x,a*y,a*z);16 }17 vector3dd operator+(const vector3dd& v)18 {19 return vector3dd(x+v.x,y+v.y,z+v.z);20 }21 vector3dd operator-(const vector3dd& v)22 {23 return vector3dd(x-v.x,y-v.y,z-v.z);24 }2526 public:27 double getX(){return x;}28 double getY(){return y;}29 double getZ(){return z;}3031 void setValue(double a, double b, double c)32 {33 x = a;34 y = b;35 z = c;36 }3738 double getLength()39 {40 return sqrt(x*x+y*y+z*z);41 }4243 void normailize()44 {45 double length = getLength();46 x/=length;47 y/=length;48 z/=length;49 }5051 void invert()52 {53 x*=-1;54 y*=-1;55 z*=-1;56 }5758 vector3dd crossProduct(const vector3dd& v)59 {60 return vector3dd(y*v.z-z*v.y,z*v.x-x*v.z,x*v.y-y*v.x);61 }6263 double dotProduct(const vector3dd& v)64 {65 return (x*v.x+y*v.y+z*v.z);66 }6768 void traceMsg()69 {70 fprintf(stdout, "%.7f, %.7f, %.7f\n", x, y, z);71 }72 };效果图:。
opengl中旋转公式推导

opengl中旋转公式推导OpenGL是一个用于渲染2D和3D图形的开放式图形库。
在OpenGL中,旋转是一种常见的变换操作,用于将对象绕某个轴旋转一定角度。
本文将推导出OpenGL中旋转的公式,并解释其原理和应用。
在OpenGL中,旋转变换是通过一个旋转矩阵来实现的。
旋转矩阵可以描述物体绕某个轴旋转一定角度后的新位置。
假设我们要将一个物体绕原点的Z轴旋转,旋转角度为θ。
那么旋转矩阵可以表示为:R = | cosθ -sinθ 0 || sinθ cosθ 0 || 0 0 1 |其中,cosθ表示θ的余弦值,sinθ表示θ的正弦值。
通过将物体的顶点坐标与旋转矩阵相乘,可以得到旋转后的新顶点坐标。
下面我们来推导一下这个旋转矩阵的公式。
假设物体的原始坐标为P(x, y, z),旋转后的新坐标为P'(x', y', z')。
我们可以表示P为一个列向量:P = | x || y || z |旋转矩阵R作用于P,得到P'的计算公式为:P' = R * P展开矩阵乘法,可以得到:P' = | cosθ -sinθ 0 | * | x || y || z |经过计算,可以得到:x' = x * cosθ - y * sinθy' = x * sinθ + y * cosθz' = z这就是物体绕Z轴旋转θ角度后的新坐标公式。
同样的,我们可以推导出绕X轴和Y轴旋转的公式,分别为:绕X轴旋转:x' = xy' = y * cosθ - z * sinθz' = y * sinθ + z * cosθ绕Y轴旋转:x' = x * cosθ + z * sinθy' = yz' = -x * sinθ + z * cosθ这三个公式分别描述了物体绕X轴、Y轴和Z轴旋转后的新坐标计算方式。
在OpenGL中,我们可以通过调用旋转函数来实现物体的旋转变换。
OPENGL实现3ds文件中的模型自由旋转

/$/
更新旋转矩阵
有 了 以 上 变 量 的 更 新 #接 下 来 就 是 根 据 这 些 更 新 #实 现 旋
转矩阵的更新 $
=)4< 1S;C<;504;H $$ZC@4?;5 !‘aG@ Ca^T=;C6 " 94E !?>1)?:3;6;< " 9?>1)?:3;6;<]E+3*; & 4E !4*S134(Q;< " I I 如果点击右键 # 重置旋转 9 I I 把 K+*6S)6 重置为单位矩阵 [+654\&EA;6a<;C646b!cK+*6S)6 "& I I 把 @B4*S)6 重置为单位矩阵 [+654\&EA;6a<;C646b!c@B4*S)6 "&
%% 和 %! 的叉乘得到 ! 即 ’
作者简介 ! 张正波 &%ERE= $! 男 ! 硕士研究生 ! 研究方向为信号与信息处理 ( 计算机图形图像 %
!"
!""#$%&
万方数据
计算机工程与应用
!"#$%&%’&!
而旋转角度就是 &% 和 &! 之间的夹角 ’ # 因此 $
!! " !& "
0;(6)5&E@ TC0;( & I I 保存拖动时的向量 ! 终点 " JKE3)+6 U<V7*6L4<6B & I I *;68)7C<* 函数用其来调整窗口 JKE3)+6 U<V7*6M;4NB6 &P
OpenGL 3D魔方游戏的设计与实现 3D魔方设计与实现 毕业论文[实用论文]
![OpenGL 3D魔方游戏的设计与实现 3D魔方设计与实现 毕业论文[实用论文]](https://img.taocdn.com/s3/m/5318f326cfc789eb172dc820.png)
摘要三维动画又称3D动画,是近年来随着计算机软硬件技术的发展而产生的一新兴技术,其技术是模拟真实物体的方式使其成为一个有用的工具。
由于其精确性、真实性和无限的可操作性,目前被广泛应用于医学、教育、军事、娱乐等诸多领域。
本设计是在Visual C++6.0开发环境下,使用OpenGL(Open Graphics Library)函数库,绘制魔方并实现魔方的旋转、随机生成、回拧、透明处理和放大缩小等功能。
采用基本图形的绘图函数及定位函数,添加相应的颜色、纹理来实现魔方模型的绘制。
通过读取载入BMP文件,应用纹理贴图技术来完成对魔方旋转面的处理。
利用随机数来随机产生一个打乱顺序的魔方,并使用C++标准模板库(STL)中的容器来记录魔方的旋转动作,为魔方的回拧提供依据。
关键词:魔方,动画,三维模型,纹理贴图Abstract3-D animation is also called 3D animation, in recent years as computer hardware and software technology and the development of a new and emerging technologies, its technical simulate the real object is the way to become a useful tool. Because of its accuracy, authenticity and unlimited operable, is now widely used in medicine, education, military, entertainment and many other areas.This is designed to Visual C + +6.0 development environment, the use of OpenGL (Open Graphics Library) functions, drawing Rubik's Cube and Rubik's Cube to achieve the rotation, randomly generated, to twist, transparent processing and zoom functions. Drawing a basic function of the graphics and positioning function, add the corresponding color, texture Rubik's Cube model to achieve the draw. By reading load BMP files, applications texture mapping technology to complete the Rubik's Cube rotation of the handle. Using randomly generated random numbers to disrupt the order of a Rubik's Cube, and the use of C + + Standard Template Library (STL) of containers to record the rotating Rubik's Cube action for the Rubik's Cube to provide the basis for fastening.Key words: Rubik's Cube, animation, model, rendering, texture mapping目录1引言 (1)1.1课题研究的目的与意义 (1)1.2 国内外发展现状 (2)1.3 论文的主要内容 (3)2 开发环境及开发工具 (5)2.1 课题需要的知识 (5)2.2 OpenGL概述 (6)3 3D魔方生成的技术实现 (12)3.1 设计思路和需要解决的问题 (12)3.2 初始化 (13)3.3 魔方模型的设计 (17)3.4 纹理及灯光的设计 (20)3.5 程序功能效果 (32)4 总结 (34)参考文献 (35)致谢辞 (36)附录1 外文原文 (37)附录2 中文译文 (46)1引言1.1课题研究的目的与意义一、目的随着计算机技术的发展和三维图形理论与算法的日益成熟,结合三维建模技术进行创建三维电子游戏已经成为可能,对于游戏的三维模拟,除了具有真实感,符合人们平时所看的物体,更可以增添游戏的乐趣。
openGL+VS2010的例程--旋转变色立方体(三维)

openGL+VS2010的例程--旋转变⾊⽴⽅体(三维)效果图如上。
步骤:⾸先,变换模型视⾓;然后,改变颜⾊;最后,利⽤顶点数组绘制⽴⽅体。
源代码如下:#include <GL/glut.h>// 绘制⽴⽅体// 将⽴⽅体的⼋个顶点保存到⼀个数组⾥⾯static const float vertex_list[][3] ={-0.5f, -0.5f, -0.5f,0.5f, -0.5f, -0.5f,-0.5f, 0.5f, -0.5f,0.5f, 0.5f, -0.5f,-0.5f, -0.5f, 0.5f,0.5f, -0.5f, 0.5f,-0.5f, 0.5f, 0.5f,0.5f, 0.5f, 0.5f,};// 将要使⽤的顶点的序号保存到⼀个数组⾥⾯static const GLint index_list[][2] ={{0, 1},{2, 3},{4, 5},{6, 7},{0, 2},{1, 3},{4, 6},{5, 7},{0, 4},{1, 5},{7, 3},{2, 6}};// 绘制⽴⽅体void DrawCube(void){int i,j;glBegin(GL_LINES);for(i=0; i<12; ++i) // 12 条线段{for(j=0; j<2; ++j) // 每条线段 2个顶点{glVertex3fv(vertex_list[index_list[i][j]]);}}glEnd();}static float rotate = 0;static int times = 0;void renderScene(void){glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清理颜⾊缓冲和深度缓冲glMatrixMode(GL_MODELVIEW); // 对模型视景的操作glLoadIdentity(); // 重置当前指定的矩阵为单位矩阵glPushMatrix(); // 压栈//glTranslatef(-0.2, 0, 0); // 平移//glScalef(1, 1, 1); // 缩放times++;if(times > 100){times = 0;}if(times % 100 == 0) // [0, 100){rotate += 0.5; // [0, 20)}glRotatef(rotate, 0, 1, 0); // 旋转glRotatef(rotate, 1, 0, 0);// 动态颜⾊变换--红->绿->蓝->红if(rotate == 0)glColor3f(1, 0, 0);if(rotate ==90)glColor3f(0, 1, 0);if(rotate ==180)glColor3f(0, 0, 1);if(rotate ==270)glColor3f(1, 1, 0);if(rotate ==360)rotate = 0;DrawCube(); // 绘制⽴⽅体glPopMatrix();// 出栈glutSwapBuffers();}int main(int argc, char* argv[]){glutInit(&argc, argv); // 初始化GLUTglutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); glutInitWindowPosition(100, 100); // 显⽰窗⼝在屏幕的相对位置glutInitWindowSize(500, 500); // 设置显⽰窗⼝⼤⼩glutCreateWindow(argv[0]); // 创建窗⼝,附带标题glutDisplayFunc(renderScene); // 注册显⽰⽤的函数glutIdleFunc(renderScene); // 注册空闲⽤的函数glutMainLoop(); // GLUT 状态机return0;}。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
华中科技大学电子科学与技术系课程设计报告( 2010-- 2011年度第 2 学期)名称:软件课程设计题目:基于OpenGL的3D旋转魔方实现院系:班级:学号:学生姓名:指导教师:设计周数:成绩:日期:年月日目录1.课程设计介绍............................................................................................ (2)1.1目的.............................................................................................................. (2)1.2内容.............................................................................................................. (2)1.3取得的成果 (2)2.程序分析..................................................................................................... (3)2.1 程序原理 (3)2.2 程序流程 (4)2.3 数据结构 (13)2.4 重要函数 (13)3.程序分析与结果演示 (16)3.1 成果演示 (16)3.2 程序分析 (17)4.出现过的问题 (18)5.心得和小节 (19)1.课程设计介绍1.1目的21世纪是高科技时代,是信息技术时代,而计算机技术无疑会引领各行各业,为我们带来一个全新的时代。
作为新世纪的接班人,我们必须拥有良好的计算机应用能力,才能跟上世界发展的大流,不至于在激烈的竞争中被淘汰。
而程序作为计算机的灵魂,因此编程能力对当代大学生来说至关重要。
通过本课程单元的学习,可以对软件工程项目从整体上有一个较清晰的了解和认识;可以提高自身软件编程能力,培养对计算机编程兴趣,培养良好的编程习惯。
同时编程时的态度和方法对我们今后的学习和工作也有重要影响。
所以整体看来软件课程设计这门课程提高了我们计算机使用水平,培养了我们良好的学习态度,对我们个人的发展而言有着重要的意义。
1.2 内容(1)巩固和加强c语言相关编程知识,学会用Visual C++6.0进行c语言编程。
(2)掌握程序设计流程和思想,模块化结构分析以及程序设计流程,初步培养需求分析、软件测试、调试的能力。
(3)掌握win32相关编程知识,了解windows程序内部运行机制。
(4)掌握OpenGL贴图技术原理与函数实现,掌握OpenGL几何的移动、旋转等模式变化的原理。
(5)掌握魔方图形构造原理,在掌握二阶魔方构造原理的基础上,构造出三阶魔方并实现其旋转。
1.3 取得的成果在理解和掌握老师所给的范例程序的基础上,借助Win32平台进行了一系列调试和学习,熟练掌握了Win32 Application开发流程。
同时也学习和了解了OpenGL的基本知识,掌握了一些OpenGL的重要技术与重要函数的使用,编写了一些简单的OpenGL程序。
在比较透彻的了解了二阶魔方的构造原理后,成功地构造出了三阶魔方,换上了自己班级同学的图片,并且在一个小立方体的六个面上贴上了不同的图片。
能够比较完美的实现三阶魔方各个层面的随机旋转,并且把窗口背景设置为红色。
为了使程序更加有趣,我在程序中导入了刘德华的《爱你一万年》这首歌,使魔方在旋转的同时能够播放歌曲。
除此之外,我还实现了一种三阶魔方自由移动的屏保效果:即三阶魔方在旋转的同时能够在屏幕内部自由移动,并且在边缘无限次的反弹。
在魔方平移的过程中同样可以通过四个方向键来控制魔方的移动。
当松开方向键后,魔方会继续按照先前的方式自由移动。
2.程序分析2.1 程序原理(1)OpenGLOpenGL是为Open Graphics Library的简称,它是3D绘图工业标准,广泛地应用于计算机3D绘图领域。
它是个专业的开放的3D程序接口,是一个功能强大,调用方便的底层3D图形库。
它独立于窗口系统和操作系统,以它为基础开发的应用程序可以十分方便地在各种平台间移植;OpenGL可以与Visual C++紧密接口,便于实现机械手的有关计算和图形算法,可保证算法的正确性和可靠性;它具有七大功能:建模、变换、颜色模式设置、光照和材质设置、纹理映射、位图显示和图象增强和双缓存动画功能。
OpenGL 使用简便,效率高。
本项目是在Visual C++6.0开发环境下,使用OpenGL函数库,绘制魔方并实现魔方贴图、随机旋转、以及键盘控制等功能。
采用基本图形的绘图函数及定位函数,添加相应纹理来实现魔方模型的绘制。
通过读取载入BMP 文件,应用纹理贴图技术来完成对魔方旋转面的处理。
通过OpenGL中对图形的旋转和平移函数来实现对魔方整体的旋转和平移。
(2)旋转在建立好空间三维模型后,要实现魔方体每一层面的旋转。
而魔方体每一层面的旋转归结于每一个小立方体的旋转。
每个小立方体的旋转又最终归结于每个点的旋转。
对于一个坐标为(x,y,z)的点,如果围绕z轴逆时针旋转角度为a,则旋转之后z坐标不变,x和y坐标分别变为x*cosa - y*sina,x*sina + y*cosa,如图1所示:图1这样,实现了每个点的旋转,针对每个立方体只需采用循环对8个点均采取旋转操作就可实现一个立方体的旋转。
(3)消息循环与定时器由于程序在运行时CPU只能执行一个任务,然而此项目中魔方在旋转的同时要实现平移,所以需要用到Win32中的定时器功能。
此程序中要用到的定时器的函数原型为:SetTimer(HWND hWnd ,UINT nIDEvent,UINT uElapse,TIMERPROC lpTimerFunc)HWND hWnd为窗口句柄,使程序和定时器建立联系,UINT nIDEvent 是定时器ID,用于区分不同的定时器;UINT uElapse为定时器触发周期,意味着多长时间执行一次;,TIMERPROC lpTimerFunc为该定时器执行时触发的函数。
所以控制好不同定时器的触发周期和触发函数,就能使魔方的各个层面的旋转和平移互不冲突。
2.2 程序流程(1)WinMain主函数WinMain主函数是所有Win32程序的入口点。
在WinMain函数里窗体的建立和消息循环,在消息循环中实现键盘、鼠标输入事件处理响应。
在本程序中,要创建Window窗体和构建OpenGL设备绘图环境。
Window窗体创建步骤:●窗体类注册:RegisterClass●设置显示分辨率:ChangeDisplaySettings●设置窗体大小:AdjustWindowRectEx●创建窗体:CreateWindowExOpenGL绘图环境搭建:●获取设备绘图环境(DC,DeviceContext):hDC=GetDC(hWnd)●选择绘图环境像素格式:ChoosePixelFormat(hDC,&pfd),其中pfd为像素格式描述符,如果设置不对,OpenGL绘图失败,看不到正确的显示结果。
●设置绘图环境像素格式:SetPixelFormat(hDC,PixelFormat,&pfd)●获取OpenGL绘图环境:hRC =wglCreateContext(hDC)●设置OpenGL绘图环境:wglMakeCurrent(hDC,hRC)(2)三维建模一个三阶魔方体由27个小立方体构成,每个小立方体由8个顶点组成,而每个顶点又有x,y,z三个方向上的坐标值。
这样由结构体的层层嵌套就可以对魔方体的每个小立方体、每个顶点进行操作。
typedef struct{GLfloat p[3]; //定义一个点的x,y,z 坐标值}stPoint;typedef struct{stPoint CubePoint[8];//定义一个小立方体的8个顶点}stCube;如图2:0(-1.0f, -1.0f, 1.0f)(1.0f, -1.0f, 1.0f)3Y Y图2stCube Cube[27]; //定义魔方体的27个小立方体其中一个难点是怎样根据各个点的坐标值构造出魔方体,其实只要定义好每个顶点的坐标就行了。
但是三阶魔方必须定义27*8=216个顶点的坐标值,而且很难用for循环实现,因为各个顶点的x,y,z坐标值几乎没有什么规律。
但是如果能够将一个小魔方体作为一个整体来看待,工作量似乎会减轻很多。
先在整个魔方体中间定义一个基准小立方体,则整个魔方体的各个小立方体均可以通过这个基准立方体的平移来实现,各个小立方体上各点的平移向量和小立方体中心的平移向量相同。
static stPoint CubePoint[8]= //定义好基准小立方体,边长为1 { -0.5f, -0.5f, 0.5f}, //0 --{ 0.5f, -0.5f, 0.5f }, //1{0.5f, 0.5f, 0.5f }, //2 --{-0.5f, 0.5f, 0.5f}, //3{-0.5f, -0.5f, -0.5f}, //4 --{-0.5f, 0.5f, -0.5f}, //5{0.5f, 0.5f, -0.5f}, //6 --{0.5f, -0.5f, -0.5f}, //7};基准小立方体平移得到一个小立方体Cube[0]:for(int i=0;i<8;i++){Cube[0].CubePoint[i].p[0] = CubePoint[i].p[0] + 1.0f;Cube[0].CubePoint[i].p[1] = CubePoint[i].p[1] - 1.0f;Cube[0].CubePoint[i].p[2] = CubePoint[i].p[2] - 1.0f;}其他26个立方体可通过同样的方法得到。
我认为这是整个程序中最难也是最麻烦的一点。
本程序是通过reset_model()这一函数来构造出整个魔方体的。
(3)OpenGL贴图实现glGenTextures(1, &texture[i]),作用是利用载入的图像生成纹理。
glTexCoord2f(GLfloat s, GLfloat t) 函数用于绘制图形时指定纹理的坐标。
第一个参数是X坐标,0.0是纹理的左侧,0.5是纹理的中点,1.0是纹理的右侧。
第二个参数是Y坐标,0.0是纹理的底部,0.5是纹理的中点,1.0是纹理的顶部。
为了将纹理正确的映射到四边形上,必须将纹理的四个角与四边形的四个角相对应。