《OpenGL编程基础》第三章笔记2

第三章,另一半简单讲述了opengl的工作模式,方法。


显示列表:
书中解释,可以将显示列表看作一种类型的图形文件,在需要的时候调用该文件进行绘制。我觉得,把显示列表理解成理解成“opengl的特殊代码块”更好些。我们就是在显示列表中码好田,需要时候调用即可。当然,调用时有opengl规定的方式去调用,并不像普通函数那样使用。
显示列表的使用步骤:
1 创建/命名显示列表
2添加命令
3关闭显示列表
4调用显示列表
示例代码田:
# define LIST_NAME 1  //定义一个显示列表的名字。
glNewList(LIST_NAME, GL_COMPILE); //创建/命名显示列表。
                                  //显示列表的“名字”是 GLuint类型。
                                  //第二个参数mode。表示显示列表是否在创建时就显示。GL_COMPILE_AND_EXCUTE表示创建立即显示。
 glPushAttrib(GL_CURRENT_BIT); //添加命令:保存当前属性?需要调查一下,这个函数和参数值。。 
 glColor3f(1.0, 0.0, 0.0); //添加命令:红色 
 glRecf(-1.0, -1.0, 1.0, 1.0); //添加命令:方形
 glPopAttrib(); //添加命令:回复修改前的属性?
glEndList(); //关闭显示列表
//...
glCallList(LIST_NAME); //调用显示列表,参数是显示列表的名字。

我觉得,显示列表的一个作用是提供了间接的面向对象的方法。显示列表支持内部调用,即可以在添加命令的部分中加入glCallList()函数。于是,可以定义不同的显示模块,然后拼出一盘大拌菜来。如果您有才,您可以让地里长出对象来(,,,如果你单身的话 :P)。


拾取模式:
当你鼠标在窗口中选择了某个东西,你想让opengl反应一下,那么你需要使用拾取模式。
以下是通过鼠标获取“命中数据”的关键代码。命中数据,简单的说,就是你用鼠标点到了啥。
void mouse(int button, int state, int x, int y)
{
   GLuint selectBuf[SIZE];
   GLint hits;
   GLint viewport[4];


   if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
   {
      glGetIntegerv (GL_VIEWPORT, viewport);       //获得当前的视点


      glSelectBuffer (SIZE, selectBuf);    //将拾取的数据存在大小为SIZE的selectBuf中
      glRenderMode(GL_SELECT);         //开始拾取模式。在使用glRenderMode(GL_SELECT)前,必须先确定glSelectBuffer()


      glInitNames();     //之前的selectBuf被称作名称堆栈,拾取模式需要初始化该堆栈。
      glPushName(0);  //拾取模式不允许在空堆栈中加载“名称”(glLoadName)。所以先push一个不会使用的名称,比如我不用0,那就push个0进去。


      glMatrixMode (GL_PROJECTION);  //选择GL_PROJECTION模式
      glPushMatrix ();     //保存当前状态
      glLoadIdentity ();   //单位化当前矩阵?
      /*  在viewport中,建立一个以鼠标为中心,5x5像素的区域。	*/
      gluPickMatrix ((GLdouble) x, (GLdouble) (viewport[3] - y),
                  5.0, 5.0, viewport);
      gluOrtho2D (-2.0, 2.0, -2.0, 2.0);  //设置与初始化时相同的正交投影
      drawObjects(GL_SELECT);             //在5X5区域中重新绘制需要的图像。拾取需要重新绘制图像,opengl以此计算哪些对象的名称被选中。
                                       //这是一个自定义的函数
      glMatrixMode (GL_PROJECTION);
      glPopMatrix (); //还原GL_PROJECT状态
      glFlush(); //重绘
      hits = glRenderMode (GL_RENDER); //退出拾取模式,回复渲染模式。函数返回值是命中信息的个数。所有命中信息存在selectBuf中
      processHits (hits, selectBuf); //处理所有命中信息(selectBuf)。这是一个自定义的函数
      glutPostRedisplay(); //如果处理命中信息时改变了绘制状态,那么当前的窗口需要重新绘制。
   }
}

再来看看drawObjecs()和processHits()函数,这两个都是我们自定义的函数。不是opengl的接口,我们可以替换成其他任何函数,来完成类似的功能。
void drawObjects(GLenum mode)
{
	if(mode == GL_SELECT) {
            glLoadName(1);       //加载名称‘1’
        }
        glColor3f(1.0, 0.0, 0.0);
        glRectf(-0.5, -0.5, 1.0, 1.0); //名称‘1’所属的图元。
        
        if(mode == GL_SELECT) {
            glLoadName(2);       //加载名称‘2’
        }
        glColor3f(0.0, 0.0, 1.0);
        glRectf(-1.0, -1.0, 0.5, 0.5); //名称‘2’所属的图元。
}


void processHits (GLint hits, GLuint buffer[])
{
   unsigned int i, j;
   GLint names, *ptr;


   printf ("hits = %d\n", hits);      //有多少个命中
   ptr = (GLint *) buffer;
   for (i = 0; i < hits; i++) {	/*  for each hit  */
      names = *ptr;
	  ptr+=3;        //书中解释是跳过名称和深度值,没有解释深度值是什么。
      for (j = 0; j < names; j++) { /*  处理当前hit中的所有名称*/
         if(*ptr==1) printf ("red rectangle\n");
         else printf ("blue rectangle\n");
         ptr++;          //下一个名称
      }
      printf ("\n");
   }
}

从processHit中可以看出名称堆栈的大致结构:

| (第一个hit。当前hit中,命中的名称N个)N | depth | depth | name1 | name2 | ...| nameN | (第二个hit。当前hit中,命中的名称N1个)N1| depth | depth | name1 | name2 | ...| nameN1 |以此类推

其中,每一个| XXX |表示一个GLuint。

最近犯懒,好几天没更新笔记,哎,体现我深刻的劣根性啊。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值