用OpenInventor实现的NeHe OpenGL教程-第十一课

用OpenInventor实现的NeHe OpenGL教程-第十一课
 
      
 
这节课我们将创建一个以正弦波方式飘动的旗帜。读者将看到实现这种效果并不像想象中那样的困难。至少说使用OpenInventor来实现还是比较容易的。^_^ 。
 
       和前面的程序一样,我们在程序开始的部分定义了一些全局变量,这些变量的作用和NeHe教程中定义的变量有相同的作用。
SoCoordinate3*              g_FlagCoords = NULL; // 旗帜的顶点坐标节点
SoRotation*                 g_pXRotation = NULL; // 绕X轴旋转的旋转节点
SoRotation*                 g_pYRotation = NULL; // 绕Y轴旋转的旋转节点
SoRotation*                 g_pZRotation = NULL; // 绕Z轴旋转的旋转节点
 
     和NeHe教程一样,我们使用points数组来存放网格各顶点独立的x,y,z坐标。这里网格由45×45点形成。
float     points[45][45][3];   
float     xrot = 0.0f; // 绕X轴旋转的角度
float     yrot = 0.0f; // 绕Y轴旋转的角度
float     zrot = 0.0f; // 绕Z轴旋转的角度
const float piover180 = 0.0174532925f;// 角度和弧度之间的转换因子
 
       在函数BuildScene中,我们编写如下的代码。
void BuildScene(void)
{
     在NeHe教程中,旗帜的前面使用框线方式显示,后面使用正常的填充方式显示。OpenInventor虽然也提供了使用框线方式显示的方法。但它只能同时设置前面和后面,不能分别单独设置。因此我们需要调用OpenGL函数。和前面的课程类似我们要向场景中增加一个SoCallback节点,这个节点的作用是可以在它的回调函数中调用OpenGL函数。
     SoCallback *pGlCallback = new SoCallback();
     pGlCallback->setCallback(GlCB, NULL); // 设置用户自定义回调函数GLCB
     g_pOivSceneRoot->addChild(pGlCallback);
 
     向场景中增加绕X,Y,Z轴旋转的旋转节点。
     g_pXRotation = new SoRotation;
     g_pOivSceneRoot->addChild(g_pXRotation);
 
     g_pYRotation = new SoRotation;
     g_pOivSceneRoot->addChild(g_pYRotation);
 
     g_pZRotation = new SoRotation;
     g_pOivSceneRoot->addChild(g_pZRotation);
    
向场景中增加纹理节点
     SoTexture2 *pTexture = new SoTexture2;
     pTexture->filename.setValue("../Data/Tim.png");
     pTexture->model = SoTexture2::DECAL;
     g_pOivSceneRoot->addChild(pTexture);
 
     定义旗帜的顶点数据和纹理数据,计算方法和NeHe教程相同
     g_FlagCoords = new SoCoordinate3;
     SoTextureCoordinate2 *FlagTexCoord = new SoTextureCoordinate2;
     for(int x = 0; x < 45; x++)
     {
         for(int y = 0; y < 45; y++)
         {
              points[x][y][0] = float((x / 5.0f) - 4.5f);
              points[x][y][1] = float((y / 5.0f) - 4.5f);
              points[x][y][2] = float(sin((((x / 5.0f) * 40.0f) / 360.0f) * 3.141592654 * 2.0f));
 
              g_FlagCoords->point.set1Value(  x * 45 + y,points[x][y][0],
points[x][y][1],
points[x][y][2]);
              FlagTexCoord->point.set1Value(x * 45 + y,float(x) / 45.0, float(y) / 45.0f);
         }
     }
     g_pOivSceneRoot->addChild(FlagTexCoord);
     g_pOivSceneRoot->addChild(g_FlagCoords);
 
     定义网隔节点,显示旗帜
     SoQuadMesh *pQuadMesh = new SoQuadMesh;
     pQuadMesh->verticesPerRow = 45;
     pQuadMesh->verticesPerColumn = 45;
     g_pOivSceneRoot->addChild(pQuadMesh);
 
     设置定时器来使旗帜飘动起来。读者可以参考第九节课程中的内容
     SoTimerSensor * Timer = new SoTimerSensor(TimerSensorCB, NULL);
     Timer->setInterval(0.001);
     Timer->schedule();
}
 
     下面我们编写SoCallback节点的响应函数,在OpenInventor遍历到SoCallback节点时会调用这个函数。在这个函数中,我们可以调用OpenGL命令,因为这时OpenGL Context是合法的。
void GlCB(void *data, SoAction *action)
{
     if (action->isOfType(SoGLRenderAction::getClassTypeId()))
     {
          glPolygonMode( GL_BACK, GL_FILL );// 背面采用填充方式
          glPolygonMode( GL_FRONT, GL_LINE );// 前面采用线框方式
     }
}
 
     下面的代码是定时器响应函数,定时器会每个一段时间调用一次这个函数,我们在这个函数中使旗帜运动起来。计算方法和NeHe教程中是相同的。
void TimerSensorCB(void * data, SoSensor *)
{
     static int wiggle_count = 0;        
     if( wiggle_count == 2 )
     {
         for( int y = 0; y < 45; y++ )
         {
              float hold = points[0][y][2];
              for( int x = 0; x < 44; x++)
              {
                   points[x][y][2] = points[x+1][y][2];
              }
              points[44][y][2] = hold;
         }
         for(int x = 0; x < 45; x++)
         {
              for(int y = 0; y < 45; y++)
                   g_FlagCoords->point.set1Value(  x * 45 + y,points[x][y][0],
points[x][y][1],
points[x][y][2]);
         }
         wiggle_count = 0;
     }
     wiggle_count++;
 
     g_pXRotation->rotation.setValue(SbVec3f(1,0,0),xrot);
     g_pYRotation->rotation.setValue(SbVec3f(0,1,0),yrot);
     g_pZRotation->rotation.setValue(SbVec3f(0,0,1),zrot);
     xrot += 0.3f * piover180;
     yrot += 0.2f * piover180;
     zrot += 0.4f * piover180;
 }  
 
       现在编译运行我们程序,屏幕上会显示一个不断旋转的飘动旗帜。效果和NeHe第十一课是相同的。
 
本课的完整代码 下载。(VC 2003 + Coin2.5)
 
 
 
后记
OpenInventor是一种基于OpenGL的面向对象的三维图形软件开发包。使用这个开发包,程序员可以快速、简洁地开发出各种类型的交互式三维图形软件。这里不对OpenInventor做详细的介绍,读者如果感兴趣,可以阅读我的blog中的这篇文章《 OpenInventor 简介》。
 
NeHe教程是目前针对初学者来说最好的OpenGL教程,它可以带领读者由浅入深,循序渐进地掌握OpenGL编程技巧。到目前为止(2007年11月),NeHe教程一共有48节。我的计划是使用OpenInventor来实现所有48节课程同样的效果。目的是复习和巩固OpenGL的知识,同时与各位读者交流OpenInventor的使用技巧。
 
       因为篇幅的限制,我不会介绍NeHe教程中OpenGL的实现过程,因为NeHe的教程已经讲解的很清楚了,目前网络中也有NeHe的中文版本。我将使用VC 2003作为主要的编译器。程序框架采用和NeHe一样的Win32程序框架,不使用MFC。程序也可以在VC Express,VC 2005/2008中编译。我采用的OpenInventor开发环境是Coin,这是一个免费开源的OpenInventor开发库。文章 《 OpenInventor-Coin3D开发环境》 介绍了如何在VC中使用Coin。我使用的Coin版本是2.5。读者可以到 www.coin3d.org 中免费下载。
 
       读者可以在遵循GNU协议的条件下自由使用、修改本文的代码。水平的原因,代码可能不是最优化的,我随时期待读者的指正和交流。转载请注明。谢谢。
我的联系方式:

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值