`
huozheleisi
  • 浏览: 1237437 次
文章分类
社区版块
存档分类
最新评论

用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第十一课是相同的。
后记
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开发库。文章 《OpenInventorCoin3D开发环境》 介绍了如何在VC中使用Coin。我使用的Coin版本是2.5。读者可以到 www.coin3d.org 中免费下载。
读者可以在遵循GNU协议的条件下自由使用、修改本文的代码。水平的原因,代码可能不是最优化的,我随时期待读者的指正和交流。转载请注明。谢谢。
我的联系方式:

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics