製做立體圖像(下):用Ogre渲染立體圖像

瞭解紅藍眼鏡原理以後剩下的事情就簡單了php

若是不清楚紅藍眼鏡原理,請先看上一篇:製做立體圖像(一):紅藍眼鏡原理html

 

另外你應該已經準備好了一副紅藍眼鏡(若是沒有請點擊這裏,而後關閉本頁面:)windows

如今戴上眼鏡,先看看咱們要作到的最終效果,一個旋轉的立體地球:app

(固然這個是靜止截圖)ide

 

先說說實現原理:函數

  1. 在座標原點建立一個圓球模型,並貼上地球紋理
  2. 在恰當位置建立兩個相機,並將兩個相機的結果渲染到左右紋理
  3. 繪製全屏四邊形,並應用立體材質,材質中經過shader對步驟2的紋理作紅綠藍混合,這個全屏四邊形就是咱們最終想要的結果

 

如下是詳細說明:post

  1. 建立三維模型
    這一步最重要的是製做一副高清的地球紋理圖,相似下面這樣

    不過圖片nasa早就爲你準備好了,你能夠到這裏下載任何你想要的(鬼子真的很強大)
    建立地球mesh的代碼也早有人幫你寫好了,詳見附帶文件中函數:
    //根據mesh名稱、半徑、經緯線條數建立對應的mesh
    void MyApplication::createSphere(const std::string& meshName, const float r, const int nRings, const int nSegments)

     

  2. 相機設置
    渲染到紋理,左眼使用主相機mCamera,需另建立右眼相機
    //左眼紋理
        Ogre::TexturePtr textureLeft = Ogre::TextureManager::getSingleton().createManual("textureLeft", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, mWindow->getWidth(), mWindow->getHeight(), 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET);
        Ogre::RenderTexture *targetLeft = textureLeft->getBuffer()->getRenderTarget();
        targetLeft->addViewport(mCamera);
    
        //右眼紋理
        Ogre::Camera *cameraRight = mSceneMgr->createCamera("cameraRight");
        ...同上... ;

    設置相機ui

    //設置相機位置、焦距
        const int x = 10, y = 150, z = 400;
        mCamera->setPosition(-x, y, z);
        cameraRight->setPosition(x, y, z);
        mCamera->lookAt(0, 0, 0);
        cameraRight->lookAt(0, 0, 0);
        mCamera->setFrustumOffset(x + x);
        mCamera->setFocalLength(Ogre::Math::Sqrt(x*x + y*y + z*z));
    setFrustumOffset setFocalLength 爲Ogre提供的用於立體渲染輔助方法,可調整視角偏移
    你能夠經過設置很遠的焦距和很小的fovy製做出看上去很遠很大的地球

  3. 全屏四邊形,最終的渲染效果
    這裏使用Ogre::Rectangle2D:
        mScreen = new Ogre::Rectangle2D(true);
        mScreen->setCorners(-1, 1, 1, -1, true); mScreen->setMaterial("stereo/fp");

    材質stereo/fp定義:(這裏使用cg腳本以支持direct3d+opengl,同時代碼也簡短)this

    fragment_program fpCG cg
    {
        source stereo.cg
        entry_point RedCyan
        profiles ps_2_0 arbfp1
    }
    
    material stereo/fpCG { technique { pass { fragment_program_ref fpCG{} texture_unit { texture textureLeft } texture_unit { texture textureRight } } } }

    材質腳本指定了左右相機渲染的textureLeft、textureRight兩幅紋理,並引用RedCyan着色器

    CG腳本,stereo.cg:spa

    void RedCyan(
        float2 uv : TEXCOORD0,
        out float4 color :COLOR, uniform sampler2D t1 : register(s0), uniform sampler2D t2 : register(s1)) { color = float4(tex2D(t1, uv) * float4(1, 0, 0, 0) + tex2D(t2, uv) * float4(0, 1, 1, 1)); }

    簡單的取左右紋理對應紅+綠藍份量便可
    注:這裏用的乘法後相加,若是直接先取左右紋理顏色,再提取rgb份量的形式,如:color = float4(c1.r, c2.g, c2.b, 1)會致使與direct3d不兼容,and i don't konw why:(


  4. 其它
    由於咱們使用全屏四邊形,在左右相機渲染紋理的時候須要隱藏,否則有可能將咱們的四邊形渲染到紋理中
    這裏須要實現RenderTargerListener接口,在渲染先後作顯隱控制:
        virtual void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt)
        {
            mScreen->setVisible(false);
        }
        virtual void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt)
        {
            mScreen->setVisible(true);
        }

    同時在createScene中註冊對應的listener:

        targetLeft->addListener(this);
        targetRight->addListener(this);
  5. 最後是錦上添花的一步:讓咱們的地球轉起來
    bool MyApplication::frameRenderingQueued(const Ogre::FrameEvent &evt)
    {
        mEarthNode->yaw(Ogre::Radian(evt.timeSinceLastFrame * 0.5));
        return true;
    }

     

    附程序代碼:

    #pragma once
    
    #include <vector>
    #include <fstream>
    #include <string>
    
    #include <Ogre/Ogre.h>
    #include <OIS/OIS.h>
    
    class MyApplication: public Ogre::RenderTargetListener, public Ogre::FrameListener, public OIS::KeyListener 
    {
    public:
        MyApplication(void){
            mSceneMgr = NULL;
            mRoot = NULL;
        }
    
        ~MyApplication(void){
            mInputManager->destroyInputObject(mKeyboard);
            mInputManager->destroyInputObject(mMouse);
            OIS::InputManager::destroyInputSystem(mInputManager);
            delete mRoot;
        }
    
        int startup();
    
    private:
        void createScene();
    
        virtual void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt)
        {
            mScreen->setVisible(false);
        }
    
        virtual void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt)
        {
            mScreen->setVisible(true);
        }
    
        Ogre::MovableObject* createSphere();
    
        void createSphere(const std::string& meshName, const float r, const int nRings = 16, const int nSegments = 16);
    
        bool frameStarted(const Ogre::FrameEvent& evt);
    
        bool frameEnded(const Ogre::FrameEvent& evt);
    
        bool frameRenderingQueued(const Ogre::FrameEvent &evt);
    
        bool keyPressed(const OIS::KeyEvent &e);
    
        bool keyReleased(const OIS::KeyEvent &e) { return true; }
    
        void _createAxis(const int lenth); //建立座標軸:  x red, y green, z blue
    
        void _loadResources(const char* resoureFile);
    
        void _createInput();
    
        void _showDebugOverlay(bool show);
    
        void _updateStats(void);
    
        void _keyPressedDefault(const OIS::KeyEvent &e);
    
        //默認鍵盤、鼠標導航
        bool _navigateDefault(const Ogre::FrameEvent& evt);
    
        Ogre::SceneManager* mSceneMgr;
        Ogre::RenderWindow* mWindow;
        Ogre::Camera* mCamera;
        Ogre::Root* mRoot;
        Ogre::SceneNode* mRootNode;        //根節點
    
        OIS::InputManager* mInputManager;
        OIS::Keyboard* mKeyboard;
        OIS::Mouse* mMouse;
    
        Ogre::SceneNode* mEarthNode;
        Ogre::Rectangle2D* mScreen;
    
        int mNumScreenShots;    //截圖順序號
    
        bool mStatsOn;
        Ogre::Overlay* mDebugOverlay;
    };
    MyApplication.h
    //易變動部分
    #include "MyApplication.h"
    
    void MyApplication::createScene()
    {
        mEarthNode = mRootNode->createChildSceneNode();
        mEarthNode->attachObject(createSphere());
    
        //左眼紋理
        Ogre::TexturePtr textureLeft = Ogre::TextureManager::getSingleton().createManual("textureLeft", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, mWindow->getWidth(), mWindow->getHeight(), 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET);
        Ogre::RenderTexture *targetLeft = textureLeft->getBuffer()->getRenderTarget();
        targetLeft->addViewport(mCamera);
    
        //右眼紋理
        Ogre::Camera *cameraRight = mSceneMgr->createCamera("cameraRight");
        cameraRight->setAspectRatio(Ogre::Real(mWindow->getWidth()) / Ogre::Real(mWindow->getHeight()));
        Ogre::TexturePtr textureRight = Ogre::TextureManager::getSingleton().createManual("textureRight", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, mWindow->getWidth(), mWindow->getHeight(), 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET);
        Ogre::RenderTexture *targetRight = textureRight->getBuffer()->getRenderTarget();
        targetRight->addViewport(cameraRight);
    
        //設置相機位置、焦距
        const int x = 10, y = 150, z = 400;
        mCamera->setPosition(-x, y, z);
        cameraRight->setPosition(x, y, z);
        mCamera->lookAt(0, 0, 0);
        cameraRight->lookAt(0, 0, 0);
        mCamera->setFrustumOffset(x + x);
        mCamera->setFocalLength(Ogre::Math::Sqrt(x*x + y*y + z*z));
    
        mScreen = new Ogre::Rectangle2D(true);
        mScreen->setCorners(-1, 1, 1, -1, true);
        mScreen->setMaterial("stereo/fpCG");
        mRootNode->attachObject(mScreen);
    
        targetLeft->addListener(this);
        targetRight->addListener(this);
    }
    
    bool MyApplication::keyPressed(const OIS::KeyEvent &e)
    {
        _keyPressedDefault(e);
    
    
        return true;
    }
    
    bool MyApplication::frameStarted(const Ogre::FrameEvent& evt)
    {
        //if(!_navigateDefault(evt)) return false;
        mKeyboard->capture();
        if(mKeyboard->isKeyDown(OIS::KC_ESCAPE)){
            return false;
        }
    
        return true;
    }
    
    bool MyApplication::frameEnded(const Ogre::FrameEvent& evt){
        _updateStats();
    
        return true;
    }
    
    bool MyApplication::frameRenderingQueued(const Ogre::FrameEvent &evt)
    {
        mEarthNode->yaw(Ogre::Radian(evt.timeSinceLastFrame * 0.5));
        return true;
    }
    
    Ogre::MovableObject* MyApplication::createSphere(){
        createSphere("mySphereMesh", 100, 100, 100);
        Ogre::Entity* sphereEntity = mSceneMgr->createEntity ("mySphereEntity", "mySphereMesh");
        sphereEntity->setMaterialName("Test/earth");
    
        return sphereEntity;
    }
    
    //根據mesh名稱、半徑、經緯線條數建立對應的mesh
    void MyApplication::createSphere(const std::string& meshName, const float r, const int nRings, const int nSegments)
    {
        Ogre::MeshPtr pSphere = Ogre::MeshManager::getSingleton().createManual(meshName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
        Ogre::SubMesh *pSphereVertex = pSphere->createSubMesh();
    
        Ogre::VertexData* vertexData = new Ogre::VertexData();
        pSphere->sharedVertexData = vertexData;
    
        // define the vertex format
        Ogre::VertexDeclaration* vertexDecl = vertexData->vertexDeclaration;
        size_t currOffset = 0;
        // positions
        vertexDecl->addElement(0, currOffset, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
        currOffset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
        //// DIFFUSE
        //vertexDecl->addElement(0, currOffset, VET_FLOAT3, Ogre::VES_DIFFUSE);
        //currOffset += VertexElement::getTypeSize(VET_FLOAT3);
        // normals
        vertexDecl->addElement(0, currOffset, Ogre::VET_FLOAT3, Ogre::VES_NORMAL);
        currOffset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
        //// two dimensional texture coordinates
        vertexDecl->addElement(0, currOffset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, 0);
        currOffset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2);
    
        // allocate the vertex buffer
        vertexData->vertexCount = (nRings + 1) * (nSegments+1);
        Ogre::HardwareVertexBufferSharedPtr vBuf = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(vertexDecl->getVertexSize(0), vertexData->vertexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
        Ogre::VertexBufferBinding* binding = vertexData->vertexBufferBinding;
        binding->setBinding(0, vBuf);
        float* pVertex = static_cast<float*>(vBuf->lock(Ogre::HardwareBuffer::HBL_DISCARD));
    
        // allocate index buffer
        pSphereVertex->indexData->indexCount = 6 * nRings * (nSegments + 1);
        pSphereVertex->indexData->indexBuffer = Ogre::HardwareBufferManager::getSingleton().createIndexBuffer(Ogre::HardwareIndexBuffer::IT_16BIT, pSphereVertex->indexData->indexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
        Ogre::HardwareIndexBufferSharedPtr iBuf = pSphereVertex->indexData->indexBuffer;
        unsigned short* pIndices = static_cast<unsigned short*>(iBuf->lock(Ogre::HardwareBuffer::HBL_DISCARD));
    
        float fDeltaRingAngle = float(Ogre::Math::PI / nRings);
        float fDeltaSegAngle = float(2 * Ogre::Math::PI / nSegments);
        unsigned short wVerticeIndex = 0 ;
    
        // Generate the group of rings for the sphere
        for( int ring = 0; ring <= nRings; ring++ ) {
            float r0 = r * sinf (ring * fDeltaRingAngle);
            float y0 = r * cosf (ring * fDeltaRingAngle);
    
            // Generate the group of segments for the current ring
            for(int seg = 0; seg <= nSegments; seg++) {
                float x0 = r0 * sinf(seg * fDeltaSegAngle);
                float z0 = r0 * cosf(seg * fDeltaSegAngle);
    
                // Add one vertex to the strip which makes up the sphere
                *pVertex++ = x0;
                *pVertex++ = y0;
                *pVertex++ = z0;
    
                Ogre::Vector3 vNormal = Ogre::Vector3(x0, y0, z0).normalisedCopy();
                *pVertex++ = vNormal.x;
                *pVertex++ = vNormal.y;
                *pVertex++ = vNormal.z;
    
                *pVertex++ = (float) seg / (float) nSegments;
                *pVertex++ = (float) ring / (float) nRings;
    
                if (ring != nRings) {
                    // each vertex (except the last) has six indices pointing to it
                    *pIndices++ = wVerticeIndex + nSegments + 1;
                    *pIndices++ = wVerticeIndex;               
                    *pIndices++ = wVerticeIndex + nSegments;
                    *pIndices++ = wVerticeIndex + nSegments + 1;
                    *pIndices++ = wVerticeIndex + 1;
                    *pIndices++ = wVerticeIndex;
                    wVerticeIndex ++;
                }
            }; // end for seg
        } // end for ring
    
        // Unlock
        vBuf->unlock();
        iBuf->unlock();
        // Generate face list
        pSphereVertex->useSharedVertices = true;
    
        // the original code was missing this line:
        pSphere->_setBounds( Ogre::AxisAlignedBox(Ogre::Vector3(-r, -r, -r), Ogre::Vector3(r, r, r) ), false );
        pSphere->_setBoundingSphereRadius(r);
        // this line makes clear the mesh is loaded (avoids memory leaks)
        pSphere->load();
    }
    MyApplication.cpp
    //系統不常變動部分實現
    #include "MyApplication.h"
    #include "windows.h"
    
    int main(int argc, char *argv[])
    {
        //設置當前工做目錄,用於文件關聯打開方式
        std::string file(argv[0]);
        SetCurrentDirectoryA(file.substr(0, file.find_last_of("\\")).c_str());
    
        MyApplication app;
        app.startup();
    }
    
    int MyApplication::startup()
    {
    
    #ifdef _DEBUG
        mRoot = new Ogre::Root("../plugins_d.cfg", "../ogre.cfg", "../Ogre.log");
    #else
        mRoot = new Ogre::Root("../plugins.cfg", "../ogre.cfg", "../Ogre.log");
    #endif
    
        if(!mRoot->showConfigDialog()){
            //if(!mRoot->showConfigDialog()){
            return -1;
        }
    
        mWindow = mRoot->initialise(true, "Ogre3D");
        mSceneMgr = mRoot->createSceneManager(Ogre::ST_EXTERIOR_CLOSE);
    
        mCamera = mSceneMgr->createCamera("camera");
        mCamera->setPosition(Ogre::Vector3(100, 200, 300));
        mCamera->lookAt(Ogre::Vector3(0, 0, 0));
        mCamera->setNearClipDistance(10); //default [100, 100 * 1000]
    
        Ogre::Viewport* viewport = mWindow->addViewport(mCamera);
        viewport->setBackgroundColour(Ogre::ColourValue(0.0, 0.0, 0.0));
        mCamera->setAspectRatio(Ogre::Real(viewport->getActualWidth())/Ogre::Real(viewport->getActualHeight()));
    
        mRootNode = mSceneMgr->getRootSceneNode();
    
        _loadResources("../resources_testStereo.cfg");
    
        createScene();
        _createAxis(100);
        _createInput();
    
        mDebugOverlay = Ogre::OverlayManager::getSingleton().getByName("Core/DebugOverlay");
        _showDebugOverlay(true);
    
        mRoot->addFrameListener(this);
    
        mRoot->startRendering();
        return 0;
    }
    
    void MyApplication::_createAxis(const int lenth)
    {
        Ogre::ManualObject *mo = mSceneMgr->createManualObject();
        mo->begin("BaseWhiteNoLighting", Ogre::RenderOperation::OT_LINE_LIST);
        mo->position(lenth, 0, 0);
        mo->colour(1.0, 0, 0);
        mo->position(0, 0, 0);
        mo->colour(1.0, 0, 0);
        mo->position(0, lenth, 0);
        mo->colour(0, 1.0, 0);
        mo->position(0, 0, 0);
        mo->colour(0, 1.0, 0);
        mo->position(0, 0, lenth);
        mo->colour(0, 0, 1.0);
        mo->position(0 , 0, 0);
        mo->colour(0, 0, 1.0);
        mo->end();
        mRootNode->attachObject(mo);
    }
    
    void MyApplication::_loadResources(const char* resourceFile)
    {
        Ogre::ConfigFile cf;
        cf.load(resourceFile);
    
        Ogre::ConfigFile::SectionIterator sectionIter = cf.getSectionIterator();
        Ogre::String sectionName, typeName, dataName;
        while(sectionIter.hasMoreElements()){
            sectionName = sectionIter.peekNextKey();
            Ogre::ConfigFile::SettingsMultiMap *settings = sectionIter.getNext();
            Ogre::ConfigFile::SettingsMultiMap::iterator i;
            for(i=settings->begin(); i!=settings->end(); i++){
                typeName =i->first;
                dataName = i->second;
    
                Ogre::ResourceGroupManager::getSingleton().addResourceLocation(dataName, typeName, sectionName);
            }
        }
    
        Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
    }
    
    void MyApplication::_updateStats(void)
    {
        static Ogre::String currFps = "Current FPS: ";
        static Ogre::String avgFps = "Average FPS: ";
        static Ogre::String bestFps = "Best FPS: ";
        static Ogre::String worstFps = "Worst FPS: ";
        static Ogre::String tris = "Triangle Count: ";
        static Ogre::String batches = "Batch Count: ";
    
        // update stats when necessary
        try {
            Ogre::OverlayElement* guiAvg = Ogre::OverlayManager::getSingleton().getOverlayElement("Core/AverageFps");
            Ogre::OverlayElement* guiCurr = Ogre::OverlayManager::getSingleton().getOverlayElement("Core/CurrFps");
            Ogre::OverlayElement* guiBest = Ogre::OverlayManager::getSingleton().getOverlayElement("Core/BestFps");
            Ogre::OverlayElement* guiWorst = Ogre::OverlayManager::getSingleton().getOverlayElement("Core/WorstFps");
    
            const Ogre::RenderTarget::FrameStats& stats = mWindow->getStatistics();
            guiAvg->setCaption(avgFps + Ogre::StringConverter::toString(stats.avgFPS));
            guiCurr->setCaption(currFps + Ogre::StringConverter::toString(stats.lastFPS));
            guiBest->setCaption(bestFps + Ogre::StringConverter::toString(stats.bestFPS)
                +" "+Ogre::StringConverter::toString(stats.bestFrameTime)+" ms");
            guiWorst->setCaption(worstFps + Ogre::StringConverter::toString(stats.worstFPS)
                +" "+Ogre::StringConverter::toString(stats.worstFrameTime)+" ms");
    
            Ogre::OverlayElement* guiTris = Ogre::OverlayManager::getSingleton().getOverlayElement("Core/NumTris");
            guiTris->setCaption(tris + Ogre::StringConverter::toString(std::max((int)stats.triangleCount, 230) - 230));
    
            Ogre::OverlayElement* guiBatches = Ogre::OverlayManager::getSingleton().getOverlayElement("Core/NumBatches");
            guiBatches->setCaption(batches + Ogre::StringConverter::toString((int)stats.batchCount - 10));
    
            //Ogre::OverlayElement* guiDbg = Ogre::OverlayManager::getSingleton().getOverlayElement("Core/DebugText");
            //guiDbg->setCaption("mDebugText");
        }
        catch(...) { /* ignore */ }
    }
    
    
    void MyApplication::_showDebugOverlay(bool show)
    {
        if (mDebugOverlay)
        {
            if (show)
                mDebugOverlay->show();
            else
                mDebugOverlay->hide();
        }
    }
    
    void MyApplication::_createInput()
    {
        OIS::ParamList parameters;
        unsigned int windowHandle = 0;
        std::ostringstream windowHandleString;
    
        mWindow->getCustomAttribute("WINDOW", &windowHandle);
        windowHandleString<<windowHandle;
        parameters.insert(std::make_pair("WINDOW", windowHandleString.str()));
    
        mInputManager = OIS::InputManager::createInputSystem(parameters);
        mKeyboard = static_cast<OIS::Keyboard*>(mInputManager->createInputObject(OIS::OISKeyboard, true));
        mMouse = static_cast<OIS::Mouse*>(mInputManager->createInputObject(OIS::OISMouse, true));
        mKeyboard->setEventCallback(this);
    }
    
    
    void MyApplication::_keyPressedDefault(const OIS::KeyEvent &e)
    {
        if(e.key == OIS::KC_SYSRQ)
        {
            std::ostringstream ss;
            ss << "screenshot_" << ++mNumScreenShots << ".png";
            mWindow->writeContentsToFile(ss.str());
        }
        else if(e.key == OIS::KC_G)
        {
            mStatsOn = !mStatsOn;
            _showDebugOverlay(mStatsOn);
        }
        else if(e.key == OIS::KC_R)
        {
            if(mCamera->getPolygonMode() == Ogre::PM_SOLID)
            {
                mCamera->setPolygonMode(Ogre::PM_WIREFRAME);
            }
            else
            {
                mCamera->setPolygonMode(Ogre::PM_SOLID);
            }
        }
    }
    
    //默認鍵盤、鼠標導航
    bool MyApplication::_navigateDefault(const Ogre::FrameEvent& evt)
    {
        mKeyboard->capture();
        if(mKeyboard->isKeyDown(OIS::KC_ESCAPE)){
            return false;
        }
    
        Ogre::Vector3 translate(0, 0, 0);
        if(mKeyboard->isKeyDown(OIS::KC_W)){
            translate +=Ogre::Vector3(0, 0, -1);
        }
        if(mKeyboard->isKeyDown(OIS::KC_S)){
            translate += Ogre::Vector3(0, 0, 1);
        }
        if(mKeyboard->isKeyDown(OIS::KC_A)){
            translate += Ogre::Vector3(-1, 0, 0);
        }
        if(mKeyboard->isKeyDown(OIS::KC_D)){
            translate += Ogre::Vector3(1, 0, 0);
        }
        if(mKeyboard->isKeyDown(OIS::KC_Q)){
            translate += mCamera->getOrientation().Inverse() * Ogre::Vector3(0, 1, 0);
        }
        if(mKeyboard->isKeyDown(OIS::KC_E)){
            translate += mCamera->getOrientation().Inverse() *  Ogre::Vector3(0, -1, 0);
        }
    
        Ogre::Real speed = mCamera->getPosition().y;
        if(speed < 5) speed =5;
        mCamera->moveRelative(translate * evt.timeSinceLastFrame *  speed);
    
    
        if(mKeyboard->isKeyDown(OIS::KC_UP)){
            mCamera->pitch(Ogre::Radian(-evt.timeSinceLastFrame));
        }else if(mKeyboard->isKeyDown(OIS::KC_DOWN)){
            mCamera->pitch(Ogre::Radian(evt.timeSinceLastFrame));
        }
        if(mKeyboard->isKeyDown(OIS::KC_LEFT)){
            mCamera->yaw(Ogre::Radian(evt.timeSinceLastFrame));
        }
        if(mKeyboard->isKeyDown(OIS::KC_RIGHT)){
            mCamera->yaw(Ogre::Radian(-evt.timeSinceLastFrame * 0.3f));
        }
    
        mMouse->capture();
        Ogre::Real rotX = Ogre::Math::Clamp(mMouse->getMouseState().X.rel * evt.timeSinceLastFrame * -1, -0.1f, 0.1f);
        Ogre::Real rotY = Ogre::Math::Clamp(mMouse->getMouseState().Y.rel * evt.timeSinceLastFrame * -1, -0.1f, 0.1f);
    
        mCamera->yaw(Ogre::Radian(rotX));
        mCamera->pitch(Ogre::Radian(rotY));
    
        return true;
    }
    MyApplicationConst.cpp

     

  附:代碼使用Test/earth原始材質,若是在nasa下載個高清的圖片叫earth.jpg,須要指定對應的材質:

material Test/earth{ technique { pass {           texture_unit           {             texture earth.jpg           }} } }

相關文章
相關標籤/搜索