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

OpenInventor/Coin3D 学习指南 Coin3D是一个功能强大的开源3D可视化库,与OpenInventor兼容。它提供了丰富的类和功能,可用于构建复杂的3D场景图、处理用户交互、集成到不同的窗口系统中,并通过Qt的Quarter库与2D用户界面实现无缝集成。 阅读详情

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

      

 

 

NeHe教程在这节课中向我们介绍了如何创建镜面显示效果,它使用剪裁平面,蒙板缓存等OpenGL中一些高级的技巧。

 

OpenInventor中已经提供了剪裁面节点SoClipPlane但蒙板缓存目前还没有直接支持,所以我们只能通过调用OpenGL的方式来实现蒙板缓存。这篇教程所讲述的技术比较高级,读者应该首先了解清楚蒙板缓存的功能。下面我们仍然在代码中介绍这些技术。

 

 

首先定义一些程序中使用的全局变量:

SoTranslation*              g_pOffsetTrans = NULL;

SoTranslation*              g_pHeightTrans = NULL;

SoRotation*                 g_pXRotation = NULL;

SoRotation*                 g_pYRotation = NULL;

 

//下面这些变量的含义和NeHe教程中的含义相同

float         xrot     =  0.0f ;                         // X Rotation

float         yrot     =  0.0f ;                         // Y Rotation

float         xrotspeed =  0.0f ;                         // X Rotation Speed

float         yrotspeed =  0.0f ;                         // Y Rotation Speed

float         zoom     = -7.0f ;                         // Depth Into The Screen

float         height        =  2.0f ;                    // Height Of Ball From Floor

 

下面的函数用来创建一个简单的地板场景

SoSeparator* BuildFloor(void)

{

     SoSeparator *pFloorSep = new SoSeparator;

 

     SoMaterial *pMaterial = new SoMaterial;

     pMaterial->diffuseColor.setValue(1,1,1);

     pMaterial->transparency = 0.3;

     pFloorSep->addChild(pMaterial);

 

     SoTexture2 *pTexture = new SoTexture2;

     pTexture->filename.setValue("../Data/Envwall.PNG");

     pTexture->model = SoTexture2::DECAL;

     pFloorSep->addChild(pTexture);

 

     SoCoordinate3 *pCoord = new SoCoordinate3;

     pCoord->point.set1Value(0,-2.0, 0.0, 2.0);

     pCoord->point.set1Value(1,2.0, 0.0, 2.0);

     pCoord->point.set1Value(2,2.0, 0.0,-2.0);

     pCoord->point.set1Value(3,-2.0, 0.0,-2.0);

     pFloorSep->addChild(pCoord);

 

     pFloorSep->addChild(new SoFaceSet);

 

     return pFloorSep;

}

 

这个函数用来创建球体场景,里面使用了前面第23课中使用的环境纹理映射,以及纹理的Alpha混合。

SoSeparator* BuildObject(void)

{

     SoSeparator *pSphereSep = new SoSeparator;

     SoTexture2 *pTexture = new SoTexture2;

     pTexture->filename.setValue("../Data/Ball.PNG");

     pSphereSep->addChild(pTexture);

 

     g_pHeightTrans = new SoTranslation;

     pSphereSep->addChild(g_pHeightTrans);

     g_pHeightTrans->translation.setValue(0,height,0);

 

     g_pXRotation = new SoRotation;

     pSphereSep->addChild(g_pXRotation);

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

 

     g_pYRotation = new SoRotation;

     pSphereSep->addChild(g_pYRotation);

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

 

     SoRotation *pFixXRotation = new SoRotation;

     pSphereSep->addChild(pFixXRotation);

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

 

     SoSphere *pSphere = new SoSphere;

     pSphere->radius = 0.35f ;

     pSphereSep->addChild(pSphere);

     ////////////////////////////////////////////////////////////////////////

     //创建环境纹理节点

     SoTextureCoordinateEnvironment *pTexPlane = new SoTextureCoordinateEnvironment;

     pSphereSep->addChild(pTexPlane);

    

     SoTexture2 *pEnvTexture = new SoTexture2;

     pEnvTexture->filename.setValue("../Data/Envroll.PNG");

     pSphereSep->addChild(pEnvTexture);

     //这里进行Alpha纹理混合操作

     SoCallback *pGlCallback = new SoCallback();

     pGlCallback->setCallback(GlCB, 0);

     pSphereSep->addChild(pGlCallback);

 

     pSphereSep->addChild(pSphere);

 

     pGlCallback = new SoCallback();

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

     pSphereSep->addChild(pGlCallback);

 

     return pSphereSep;

}

 

构建整个场景

void BuildScene(void)

{

     //定义键盘事件节点

     SoEventCallback* pEventCallback = new SoEventCallback;

     pEventCallback->addEventCallback(SoKeyboardEvent::getClassTypeId(),

KeyboardEventCB,g_pOivSceneRoot);

     g_pOivSceneRoot->addChild(pEventCallback);

     //////////////////////////////////////////////////////////////////////////////////

     SoComplexity *pComplexity = new SoComplexity;

     pComplexity->value = 1.0;

     pComplexity->textureQuality = 1.0;

     g_pOivSceneRoot->addChild(pComplexity);

 

     g_pOffsetTrans = new SoTranslation;

     g_pOivSceneRoot->addChild(g_pOffsetTrans);

 

     SoSeparator *pFloorSep = BuildFloor();

     SoSeparator *pObjectSep = BuildObject();

     SoCallback *pGlCallback = NULL;

 

     //下面的节点调用OpenGL的蒙板缓存操作

     SoSeparator *pStencilSep = new SoSeparator;

     g_pOivSceneRoot->addChild(pStencilSep);

     pGlCallback = new SoCallback();

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

     pStencilSep->addChild(pGlCallback);

     pStencilSep->addChild(pFloorSep);

     pGlCallback = new SoCallback();

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

     pStencilSep->addChild(pGlCallback);

 

     //创建剪裁平面节点

     SoClipPlane *pClipPlane = new SoClipPlane;

     pClipPlane->plane.setValue(SbPlane(SbVec 3f ( 0.0f , -1.0f , 0.0f ),SbVec 3f (0,0,0)));

     pStencilSep->addChild(pClipPlane);

 

     //定义反射矩阵

     SoScale *pInvert = new SoScale;

     pInvert->scaleFactor.setValue(1,-1,1);

     pStencilSep->addChild(pInvert);

     pStencilSep->addChild(pObjectSep);

    

//下面的节点调用OpenGL的蒙板缓存操作

     pGlCallback = new SoCallback();

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

     pStencilSep->addChild(pGlCallback);

     /////////////////////////////////////////////////////////////////////////////////////

     g_pOivSceneRoot->addChild(pFloorSep);

     g_pOivSceneRoot->addChild(pObjectSep);

     //////////////////////////////////////////////////////////////////////////////////////

     SoTimerSensor * texttimer = new SoTimerSensor(TimerSensorCB, NULL);

     texttimer->setInterval(0.001);

     texttimer->schedule();

}

下面是具体的OpenGL调用,其含义和NeHe教程中相同

void GlCB(void *data, SoAction *action)

{

     if (action->isOfType(SoGLRenderAction::getClassTypeId()))

     {

         switch((int)data)

         {

         case 0:

              glEnable(GL_BLEND);                   // Enable Blending

              glBlendFunc(GL_SRC_ALPHA, GL_ONE); // Set Blending Mode To Mix Based On SRC Alpha

              break;

         case 1:

              glDisable(GL_BLEND);             // Disable Blending

              break;

         case 2:

              glClearStencil(0);               // Clear The Stencil Buffer To 0

              glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

              glDepthFunc(GL_LEQUAL);          // The Type Of Depth Testing To Do

              glColorMask(0,0,0,0);            // Set Color Mask

              glEnable(GL_STENCIL_TEST);       // Enable Stencil Buffer For "marking" The Floor

              glStencilFunc(GL_ALWAYS, 1, 1);  // Always Passes, 1 Bit Plane, 1 As Mask

              glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);

              glDisable(GL_DEPTH_TEST);        // Disable Depth Testing

              break;

         case 3:

              glEnable(GL_DEPTH_TEST);         // Enable Depth Testing

              glColorMask(1,1,1,1);            // Set Color Mask to TRUE, TRUE, TRUE, TRUE

              glStencilFunc(GL_EQUAL, 1, 1);   // We Draw Only Where The Stencil Is 1

                                               // (I.E. Where The Floor Was Drawn)

              glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);   // Don't Change The Stencil Buffer

              break;

         case 4:

              glDisable(GL_STENCIL_TEST); // We Don't Need The Stencil Buffer Any More (Disable)

              break;

         }

     }

}

 

剩下的代码和以前的课程类似,我们就不在详细介绍了。

 

       现在编译运行我们程序,屏幕会显示出一个地板和一个球体。按上下左右箭头可以旋转球体。按下A/Z键,放大/缩小场景。按下PageDown/PageUP可以抬高/降低球体。效果和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 >

 
NeHe_OpenGL入门程讲解(教程 这是在网上搜到的OpenGL入门教程,挺不错的,就是NeHe的这个制作有点问题,不过能看的。还有我已经把其全部源码也上传了(名称是"NeHe_OpenGL入门程讲解(源码)"),希望想学的能从中获益。 立即下载

相关推荐

Open Inventor Open Inventor7

Open Inventor Open Inventor7

NeHe教程Qt实现——lesson10

NeHe 系列教程之十:在3D空间中漫游 英文教程地址:lesson10 本演示了从外部文件中加载数据构建3D模型的实例,代码基于第一。 首先是3D模型的数据结构定义: namespace { bool fp; // F pressed? const f...

chijiandao3197的博客 234

OpenGLnehe教程第一学习笔记

nehe教程的第一主要讲了OpenGL程序的创建。 它引用了最基本的gl.h、glu.h、glaux.h三个头文件。 包含了五个函数,分别是InitGL、ResizeGLScene、DrawGLScene、WinProc、winMain。 winMain函数是程序的入口,它负责创建windows窗口,将openGL程序引到该窗口(通过调用WinProc函数),并通过窗口句柄

lzh1590的博客 2697

Open Inventor练习-SoEventCallback,SoKeyboardEvent键盘事件(红绿灯)

SoEventCallback是Open Inventor用来管理事件的,SoKeyboardEvent是键盘事件,SO_KEY_PRESS_EVENT宏可以获得是键盘上哪个键被操作了,SoSwitch是一个节点切换开关节点,这里用来管理颜色信息。 代码如下 // 预定义COIN宏 #define COIN_DLL #define SOWIN_DLL // 加载COIN库文件 ...

huozheleisi 295

SoSelection SoEventCallback

/*------------------------------------------------------------ * The scene graph has 4 objects which may be * selected by picking with the left mouse button * (use shift key to extend the sel...

huozheleisi 161

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的专栏 1492

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原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值