Sunshine Alike

半完美主义

  C++博客 :: 首页 :: 联系 :: 聚合  :: 管理
  35 Posts :: 1 Stories :: 56 Comments :: 0 Trackbacks

常用链接

留言簿(15)

积分与排名

  • 积分 - 49579
  • 排名 - 451

最新随笔

最新评论

一、 MFC 框架下使用 OpenGL 绘图演示平移、旋转、缩放等操作的具体实现

二、 实现算法

绘制的图形以各种顶点及顶点之间的线、面构成

要想对这些图形进行操作,只需要对各种顶点在坐标系中的坐标进行转换即可

顶点在 OpenGL 中的坐标以四维形式表示:( X,Y,Z,W

其中 X,Y,Z 对应三维系统中 X Y Z 三个柚; W 默认为 1 ,一般为了方便各种操作时坐标换算而将三维坐标系提升为四次,即齐次坐标系

平移操作——对应 glTranslate 函数:

初始点:( X,Y,Z,W

使用转换矩阵 TMatrix

1, 0, 0, Tx

0, 1, 0, Ty

0, 0, 1, Tz

0, 0, 0, 1

(X’, Y’, Z’) = TMatrix * (X, Y, Z), 其中 Tx Ty Tz 对应 glTranslate 函数中的三个参数,分别表示三个方向的的平移量;原始坐标右乘平移矩阵后即得到新的坐标

缩放操作——对应 glScale 函数:

使用转换矩阵为 SMatrix

Sx, 0, 0, 0

0, Sy, 0, 0

0, 0, Sz, 0

0, 0, 0, 1

(X’, Y’, Z’) = SMatrix * (X, Y, Z)

此次自己实现的缩放函数与 OpenGL 有所不同,我实现的是与图形的中心点为基准进行缩放,所以进行矩阵变换前需要计算各个坐标的位置并求几何中心

旋转操作——对应 glRotate 函数(逆时针方向):

在三维坐标系统中,旋转操作与二维情况有所不同,因为三维中的一个点可以绕不同的方向进行旋转,所以除了要指定旋转角度外,还要指定旋转轴

当所取旋转轴为 X Y Z 三个坐标轴时,与二维情况相似

即所选取的轴那一方向上的坐标不变,在其它两个轴所成的平面上进行二维旋转变换

根据这个规律可以把三维中绕任意轴旋转的操作分为几个操作来完成

步骤:

先将待旋转的坐标与旋转轴平移,使旋转轴经过原点

进行若干次旋转操作,例旋转轴与 Z 轴正向重合

依据对坐标轴旋转的方法将待旋转坐标进行旋转操作

应用逆旋转使旋转轴回到原方向

应用逆平移使旋转轴回到原位置

 

二维情况下旋转矩阵为:

cosQ, -sinQ, 0

sinQ, cosQ, 0

0, 0, 1

 

此次采用先绕 X 转做旋转 Rx ,再绕 Y 转旋转 Ry 使旋转轴与 Z 转正向重合,再绕 Z 轴做 Rz 旋转 Q 度,再进行逆操作还原位置

: (X’, Y’, Z’) = Rx*Ry*Rz(Q)*(Ry -1 )*(Rx-1)

其中 Q 是需要旋转的角度, 逆矩阵 A -1 = A*/|A|

代数余子式: (-1)^(i+j)Aij

 

三、 程序结构

使用 MFC 生成程序界面, OpenGL 负责绘制图形

文档 / 视图结构

文件数据为,图形的类型以及各个顶点坐标

从菜单中选择要进行的操作:平移,旋转,缩放后出现对话框输入参数

平移—— 3 个参数,分别表示 X,Y,Z 各个轴向的平移量

旋转—— 4 个参数,第一个角度 Angle, 后三个表示转轴向量

缩放—— 3 个参数,表示 X,Y,Z 轴方向上的缩放比例,可以为负数

文件数据为:

一个 CArray<Point, Point> m_PointArray 保存图形的各个顶点信息

一个表示图形形状的 int m_nShape 表示 glBegin 函数里的参数

 

四、 MFC 中使用 OpenGL 绘图

具体还没有研究,只是照搬网上教程,以后补上

View 头文件中加入

       HGLRC m_hRC;    //Rendering Context

       CDC* m_pDC;        //Device Context

       BOOL InitializeOpenGL();    //Initialize OpenGL

BOOL SetupPixelFormat();    //Set up the Pixel Format

 

实现部分:

InitializeOpenGL

SetupPixelFormat

此外需要将 View 类中的 OnEraseBkgnd 消息屏蔽掉,使之直接返回 TRUE ,因为消除背景的工作已经将由 OpenGL 来做,不需要由这个函数再来做一遍。

PreCreateWindow 函数中修改

cs.style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;

保证 OpenGL 不会绘制到其它窗口中去

OnCreate 函数中调用 InitializeOpenGL 函数就可以在 View 中进行绘制了

 

另外,为了适应窗口大小变化,还需要在 OnSize 函数中加入高速视域的代码

OnSize
 

做好一切准备工作后,就可以在 OnDraw 中使用 OpenGL 函数进行绘制了,不过别忘了程序最后要进行资源的释放,在 OnDestroy 中加入清理工作

OnDestroy

      最后程序演示结果:

 

五、 编程中遇到的问题总结

1.       复习了操作符重载的相关内容

2.       浮点数的比较,这个比较重要,以前在课上只是听说,没有特别印象,在耗费了我 2 个小时的调试之后,以后应该再也不会忘了。 Fabs f1-f2 <= 精度要求

3.       此次写的工具类 Matrix 胜于处理向量,矩阵的相关操作,因为偷懒还不太完善,尤其是矩阵的一些操作比较求模,求逆都没有实现,以后补上

http://www.cppblog.com/Files/sunshinealike/HomeWork1.rar

posted on 2009-09-29 15:06 Sunshine Alike 阅读(6763) 评论(0)  编辑 收藏 引用 所属分类: 图形学

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理