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

OpenInventor程序设计——从入门到精通源代码2 阎锋欣等编写OpenInventor程序设计——从入门到精通的源代码,由于只能上传小于20M的文件,所以我将整个源代码分为2次上传的。分别命名为:OpenInventor_code1.rar OpenInventor_code2.rar 其中OpenInventor_code1.rar包含第2章到第9章的代码示例; OpenInventor_code2.rar为第10章到15章的代码以及一些说明文档,解压后请查看文件:“光盘使用说明.doc”。 立即下载
 

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

 

      

 

这节课我们将讨论使用纹理贴图的技术来显示文字。使用这种技术显示文字的好处在于程序的效果在任何机器上都是相同的。而我们前面讨论的显示文字的方法都是依赖于当前系统中所包含的字体,所以前面讨论的技术在不同的机器上有可能会有不同的显示效果。

 

使用纹理贴图来显示文字的原理很简单,首先需要制作一个包含所有需要显示的文字的图片,将这个图片作为纹理加载到内存中,然后根据要显示的文字,找到其所对应的纹理坐标,最后显示一个矩形平面,对平面的四个顶点赋值上纹理坐标,这样就完成了文字的显示。

 

 

       我们首先要仿照NeHe教程,创建一个旋转的“墙”场景。

SoSeparator* BuildWall(void)

{

     SoSeparator *pWallScene = new SoSeparator;

 

     //Z轴负方向,即屏幕向里方向移动5个单位,和NeHe教程相同。

     SoTranslation *pZTrans = new SoTranslation;

     pZTrans->translation.setValue( 0.0f , 0.0f ,- 5.0f );

     pWallScene->addChild(pZTrans);

 

     //Z轴旋转45

     SoRotation *pZRotation = new SoRotation;

     pZRotation->rotation.setValue(SbVec 3f (0,0,1),3.1415 / 4.0);

     pWallScene->addChild(pZRotation);

 

     //让物体同时绕x轴和y轴旋转,这样物体就象在一个点上旋转的钻石那样旋转

     SoRotor *pRotor = new SoRotor;

     pRotor->rotation.setValue(SbVec 3f (1,1,0),1);

     pRotor->speed = 0.1;

     pWallScene->addChild(pRotor);

     //加载纹理位图

     SoTexture2 *pBumpTexture = new SoTexture2;

     pBumpTexture->filename.setValue("../Data/Bumps.png");

     pBumpTexture->model = SoTexture2::DECAL;

     pWallScene->addChild(pBumpTexture);

     //定义墙的位置坐标数据

     float vecWallCoord[][3] = { { -100.0f , 100.0f , 0.0f },

                                     { 100.0f , 100.0f , 0.0f },

                                     { 100.0f , -100.0f , 0.0f },

                                     { -100.0f , -100.0f , 0.0f } };

     SoCoordinate3 *pWallCoords = new SoCoordinate3;

     pWallCoords->point.setValues(0,4,vecWallCoord);

     pWallScene->addChild(pWallCoords);

 

     SoFaceSet *pWallFaceSet = new SoFaceSet;

     pWallScene->addChild(pWallFaceSet);

     //旋转坐标系

     SoRotation *pRotation = new SoRotation;

     pRotation->rotation.setValue(SbVec 3f (1,1,0),3.1415 / 2.0);

     pWallScene->addChild(pRotation);

     //添加另外一个“墙”

     pWallScene->addChild(pWallFaceSet);

 

     return pWallScene;

}

 

下面的函数根据输入的字符串,使用纹理来创建字符串的场景,纹理坐标的计算方法和NeHe教程中相同。

SoSeparator* OivPrint(char *string,int set)

{

     if(lstrlen(string) <= 0)

         return NULL;

 

     float    cx,cy;

     SoCoordinate3 *pStringCoords = new SoCoordinate3;

     SoTextureCoordinate2 *pTexCoord = new SoTextureCoordinate2;

     for(int i = 0; i < lstrlen(string); i++)

     {

         pStringCoords->point.set1Value( i * 4 + 0, i * 16, 0, 0 );

         pStringCoords->point.set1Value( i * 4 + 1, (i + 1) * 16, 0, 0 );

         pStringCoords->point.set1Value( i * 4 + 2, (i + 1) * 16, 16, 0 );

         pStringCoords->point.set1Value( i * 4 + 3, i * 16, 16, 0 );

 

         cx = float((string[i] - 32 + 128 * set) % 16) / 16.0f ;

         cy = float((string[i] - 32 + 128 * set) / 16) / 16.0f ;

         pTexCoord->point.set1Value( i * 4 + 0,cx,1 - cy - 0.0625f );

         pTexCoord->point.set1Value( i * 4 + 1,cx + 0.0625f ,1 - cy - 0.0625f );

         pTexCoord->point.set1Value( i * 4 + 2,cx + 0.0625f ,1 - cy);

         pTexCoord->point.set1Value( i * 4 + 3,cx,1 - cy);

     }

 

     int iIndex = 0;

     SoIndexedFaceSet *pTextFaceSet = new SoIndexedFaceSet;

     for(int i = 0; i < lstrlen(string); i++)

     {

         pTextFaceSet->coordIndex.set1Value(iIndex,i * 4);

         pTextFaceSet->textureCoordIndex.set1Value(iIndex++,i * 4);

 

         pTextFaceSet->coordIndex.set1Value(iIndex,i * 4 + 1);

         pTextFaceSet->textureCoordIndex.set1Value(iIndex++,i * 4 + 1);

 

         pTextFaceSet->coordIndex.set1Value(iIndex,i * 4 + 2);

         pTextFaceSet->textureCoordIndex.set1Value(iIndex++,i * 4 + 2);

 

         pTextFaceSet->coordIndex.set1Value(iIndex,i * 4 + 3);

         pTextFaceSet->textureCoordIndex.set1Value(iIndex++,i * 4 + 3);

 

         pTextFaceSet->coordIndex.set1Value(iIndex,SO_END_FACE_INDEX);

         pTextFaceSet->textureCoordIndex.set1Value(iIndex++,-1);

     }

 

     SoSeparator *pStringScene = new SoSeparator;

     pStringScene->addChild(pStringCoords);

     pStringScene->addChild(pTexCoord);

     pStringScene->addChild(pTextFaceSet);

 

     return pStringScene;

}

 

下面的函数将创建三个运动的字符串,字符串运动轨迹是通过OpenInventor的数学引擎计算出来的。

SoSeparator* BuildFont(void)

{   

     SoSeparator *pFontScene = new SoSeparator;

 

     SoCallback *pGlCallback = new SoCallback();

     pGlCallback->setCallback(GlCB, 0);

     pFontScene->addChild(pGlCallback);

 

     SoTexture2 *pFontTexture = new SoTexture2;

     pFontTexture->filename.setValue("../Data/Font.png");

     pFontTexture->model = SoTexture2::MODULATE;

     pFontScene->addChild(pFontTexture);

 

     SoTimeCounter *pCnt1Counter = new SoTimeCounter;

     pCnt1Counter->max = 360;

     pCnt1Counter->step = 1;

     pCnt1Counter->frequency = .2;

     SoTimeCounter *pCnt2Counter = new SoTimeCounter;

     pCnt2Counter->max = 360;

     pCnt2Counter->step = 1;

     pCnt2Counter->frequency = .4;

 

     SoSeparator *pText1Sep = OivPrint("NeHe",0);

     if(pText1Sep != NULL)

     {

         SoTranslation *pTransl1 = new SoTranslation;

         pText1Sep->insertChild(pTransl1,0);

         SoMaterial *pText1Material = new SoMaterial;

         pText1Material->diffuseColor.setValue(1.0,0.0,0.0);

         pText1Material->transparency = 0.1;

         pText1Sep->insertChild(pText1Material,0);

 

         SoCalculator *pText1PosCalc = new SoCalculator;

         pText1PosCalc->a.connectFrom(&pCnt1Counter->output);   

         pText1PosCalc->b.connectFrom(&pCnt2Counter->output);   

         pText1PosCalc->expression.set1Value(0, "ta = a * M_PI / 180");

         pText1PosCalc->expression.set1Value(1, "tb = 28 + 120 * cos(ta)");

         pText1PosCalc->expression.set1Value(2, "td = b * M_PI / 180");

         pText1PosCalc->expression.set1Value(3, "te = 23.5 + 100 * sin(td)");

         pText1PosCalc->expression.set1Value(4, "oA = vec 3f (tb,te,0)");

         pTransl1->translation.connectFrom(&pText1PosCalc->oA);

 

         SoCalculator *pText1ColorCalc = new SoCalculator;

         pText1ColorCalc->a.connectFrom(&pCnt1Counter->output);   

         pText1ColorCalc->b.connectFrom(&pCnt2Counter->output);   

         pText1ColorCalc->expression.set1Value(0, "ta = a * M_PI / 180");

         pText1ColorCalc->expression.set1Value(1, "tb = cos(ta)");

         pText1ColorCalc->expression.set1Value(2, "td = b * M_PI / 180");

         pText1ColorCalc->expression.set1Value(3, "te = sin(td)");

         pText1ColorCalc->expression.set1Value(4, "tf = 1.0 - 0.5 * cos(ta + td)"); 

         pText1ColorCalc->expression.set1Value(5, "oA = vec 3f (tb,te,tf)");

         pText1Material->diffuseColor.connectFrom(&pText1ColorCalc->oA);

 

         pFontScene->addChild(pText1Sep);

     }

 

     SoSeparator *pText2Sep = OivPrint("OpenGL",1);

     if(pText2Sep != NULL)

     {

         SoTranslation *pTransl2 = new SoTranslation;

         pText2Sep->insertChild(pTransl2,0);

         SoMaterial *pText2Material = new SoMaterial;

         pText2Material->diffuseColor.setValue(1.0,0.0,0.0);

         pText2Material->transparency = 0.1;

         pText2Sep->insertChild(pText2Material,0);

 

         SoCalculator *pText2PosCalc = new SoCalculator;

         pText2PosCalc->a.connectFrom(&pCnt1Counter->output);   

         pText2PosCalc->b.connectFrom(&pCnt2Counter->output);   

         pText2PosCalc->expression.set1Value(0, "ta = a * M_PI / 180");

         pText2PosCalc->expression.set1Value(1, "tb = 23.5 + 100 * sin(ta)");

         pText2PosCalc->expression.set1Value(2, "td = b * M_PI / 180");

         pText2PosCalc->expression.set1Value(3, "te = 28 + 100 * cos(td)");

         pText2PosCalc->expression.set1Value(4, "oA = vec 3f (te,tb,0)");

         pTransl2->translation.connectFrom(&pText2PosCalc->oA);

 

         SoCalculator *pText2ColorCalc = new SoCalculator;

         pText2ColorCalc->a.connectFrom(&pCnt1Counter->output);   

         pText2ColorCalc->b.connectFrom(&pCnt2Counter->output);   

         pText2ColorCalc->expression.set1Value(0, "ta = a * M_PI / 180");

         pText2ColorCalc->expression.set1Value(1, "tb = cos(ta)");

         pText2ColorCalc->expression.set1Value(2, "td = b * M_PI / 180");

         pText2ColorCalc->expression.set1Value(3, "te = sin(td)");

         pText2ColorCalc->expression.set1Value(4, "tf = 1.0 - 0.5 * cos(ta + td)"); 

         pText2ColorCalc->expression.set1Value(5, "oA = vec 3f (te,tf,tb)");

         pText2Material->diffuseColor.connectFrom(&pText2ColorCalc->oA);

 

         pFontScene->addChild(pText2Sep);

     }

 

     SoSeparator *pText3Sep = OivPrint("Giuseppe D'Agata",0);

     if(pText3Sep != NULL)

     {

         SoSeparator *pText34Sep = new SoSeparator;

 

         SoShuttle *pText3Shuttle = new SoShuttle;

         pText3Shuttle->translation0.setValue(-270,-180,0);

         pText3Shuttle->translation1.setValue(25,-180,0);

         pText3Shuttle->speed = 0.1;

         pText34Sep->addChild(pText3Shuttle);

         SoMaterial *pText3Material = new SoMaterial;

         pText3Material->diffuseColor.setValue(0.0,0.0,1.0);

         pText3Material->transparency = 0.1;

         pText34Sep->addChild(pText3Material);

         pText34Sep->addChild(pText3Sep);

 

         SoTranslation *pTransl4 = new SoTranslation;

         pTransl4->translation.setValue(1,0,0);

         pText34Sep->addChild(pTransl4);

         SoMaterial *pText4Material = new SoMaterial;

         pText4Material->diffuseColor.setValue(1.0,1.0,1.0);

         pText4Material->transparency = 0.1;

         pText34Sep->addChild(pText4Material);

         pText34Sep->addChild(pText3Sep);

 

         pFontScene->addChild(pText34Sep);

     }

 

     pGlCallback = new SoCallback();

     pGlCallback->setCallback(GlCB, (void *)1);

     pFontScene->addChild(pGlCallback);

    

     return pFontScene;

}

 

分别加载墙和文字场景。

void BuildScene(void)

{

     g_pOivSceneRoot->addChild(BuildWall());

     g_pOivSceneRoot->addChild(BuildFont());

}

 

 

       现在编译运行我们程序,屏幕上显示一个旋转的叶片。三个字符串以自己的轨迹不断运动。效果和NeHe第十七课是相同的。

 

本课的完整代码下载。(VC 2003 Coin2.5

 

 

后记

OpenInventor是一种基于OpenGL的面向对象的三维图形软件开发包。使用这个开发包,程序员可以快速、简洁地开发出各种类型的交互式三维图形软件。这里不对OpenInventor做详细的介绍,读者如果感兴趣,可以阅读我的blog中的这篇文章《OpenInventor 简介》。

 

NeHe教程是目前针对初学者来说最好的OpenGL教程,它可以带领读者由浅入深,循序渐进地掌握OpenGL编程技巧。到目前为止(200711月),NeHe教程一共有48节。我的计划是使用OpenInventor来实现所有48节课程同样的效果。目的是复习和巩固OpenGL的知识,同时与各位读者交流OpenInventor的使用技巧。

 

       因为篇幅的限制,我不会介绍NeHe教程中OpenGL的实现过程,因为NeHe的教程已经讲解的很清楚了,目前网络中也有NeHe的中文版本。我将使用VC 2003作为主要的编译器。程序框架采用和NeHe一样的Win32程序框架,不使用MFC。程序也可以在VC ExpressVC 2005/2008中编译。我采用的OpenInventor开发环境是Coin,这是一个免费开源的OpenInventor开发库。文章 OpenInventorCoin3D开发环境 介绍了如何在VC中使用Coin。我使用的Coin版本是2.5。读者可以到 www.coin3d.org 中免费下载。

 

       读者可以在遵循GNU协议的条件下自由使用、修改本文的代码。水平的原因,代码可能不是最优化的,我随时期待读者的指正和交流。转载请注明。谢谢。

我的联系方式:

E-mail: < openinventor@gmail.com > < openinventor@126.com >

Blog: < http://blog.csdn.net/RobinHao >

Site: < http://www.openinventor.cn >

Open inventor介绍与openGL区别 OpenGL Inventor 入门,提高必看. //**全系列相关Open Inventor请到我的空间下载**// 立即下载

相关推荐

利用OpenInventor(Coin3d)读取点云并显示

利用OpenInventor(Coin3d)读取点云并显示

OpenInventor实现NeHe OpenGL教程-第四十五

  NeHe教程在这节向我们介绍了OpenGL新的扩展“顶点缓存”(VBO),这种技术可以直接操作显卡,直接把顶点数据放置在显卡中的高速缓存中,极大的增加了OpenGL的绘制速度。对于使用Coin3D的用户来说,有一个非常好的消息,Coin3D内部自动支持VBO。当我们使用SoIndexedFaceSet节点显示三角面时,Coin在内部缺省情况下就是使用VBO来显示的。因此VBO技术我们已经

RobinHao的专栏 3975

OpenInventor实现NeHe OpenGL教程-第三十四

  NeHe教程在这节向我们介绍了如何从一个2D的灰度图创建地形。这节的内容比较简单,只是从一个2D灰度图中读取灰度数据,然后将灰度数据转换成高度数据,最后将这些数据显示出来就可以了。  首先定义一些全局变量,这些变量的含义和NeHe教程完全一致#define       MAP_SIZE  1024   // Size Of Our .RAW Height Map (NE

RobinHao的专栏 3738

webots自学笔记(七)通过定义顶点构件3D形状(IndexedFaceSet节点)

原创文章,来自“博客园,_阿龙clliu”http://www.cnblogs.com/clliu/,转载请注明原文章出处。 看到自己写的东西有人支持,也蛮欣慰的,所以顶着毕设的压力还是再更新一篇。 在webots中使用VRML语言建模,这个语言是比较老的了,确实没有现在的建模工具好用。这一次讲的是IndexedFaceSet节点,在VRML语言...

weixin_30535843的博客 485

OpenInventor实现NeHe OpenGL教程-第十

OpenInventor实现NeHe OpenGL教程-第十         这节我们将加载一个3D场景,并在这个场景中做自由漫游。读者将看到加载3D场景不是一件很难的事情,难点是3D场景的数据组织。不过这些是美工的事情,和我们程序员关系不大 ^_^ 。        在程序开始的部分我们新定义了一些变量,这些变量的作用和NeHe教程中定义的变量有相同的作用。SoTexture2*                 g_pTexture = NULL; //场景的纹理对象SoComplexity*  

Augusdi的专栏 1802

OpenInventor实现NeHe OpenGL教程-第一

OpenInventor实现NeHe OpenGL教程-第一        OpenInventor是一种基于OpenGL的面向对象的三维图形软件开发包。使用这个开发包,程序员可以快速、简洁地开发出各种类型的交互式三维图形软件。这里不对OpenInventor做详细的介绍,读者如果感兴趣,可以阅读我的blog中的这篇文章《OpenInventor 简介》。 NeHe教程是目前

RobinHao的专栏 5725

OpenInventor实现NeHe OpenGL教程-第三十

OpenInventor实现NeHe OpenGL教程-第三十         NeHe教程在这节介绍了碰撞检测。碰撞检测是一种比较复杂的技术。NeHe教程只是检测平面、球体、圆柱体等这些规则物体之间的碰撞检测。OpenInventor提供了任意形状物体之间的碰撞检测,当然这样的碰撞检测需要更多的计算时间。 碰撞检测的算法在NeHe教程中已经做了详尽的解释,我们就

RobinHao的专栏 3911

OpenInventor实现NeHe OpenGL教程-第十二

 用OpenInventor实现NeHe OpenGL教程-第十二         NeHe这节主要讨论OpenGL的显示列表功能。OpenGL的显示列表是加速OpenGL性能的一种重要的手段。但在OpenInventor中,我们根本就不需要关心是否使用显示列表,因为OpenInventor内部有缓存功能,而这个缓存功能就是使用显示列表来实现的。所以我们只需要实现程序逻辑

RobinHao的专栏 1912

OpenInventor实现NeHe OpenGL教程-第十六

 用OpenInventor实现NeHe OpenGL教程-第十六          这节我们将在前面讲述的第七节程的基础上,对场景增加上“雾 ”的效果。在OpenInventor中添加“雾 ”效果还是很容易的。OpenInventor提供了一个叫做SoEnvironment的节点类,通过这个节点类,我们就可以实现“雾 ”的效果。        下面的代码是在第

RobinHao的专栏 1493

OpenInventor实现NeHe OpenGL教程-第二十九

 用OpenInventor实现NeHe OpenGL教程-第二十九         NeHe教程在这节中介绍了如何把一块纹理贴到另一块纹理上(即多重纹理)。这节的内容不是很难,主要是如何读取raw数据格式文件,如何计算图像的透明度等。 OpenInventor对多重纹理直接提供支持,所以我们也可以利用多重纹理来实现相同的效果。具体的代码见BuildCube2

RobinHao的专栏 3505

OpenInventor实现NeHe OpenGL教程-第四十八

 NeHe教程在这节向我们介绍了轨迹球技术。轨迹球技术可以让用户使用鼠标直接旋转物体,这是所有交互式3D软件必须提供的最基本的功能。NeHe教程提供的方法是在其它人的基础上做了一些修改和优化。但他的方法仍然有一些小的错误,例如,在将鼠标2D坐标位置映射到3D球体上时,他没有考虑透视因素,因此可能会稍微有些误差,不过对于一般应用来说已经足够用了。        Open Invento

RobinHao的专栏 5525

OpenInventor实现NeHe OpenGL教程-第四十

<br />用OpenInventor实现NeHe OpenGL教程-第四十  NeHe教程在这节向我们介绍了如何模拟一根绳子的运动状态,简单的说,就是把绳子先离散化,把它想象成一个个紧密排列的点,每两个点之间有弹性约束。其实这就是简单的有限元思想。这节的内容和上节一样,主要是和物理、数学有关系,和图形图像的关系不大。我们的代码基本上和NeHe代码的原理类似,这里就不再详细说明了。  本的完整代码 下载。(VC 2003 + Coin2.5)  后记OpenInventor是一种基于OpenG

Augusdi的专栏 1440
上一篇: 用OpenInventor实现的NeHe OpenGL教程-第十六课
下一篇: 用OpenInventor实现的NeHe OpenGL教程-第十八课
RobinHao
博客等级 码龄25年 234粉丝 55原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值