`
icheng
  • 浏览: 821213 次
  • 性别: Icon_minigender_1
  • 来自: 珠海
文章分类
社区版块
存档分类
最新评论

Win32 OpenGL编程(4) 2D图形基础(颜色及坐标体系进阶知识)

 
阅读更多

Win32 OpenGL 编程 (4) 2D 图形基础(颜色及坐标体系进阶知识)

write by 九天雁翎 (JTianLing) -- blog.csdn.net/vagrxie

讨论新闻组及文件

一、 提要

OpenGL 本身是作为高性能 3D 图形绘制设计的,实际上光是用于 2D 绘图的话 OpenGL 显得相对复杂,但是 2D 作为 3D 的基础,也值得稍微学习一下,说的直白点 3D 不过是在 2D 上增加了一维,虽然此一维让世界整个变了样。本文从本系列文章 3 (链接见本文最后的本系列其他文章,以后简称 XO3 )中为了简化说明没有提及的 OpenGL 默认一些默认环境值切入,接着讲解一些 OpenGL 下绘制 2D 图形的技术,逐渐从原来的单一图元向多种图元组合图形相关的技术扩展。与坐标体系相关的很多观点并不见诸于广为流传的经典教程,纯粹是个人编程经验之谈,不见的完全正确,可看作是一家之谈,但是个人认为对于知其然并知其所以然有所帮助。

本文后,应该能解决大部分用 OpenGL 绘制 2D 图形的技术问题,究竟能做出什么,就看大家的编程思想和创造性思维了。

二、 颜色

XO3 中,我们没有指定基本图元的颜色,但是,很显然,我们看到了图像,图像的背景是黑的,前景是白的,这就是 OpenGL 的默认颜色。我们可以通过 glClearClolor 函数改变背景颜色,即 glClear 函数清除颜色缓冲区时所用的颜色。 glColor* 用于指定前景色(即我们用于绘制图形时所用的颜色)

OpenGL Reference Manual :

glClearColor - specify clear values for the color buffers

C SPECIFICATION

void glClearColor ( GLclampf red , GLclampf green , GLclampf blue , GLclampf alpha )

PARAMETERS

red , green , blue , alpha

Specify the red, green, blue, and alpha values used when the color buffers are cleared. The default values are all zero.

DESCRIPTION

glClearColor specifies the red, green, blue, and alpha values used by glClear to clear the color buffers. Values specified by glClearColor are clamped to the range [0,1].

glColor *

Specifies a pointer to an array that contains red, green, blue, and (sometimes) alpha values.

glClearColor 相对较简单,就是一个接受 RGBA 的函数, glColor* 本身的意义也很简单,但是因为受到 C 语言无函数重载特性的问题,一族函数多达 32 个,其实就是一个意思。。。。。。 -_-! 再次提及 C 语言的弱点,喜欢 C 的人莫怪,要是这也不是问题的话,那世界上就没有问题了。

顺面简单说下颜色,事实上计算机的颜色表示是按人眼的感知能力来分的(不是实际自然的颜色表示法),人眼有 3 种光感细胞,分别能感受红 (RED) ,绿 (Green) ,蓝( Blue ),人眼感知的最终颜色由 3 种细胞综合得出,一般将其简称 RGB ,再加上用于表示透明的 alpha ,合起来简称 RGBA ,这就是 glClearColor 4 个函数的意思,学过数字图像处理的人应该还知道,其实表示颜色的方式还有很多,但是其他的颜色表示法在 OpenGL 中,甚至 PC 中都不常用,一般都习惯于 RGBA 系统,可能表示较为简单,易于换算吧。(真的感兴趣的可以参考《 Digital Image Processing By Rafael C. Gonzalez BTW ,说点题外话,此书是 原来我们的数字图像处理课程的教程,当时用的是第 2 版,如今第 3 版都已经出来了,读起来饶有趣味,本书当时用的是英文原版书,是大学中个人感觉所用教科书中最好的一本之一。)

另外,这里也可以将一般 OpenGL 函数与 glBegin glEnd 的关系梳理一下,事实上, glBegin,glEnd 之间不仅仅可以使用 XO3 中说过的那些 glVertex* 指定顶点的函数,纯粹与 C++ 相关的代码可以随意的放在 glBegin glEnd 之间,而 OpenGL 的函数就不是了,虽然可以应用于其中的 OpenGL 函数的很多,但是要牢记一点,不是所有的 OpenGL 函数都能放在其中,轻则无效,重则出现在《 OpenGL 编程指南》提及的不可预知的结果,使用时按一种原则使用最好,那就是不是明确知道能在其中使用的就不要放在其中使用。比如, glClearColor 就不能放在 glBegin,glEnd 中, glColor* 就行。

XO3 中利用了 OpenGL 的默认颜色,实际相当于调用了 glClearColor(0.0, 0.0, 0.0, 0.0); 指定背景为黑色, 调用 glColor4f(1.0, 1.0, 1.0, 1.0); 指定前景为白色了。 比如,下面程序片段就与 XO3 中的程序片段运行效果完全一样。

//OpenGL 初始化开始

void SceneInit (int w ,int h )

{

glClearColor (0.0, 0.0, 0.0, 0.0);

}

// 这里进行所有的绘图工作

void SceneShow (GLvoid )

{

glClear (GL_COLOR_BUFFER_BIT );

glColor4f (1.0, 1.0, 1.0, 1.0);

glBegin (GL_POLYGON );

glVertex3f (-0.5, -0.5, 0.0);

glVertex3f (0.5, -0.5, 0.0);

glVertex3f (0.5, 0.5, 0.0);

glVertex3f (-0.5, 0.5, 0.0);

glEnd ();

glFlush ();

}

知道了这些,就可以通过改变上述片段中 glClearColor,glColor4f 的参数去指定背景和不同基本图元的颜色了,这么简单的例子就留给大家自己去尝试了。

三、 着色模型

这里有个问题, glColor* 放在 glBegin glEnd 之外,好理解,整个图形就是一个颜色,那么在中途改变颜色会使图形有什么改变呢?难道仅仅指定每个点的颜色?这里再介绍一个函数, glShadeModel ,用于指定 OpenGL 中图形颜色的着色模型。参数可以是 GL_SMOOTH GL_FLAT ,当为 GL_FLAT 时,表示单一着色,如其原意, flat ,平坦的着色,即整个图元都是一个颜色,具体是什么颜色,根据 glBegin 不同的参数有不同的结果,在此时比较混乱,《 OpenGL 编程指南》中推荐大家最好就是为这种图元指定一种颜色,具体的颜色如下图:(来自于《 OpenGL Programming Guide 》在网上的版本 4

Table 4-2 : How OpenGL Selects a Color for the ith Flat-Shaded Polygon

Type of Polygon| Vertex Used to Select the Color for the ith Polygon

single polygon | 1

triangle strip | i+2

triangle fan | i+2

independent triangle| 3i

quad strip | 2i+2

independent quad | 4i

这里主要讲的是参数是 GL_SMOOTH 时,表示平滑着色,这个时候在指定顶点的时候用了不同的颜色会出现渐变效果,呵呵,想不到渐变效果这么容易吧?:)这里给大家看一个有意思的例子。为了简化实现,仅用上红下绿色作为例子,有兴趣的可以将其改为彩色,效果更好,主要代码片段如下,注释的很清楚了,不做过多解释。

// 矩形顶部的Green 颜色

GLfloat gfTopGreen ;

// 矩形底部的Red 颜色

GLfloat gfBottomRed ;

// 渐变方向

GLboolean gbShadeDir ;

#define FRAME_PER_SECOND (60)

#define TIME_IN_FRAME (1000/FRAME_PER_SECOND )

#define WIDTH (800)

#define HEIGHT (600)

#define SHADE_SPEED (0.005)

//OpenGL 初始化开始

void SceneInit (int w ,int h )

{

glClearColor (0.0, 0.0, 0.0, 0.0);

glShadeModel (GL_SMOOTH );

gfTopGreen = 0.0;

gfBottomRed = 1.0;

// 默认方向,Top 增长,Bottom 减少

gbShadeDir = true ;

}

void IncreaseToTop ()

{

gfTopGreen += SHADE_SPEED ;

gfBottomRed -= SHADE_SPEED ;

}

void DecreaseToTop ()

{

gfTopGreen -= SHADE_SPEED ;

gfBottomRed += SHADE_SPEED ;

}

void DrawRect ()

{

glBegin (GL_QUADS );

glColor3f (0.0, gfTopGreen , 0.0);

glVertex3f (-0.5, -0.5, 0.0);

glVertex3f (0.5, -0.5, 0.0);

glColor3f (gfBottomRed , 0.0, 0.0);

glVertex3f (0.5, 0.5, 0.0);

glVertex3f (-0.5, 0.5, 0.0);

glEnd ();

glFlush ();

}

// 这里进行所有的绘图工作

void SceneShow (GLvoid )

{

glClear (GL_COLOR_BUFFER_BIT ); // 清空颜色缓冲区

// 默认方向时

if (gbShadeDir )

{

if (gfTopGreen <= 1.0)

{

IncreaseToTop ();

}

else

{

gbShadeDir = false ;

}

}

else

{

if (gfTopGreen >= 0.0)

{

DecreaseToTop ();

}

else

{

gbShadeDir = true ;

}

}

DrawRect ();

}

运行效果附图 1 所示。完整源代码在 2009-10-14/GLShadeAnimation/ 下,查看或下载方式见本文最后的说明。

会发现 OpenGL 本身的颜色渐变效果在不断变化的时候非常平滑,而且实现如此简单,根本就不用几行代码。事实上, glShadeModel(GL_SMOOTH); 一句可有可无,因为 OpenGL 模式的着色模型就是平滑的。

四、 坐标体系进阶知识

XO3 中提到过 OpenGL 坐标体系相关的知识,也讲过了 OpenGL 中默认全局坐标体系与 Windows 普通程序的不同,事实上, OpenGL 允许我们在需要的时候对 OpenGL 的坐标系统进行选项丰富的控制。

1. Windows GDI 坐标体系

在知道或者容易知道所有物品的坐标时,我们完全可以将 OpenGL 的坐标系统改成如 Windows 普通程序一样,利用以前习惯的操作方式操作。相关的函数是 gluOrtho2D

OpenGL Reference Manual :

gluOrtho2D - define a 2-D orthographic projection matrix

C SPECIFICATION

void gluOrtho2D ( GLdouble left , GLdouble right , GLdouble bottom , GLdouble top )

PARAMETERS

left , right Specify the coordinates for the left and right vertical clipping planes.

bottom , top Specify the coordinates for the bottom and top horizontal clipping planes.

DESCRIPTION

gluOrtho2D sets up a two-dimensional orthographic viewing region. This is equivalent to calling glOrtho with near = -1 and far = 1 .

简单的说, gluOrtho2D 函数的作用就是,指定整个 2D 平面的左,右,下,上的坐标,以指定整个坐标体系,想要将 OpenGL 的坐标体系换成 Windows 那样只需要如下调用 gluOrtho2D 即可:

gluOrtho2D (0.0, (double )WIDTH , (double )HEIGHT , 0.0);

即,指定客户区左边界坐标为 0 ,右边界坐标为客户区宽度,下边界坐标为客户区高度,上边界为 0 ,这样,一个 Windows 坐标体系就诞生了。(这里使用起来会感觉顺序比较怪,我们习惯了上下的顺序,事实上,在 OpenGL 中由于更惯用的是

gluOrtho2D (0.0, (double )WIDTH , 0.0, (double )HEIGHT );

体系,这样与真实笛卡尔坐标体系第一象限一致,也与 OpenGL 中默认的 X,Y 轴方向一致。)

下面的用法,对顶点的指定完全是类 Windows 的直接指定绝对坐标,但是完成了与 XO3 中一样的矩形,就靠那句 gluOrtho2D 对坐标体系的改变了。

//OpenGL 初始化开始

void SceneInit (int w ,int h )

{

glClearColor (0.0, 0.0, 0.0, 0.0);

gluOrtho2D (0.0, (double )WIDTH , (double )HEIGHT , 0.0); // 定义一个Windows 坐标系

}

// 这里进行所有的绘图工作

void SceneShow (GLvoid )

{

glClear (GL_COLOR_BUFFER_BIT );

glColor4f (1.0, 1.0, 1.0, 1.0);

glBegin (GL_POLYGON );

glVertex3f (200, 150, 0.0);

glVertex3f (600, 150, 0.0);

glVertex3f (600, 450, 0.0);

glVertex3f (200, 450, 0.0);

glEnd ();

glFlush ();

}

这种坐标系下,由于图形全部按客户区在 Windows 坐标体系的绝对坐标来绘制,在容易获取图形的绝对坐标时,不失为一种好办法。此情况与普通的 Windows GDI 绘制类似,也不多举例子了,会在下面与 OpenGL 坐标体系比较的时候提及一些例子。

2. OpenGL 默认坐标体系

OpenGL 默认坐标体系是怎么样的,在 XO3 中已经讲的比较清楚了,还不清楚的请 过去看看 。这里主要讲讲 OpenGL 这样选择的原因,还有与 Windows 默认的坐标体系相比较的好处。

因为在 2D 体系中,容易获得图形的绝对坐标的情况相对较多,所以 Windows GDI 绘制的时候以此为默认坐标体系,毕竟 Windows GDI 主要考虑的是 2D 的情形,但是 OpenGL 考虑的主要是 3D 的情况,很多时候绝对坐标就没有那么好获得了。这里反复提到绝对坐标,没有错,在 OpenGL 的默认坐标体系中,以中心点为原点,要的就是方便用相对坐标来绘图。由于我们还没有学到 3D 呢,那么用一个 2D 的例子来看看吧。这个例子是绝对反 Windows 坐标体系的 -_-! 呵呵,圆!别怪我恶毒啊。

先看我们在 OpenGL 默认坐标体系下画一个圆。这里利用的是绘制多边形的方式来模拟,此思想我第一次提出来的时候感觉挺新鲜,还很津津乐道的说是受到中学数学老师讲解圆时的技巧,但是学多了与图形有关的东西,这不过是个老掉牙的东西了,我在以前讲 Small Basic 的时候提及过。(见《 初学编程该怎么学? —— 对初学者程序设计语言学习的思考( 1

见下面的代码:(思路来自于参考 2 的示例 2-4

#define WIDTH (600)

#define HEIGHT (600)

#define PI (3.1415926535898)

//OpenGL 初始化开始

void SceneInit (int w ,int h )

{

glClearColor (0.0, 0.0, 0.0, 0.0);

}

// 这里进行所有的绘图工作

void SceneShow (GLvoid )

{

glClear (GL_COLOR_BUFFER_BIT ); // 清空颜色缓冲区

glColor4f (1.0, 1.0, 1.0, 1.0);

GLint iCirclePoints = 50;

glBegin (GL_LINE_LOOP );

for (int i = 0; i < 50; ++i )

{

double dAngle = 2 * PI * i / iCirclePoints ;

glVertex3f (cos (dAngle )/2, sin (dAngle )/2, 0.0);

}

glEnd ();

glFlush ();

}

首先为了保证圆是正圆,我调整了窗口为矩形窗口,因为此处是相对坐标,长度也是相对长度,当窗口不正,圆也就歪了。所谓上梁不正下梁歪嘛。

其次,利用 cos,sin 两个 3 角函数来计算顶点的位置,此例中圆的半径我希望是 1/2 ,所以此处都除了 2 ,至于为啥如此计算,我特意为已经长久将原来基本的数学知识遗忘的人画了张草图,见附图 2 ,剩下的就真是基本的直角三角形已知一角及斜边求另一边的过程了(临边或对边),还不明白我也就没有办法了。

完整源代码见我的源代码目录 2009-10-14/GLDrawCircle/ ,查看或下载方式见本文最后的说明。

附图嘛,光是展示这么一个圆就太无趣了,我在循环中加入一个改变颜色的代码,这样看起来圆会更酷一些,通过颜色渐变的效果 ( 刚讲的 ) 达到一种类似光照下的立体图形的效果,代码如下:

for (int i = 0; i < 50; ++i )

{

glColor4f (1.0/i , 0, 0, 1.0);

double dAngle = 2 * PI * i / iCirclePoints ;

glVertex3f (cos (dAngle )/2, sin (dAngle )/2, 0.0);

}

效果见附图 2 ,够酷吧 ^^ 觉得不够酷的话,在学了光照,视图变换,模型变换后,到时候先画个红球,再经过恰当的视角设定,设定好光照,然后才实现类似效果,就知道这时通过这样简单的方法能看到类似效果有多么酷了。

此例纯为装酷用,为表达反对装酷,专注原话题的意思,请将其看做一个普通圆,我也只提供上述普通圆形的完整源代码。(虽然事实上你只需要在上面循环中加上一个 glColor* 就行,虽然事实上我还是提供了酷一些的附图,聊当为大家熟悉熟悉刚讲的平滑着色模型吧)还是讲老话题吧。这是在 OpenGL 默认坐标体系下我们画出来的圆。因为原点在中心点,所以我们可以简单的通过上述计算算出圆周上各个点的坐标。假如用 Windows 坐标体系,此时圆的坐标怎么算?假如直接用 Windows 坐标体系算会算死人,相对较好的方法还是按如上的方法算,然后计算上圆心的相对偏移,下面是一个 Windows 坐标体系下画圆的代码:

//OpenGL 初始化开始

void SceneInit (int w ,int h )

{

glClearColor (0.0, 0.0, 0.0, 0.0);

gluOrtho2D (0.0, (double )WIDTH , (double )HEIGHT , 0.0);

}

// 这里进行所有的绘图工作

void SceneShow (GLvoid )

{

glClear (GL_COLOR_BUFFER_BIT ); // 清空颜色缓冲区

glColor4f (1.0, 1.0, 1.0, 1.0);

// 一下代码实际中可移到初始化中

GLint iCirclePoints = 50;

GLint iRadius = WIDTH / 4;

POINT ptCenter ;

ptCenter .x = WIDTH / 2;

ptCenter .y = WIDTH / 2;

glBegin (GL_POLYGON );

for (int i = 0; i < 50; ++i )

{

double dAngle = 2 * PI * i / iCirclePoints ;

glVertex3f (cos (dAngle ) * iRadius + ptCenter .x , sin (dAngle ) * iRadius + ptCenter .y , 0.0);

}

glEnd ();

glFlush ();

}

注意 gluOrtho2D(0.0, (double)WIDTH, (double)HEIGHT, 0.0); 的调用,坐标系已经变了 ,虽然用了相对坐标计算的思想,但是会发现计算过程还是明显繁复了很多。这在 2D 的时候就可以看出一些端倪了, 3D 的时候有办法直接通过绝对坐标系去计算一个圆球吗? -_-! 另外,假如更容易理解的话,此例也可以看做先在坐标原点画了个圆,然后通过移动圆心,将整个的圆移到了屏幕的中心了。

完整源代码见我的源代码目录 2009-10-14/WinDrawCircle/, 查看或下载方式见本文最后的说明。

因为不希望误导了 OpenGL 初学者,必须提及其实在 OpenGL 下画圆有更优美高效的解决方案,如下面的代码:

// 这里进行所有的绘图工作

void SceneShow (GLvoid )

{

glClear (GL_COLOR_BUFFER_BIT ); // 清空颜色缓冲区

glColor4f (1.0, 1.0, 1.0, 1.0);

GLUquadricObj * qobj = gluNewQuadric ();

gluQuadricDrawStyle (qobj , GLU_FILL );

gluDisk ( qobj , 0.0, 0.5, 50, 1);

glFlush ();

}

但是牵涉的东西较多,暂时不详细解释。感兴趣的可以先去看看 OpenGL Reference Manual 》或者去看《 OpenGL 编程指南》的第 11 章。

五、 图元的移动,旋转

1. 移动

前面常说是 OpenGL 是计算相对坐标, Windows 的是去计算绝对坐标,其实主要是相对于 Windows 屏幕坐标体系而言的,可能有点迷惑,实际上无论哪种坐标系算出的坐标都是一个一个绝对坐标值,但是所谓相对坐标,不仅仅是指 OpenGL 用了相对屏幕高度 / 宽度的浮点数方式来表示坐标,而且在 OpenGL 中用相对坐标的方式来思考会更加容易一些,事实上, OpenGL 为此提供了强大的支持,比如,现在我们将屏幕按田字形切成四块,然后画上 4 个圆,难道需要一个一个圆去计算圆周坐标?不需要,我们可以先将坐标系原点移到左上角圆心所在的位置,按照前面提到的在原点画圆的最简单方式画一个圆,然后再将坐标系移到下一个圆心,然后继续,每个圆其实都是原点与圆心重合的画出的,没有比这更简单了。

OpenGL 支持移动坐标系的函数是 glTranslate* ,只有 glTranslatef,glTranslated 两个版本。

MSDN:

glTranslated, glTranslatef

The glTranslated and glTranslatef functions multiply the current matrix by a translation matrix.

void glTranslated( GLdouble x, GLdouble y, GLdouble z );

void glTranslatef( GLfloat x, GLfloat y, GLfloat z );

Parameters

x, y, z The x, y, and z coordinates of a translation vector.

见下例:

//OpenGL 初始化开始

void SceneInit (int w ,int h )

{

glClearColor (0.0, 0.0, 0.0, 0.0);

}

void DrawCircle ()

{

GLint iCirclePoints = 50;

glBegin (GL_POLYGON );

for (int i = 0; i < 50; ++i )

{

double dAngle = 2 * PI * i / iCirclePoints ;

glVertex3f (cos (dAngle )/2, sin (dAngle )/2, 0.0);

}

glEnd ();

}

// 这里进行所有的绘图工作

void SceneShow (GLvoid )

{

glClear (GL_COLOR_BUFFER_BIT ); // 清空颜色缓冲区

glColor4f (1.0, 1.0, 1.0, 1.0);

glTranslatef (-0.5, 0.5, 0.0);

DrawCircle ();

glTranslatef (0.5, -0.5, 0.0);

glTranslatef (0.5, 0.5, 0.0);

DrawCircle ();

glTranslatef (-0.5, -0.5, 0.0);

glTranslatef (0.5, -0.5, 0.0);

DrawCircle ();

glTranslatef (-0.5, 0.5, 0.0);

glTranslatef (-0.5, -0.5, 0.0);

DrawCircle ();

glTranslatef (0.5, 0.5, 0.0);

glFlush ();

}

此例就实现了前面提及的 4 个圆,特别注意的是, DrawCircle 函数重来都没有变过,只关心兢兢业业的画自己相对于原点的一个圆而已,移动得是原点(即整个坐标系)。此处,首先将原点坐标移到左上,然后画一个圆,然后将坐标移回了原来的中心位置,作为还原,接着不过反复此过程。效果如附图 4 。暂时没有给全部的源代码,因为此处还有可以修正的地方,上面我还原移动前的坐标是通过自己计算原来相反的方向手动还原的,这样在多次移动后会相当麻烦,所以 OpenGL 提供了保存原有矩阵坐标体系的函数。

MSDN:

glPushMatrix, glPopMatrix The glPushMatrix and glPopMatrix functions push and pop the current matrix stack.

void glPushMatrix( void );

void glPopMatrix( void );

使用方法就如一般的堆栈的使用,不过操作对象是当前的矩阵坐标体系。上例可以改成如下形式。

// 这里进行所有的绘图工作

void SceneShow (GLvoid )

{

glClear (GL_COLOR_BUFFER_BIT ); // 清空颜色缓冲区

glColor4f (1.0, 1.0, 1.0, 1.0);

glPushMatrix ();

glTranslatef (-0.5, 0.5, 0.0);

DrawCircle ();

glPopMatrix ();

glPushMatrix ();

glTranslatef (0.5, 0.5, 0.0);

DrawCircle ();

glPopMatrix ();

glPushMatrix ();

glTranslatef (0.5, -0.5, 0.0);

DrawCircle ();

glPopMatrix ();

glPushMatrix ();

glTranslatef (-0.5, -0.5, 0.0);

DrawCircle ();

glPopMatrix ();

glFlush ();

}

虽然此例中实际的语句甚至增多了(仅在如此简单的例子中才会出现),但是哪怕这样的例子,使用 Push,PopMatrix 对也是有好处的,那就是我不用再去计算一个 glTranslate* 移动相反的移动了,要知道,在这么晚的深夜(凌晨?),给我增加一个这样额外的计算也是有可能出现计算错误的, Push,PopMatrix 就不用担心了。

完整源代码见我博客源代码的 2009-10-14/GLDrawFourCircle/ 下,查看源代码或者下载的方式见最后的说明。

2. 旋转

XO1 中,我就提供了一个旋转的矩形作为示例,提供给大家测试 Win32 OpenGL 的框架。此处正式隆重介绍其核心的函数。

那就是 glRotate*

MSDN

glRotated, glRotatef The glRotated and glRotatef functions multiply the current matrix by a rotation matrix.

void glRotated( GLdouble angle, GLdouble x, GLdouble y, GLdouble z );

void glRotatef( GLfloat angle, GLfloat x, GLfloat y, GLfloat z );

Parameters

angle The angle of rotation, in degrees.

x, y, z The x, y, and z coordinates of a vector, respectively.

此函数的大概意思就是用 x,y,z 来指定旋转的轴, angle 来指定旋转的角度, XO1 中原来的例子足够复杂,用了一大堆目前没有讲过的函数,甚至利用上了交换缓冲区来实现动画(其实必要性不大),用以作为旋转的例子再不够就没有别的例子够了。。。。。。。。在那个例子中,由于我是从 2D 角度来实现的,所以围绕着 Z 轴旋转了。将 z 参数设为了 1.0 ,这与大部分 2D 实现 z 0 的情况有所不同,只要理解了坐标体系和 glRotate* 函数也就好理解了。

3. 不用 glRotate 的旋转效果

呵呵,突然想起来,我可以将前面例子中的很酷的圆狂旋转。。。。给大家看看圆旋转的效果,我甚至都不需要 glRotate 。加上此例还是比较典型的耍酷。 -_-! 其实, glTranslate 也好, glRotate 也好,看起来思想精妙,其实也就是为我们方便而设计的,很多时候并不是非用不可。别滥用了啊。

主要代码如下:

void DrawCircle ()

{

GLint iCirclePoints = 50;

glBegin (GL_POLYGON );

static double dAngleColor = 0.0;

for (int i = 0; i < 50; ++i )

{

glColor3f (1.0/i , 0.0, 0.0);

double dAngle = 2 * PI * i / iCirclePoints + dAngleColor ;

glVertex3f (cos (dAngle )/2, sin (dAngle )/2, 0.0);

}

dAngleColor += 0.02;

glEnd ();

}

如此便能形成类似球的转动效果,效果见附图 5 。四球同转,头晕目眩,就我看那效果,请不要随意减少球的数目到两个。 -_-!

完整源代码见我的博客源代码 2009-10-14/GLFourCircleAnimation/ 下,查看或下载方式见最后的说明。

六、 后记

本文可算是呕心沥血了,不计空格字符数达到了 1w3 ,光是汉字都有 6 千以上了,提供了 6 个完整的例子, N 多例子片段, 5 张图。本来不想写那么长的,可是 2D 基础嘛, OpenGL 相关的东西其实太多,很多 3D 的东西其实也都能算是 2D 的基础,(比如上述的移动,旋转)怎么讲都无法算个截止。但是其实还是有很多可以算作 2D 知识的东西没有讲,没有办法,本系列怎么说也无法成为一个完备的教程,做成像《 OpenGL 编程指南》一样整个的成一套体系,并且因为国内大部分人学习计算机 3D 图形绘制会学习 D3D 而不是 OpenGL ,所以受众有限。但是本人最奢求的愿望也不过是在写作中学习,并总结一些经验,并给大家提供一些聊以参考的资料或者例子罢了,当大家学习 OpenGL 时,能偶尔搜索到此文,然后觉得其中的一些例子有用,本人心愿足矣。

七、 参考资料

1. OpenGL Reference Manual 》, OpenGL 参考手册

2. OpenGL 编程指南》(《 OpenGL Programming Guide 》), Dave Shreiner Mason Woo Jackie Neider Tom Davis 著,徐波译,机械工业出版社

3. Nehe OpenGL Tutorials 》, Nehe 著,在 http://nehe.gamedev.net/ 上可以找到教程及相关的代码下载,(有 PDF 版本教程下载) Nehe 自己还做了一个面向对象的框架,作为演示程序来说,这样的框架非常合适。也有 中文版 ,各取所需吧。

4. OpenGL 入门学习》 eastcowboy 著,这是我在网上找到的一个比较好的教程,较为完善,而且非常通俗。这是第一篇的地址: http://bbs.pfan.cn/post-184355.html

八、 OpenGL 系列其他文章

1. Win32 OpenGL 编程( 1 Win32 下的 OpenGL 编程必须步

2. Win32 OpenGL 编程 (2) 寻找缺失的 OpenGL 函数

3. Win32 OpenGL 编程 (3) 基本图元(点,直线,多边形)的绘制

九、 完整源代码查看或下载说明

由于篇幅限制,本文一般仅贴出代码的主要关心的部分,代码带工程(或者 makefile )完整版(如果有的话)都能用 Mercurial Google Code 中下载。文章以博文发表的日期分目录存放,请直接使用 Mercurial 克隆下库:

https://blog-sample-code.jtianling.googlecode.com/hg/

Mercurial 使用方法见《 分布式的,新一代版本控制系统 Mercurial 的介绍及简要入门

要是仅仅想浏览全部代码也可以直接到 google code 上去看,在下面的地址:

http://code.google.com/p/jtianling/source/browse?repo=blog-sample-code

十、 附图

1. 附图 1 ,矩形上下颜色渐变

附图2,三角函数入门-_-!

附图3,一个圆渐变成球了(扭曲?)

附图4,四个圆

附图5,四球同转

write by 九天雁翎 (JTianLing) -- blog.csdn.net/vagrxie

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics