用OpenInventor實現的NeHe OpenGL教程-第二十六課

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(SbVec3f(1,0,0),xrot);

 

     g_pYRotation = new SoRotation;

     pSphereSep->addChild(g_pYRotation);

     g_pYRotation->rotation.setValue(SbVec3f(0,1,0),yrot);

 

     SoRotation *pFixXRotation = new SoRotation;

     pSphereSep->addChild(pFixXRotation);

     pFixXRotation->rotation.setValue(SbVec3f(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(SbVec3f(0.0f,-1.0f, 0.0f),SbVec3f(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: < [email protected] > < [email protected] >

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

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

 
發佈了55 篇原創文章 · 獲贊 15 · 訪問量 21萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章