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

  、   提要

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

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

   2、   颜色

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

  OpenGL Reference Manual:

  glClearColor - specy clear values for the color buffers

  C SPECIFICATION

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

  PARAMETERS

  red, green, blue, alpha

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

  DESCRIPTION

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

  glColor*

  Species a poer to an .gif' /> that contains red, green, blue, and (sometimes) alpha values.

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

  顺面简单说下颜色事实上计算机颜色表示是按人眼感知能力来分(不是实际自然颜色表示法)人眼有3种光感细胞分别能感受红(RED)绿(Green)蓝(Blue)人眼感知最终颜色由3种细胞综合得出般将其简称RGB再加上用于表示透明alpha合起来简称RGBA这就是glClearColor4个意思学过数字图像处理人应该还知道其实表示颜色方式还有很多但是其他颜色表示法在OpenGL中甚至PC中都不常用般都习惯于RGBA系统可能表示较为简单易于换算吧(真感兴趣可以参考Digital Image ProcessingBy Rafael C. GonzalezBTW说点题外话此书是原来我们数字图像处理课程教程当时用是第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( w, 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参数去指定背景和区别基本图元颜色了这么简单例子就留给大家自己去尝试了

   3、   着色模型

  这里有个问题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;
 
# FRAME_PER_SECOND (60)
# TIME_IN_FRAME (1000/FRAME_PER_SECOND)
# WIDTH (800)
# HEIGHT (600)
# SHADE_SPEED (0.005)
 
//OpenGL化开始
void SceneInit( w, 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);   // 清空颜色缓冲区
 
       // 默认方向时
       (gbShadeDir)
       {
              (gfTopGreen <= 1.0)
              {
                     IncreaseToTop;
              }
              
              {
                     gbShadeDir = false;
              }
       }
       
       {
              (gfTopGreen >= 0.0)
              {
                     DecreaseToTop;
              }
              
              {
                     gbShadeDir = true;
              }
       }
 
       DrawRect;
} 


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

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

   4、   坐标体系进阶知识

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

  1.      Windows GDI 坐标体系

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

  OpenGL Reference Manual:

  gluOrtho2D - a 2-D orthographic projection matrix

  C SPECIFICATION

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

  PARAMETERS

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

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

  DESCRIPTION

  gluOrtho2D s 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( w, 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)

# WIDTH (600)
# HEIGHT (600)
# PI (3.1415926535898)
//OpenGL化开始
void SceneInit( w, 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);
       GL iCirclePos = 50;
       glBegin(GL_LINE_LOOP);     
       for( i = 0; i < 50; i)
       {
              double dAngle = 2 * PI * i / iCirclePos;
              glVertex3f(cos(dAngle)/2, sin(dAngle)/2, 0.0);
       }
       glEnd;
 
       glFlush;
} 


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

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

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

       for( i = 0; i < 50; i)
       {
              glColor4f(1.0/i, 0, 0, 1.0);
              double dAngle = 2 * PI * i / iCirclePos;
              glVertex3f(cos(dAngle)/2, sin(dAngle)/2, 0.0);
}


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

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

//OpenGL化开始
void SceneInit( w, 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);
 
       // 下代码实际中可移到化中
       GL iCirclePos = 50;
       GL iRadius = WIDTH / 4;
       POINT ptCenter;
       ptCenter.x = WIDTH / 2;
       ptCenter.y = WIDTH / 2;
 
       glBegin(GL_POLYGON);
       for( i = 0; i < 50; i)
       {
              double dAngle = 2 * PI * i / iCirclePos;
              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时候有办法直接通过绝对坐标系去计算个圆球吗?-_-!另外假如更容易理解此例也可以看做先在坐标原点画了个圆然后通过移动圆心将整个圆移到了屏幕中心了

  不希望误导了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章

   5、   图元移动旋转

  1.      移动

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

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

Tags:  opengles 点击这里

延伸阅读

最新评论

发表评论