将Ogre场景透明渲染到桌面上

 可能你很想在桌面上实现一个3D物体渲染到桌面上,但又希望背景是透明的。这样就实现了像Office助手这样很酷的机器人交互。

OGRE是开源的3D图形引擎,使用这个引擎的亲一定很多,所以就谈谈利用它来如果实现。

实现步骤:

1.创建一个带WS_EX_LAYERED属性风格的窗口;

2.创建一个纹理,将场景内容渲染到这个纹理上;(纹理像素格式设为:ARGB,视口的背景色,设置为透明)

3.读取纹理的像素数据,生成32位4通道的BITMAP位图;

4.将位图利用UpdateLayeredWindow函数,更新窗口;

3~4步,放在渲染循环中。


我利用ParticleUniverse和Direct3D9两个插件,做了个粒子的demo如下:

可以发现渲染的帧率很低,性能瓶颈主要在从纹理取得数据生成位图,有空了再优化下。UpdateLayeredWindow本身是很快的。



下面直接贴代码了:(性能瓶颈的地方飘红)

#ifndef __VISION_APP_h_
#define __VISION_APP_h_

#include <OgreCamera.h>
#include <OgreEntity.h>
#include <OgreLogManager.h>
#include <OgreRoot.h>
#include <OgreViewport.h>
#include <OgreSceneManager.h>
#include <OgreRenderWindow.h>
#include <OgreConfigFile.h>
#include <OgreTexture.h>

#include <OISEvents.h>
#include <OISInputManager.h>
#include <OISKeyboard.h>
#include <OISMouse.h>

#include <SdkTrays.h>
#include <SdkCameraMan.h>

class App : public Ogre::FrameListener, 
    public Ogre::WindowEventListener, public OIS::KeyListener,
    public OIS::MouseListener, OgreBites::SdkTrayListener
{
public:
    App(void);
    virtual ~App(void);

    virtual void go(void);

protected:
    virtual bool setup();
    virtual bool configure(void);
    virtual void chooseSceneManager(void);
    virtual void createCamera(void);
    virtual void createFrameListener(void);
    virtual void createScene(void);
    virtual void destroyScene(void);
    virtual void createViewports(void);
    virtual void setupResources(void);
    virtual void createResourceListener(void);
    virtual void loadResources(void);

    // Ogre::FrameListener
    virtual bool frameRenderingQueued(const Ogre::FrameEvent& evt);

    // OIS::KeyListener
    virtual bool keyPressed( const OIS::KeyEvent &arg );
    virtual bool keyReleased( const OIS::KeyEvent &arg );
    // OIS::MouseListener
    virtual bool mouseMoved( const OIS::MouseEvent &arg );
    virtual bool mousePressed( const OIS::MouseEvent &arg, OIS::MouseButtonID id );
    virtual bool mouseReleased( const OIS::MouseEvent &arg, OIS::MouseButtonID id );

    // Ogre::WindowEventListener
    //Adjust mouse clipping area
    virtual void windowResized(Ogre::RenderWindow* rw);
    //Unattach OIS before window shutdown (very important under Linux)
    virtual void windowClosed(Ogre::RenderWindow* rw);

    void UpdateWindow(Ogre::PixelBox& pixelbox);

    Ogre::Root *mRoot;
    Ogre::Camera* mCamera;
    Ogre::SceneManager* mSceneMgr;
    Ogre::RenderWindow* mWindow;
    Ogre::String mResourcesCfg;
    Ogre::String mPluginsCfg;

    // OgreBites
    OgreBites::SdkTrayManager* mTrayMgr;
    OgreBites::SdkCameraMan* mCameraMan;     // basic camera controller
    OgreBites::ParamsPanel* mDetailsPanel;   // sample details panel
    bool mCursorWasVisible;                  // was cursor visible before dialog appeared
    bool mShutDown;

    //OIS Input devices
    OIS::InputManager* mInputManager;
    OIS::Mouse*    mMouse;
    OIS::Keyboard* mKeyboard;

    Ogre::TexturePtr texture;
};

#endif // #ifndef __VISION_APP_h_

#include <Windows.h>
#include<GdiPlus.h>
#include<Shlwapi.h>
#include<atlbase.h>
#include<ObjIdl.h>
#include <d3d9.h>
#include <d3dx9.h>

#include <ParticleUniverseSystemManager.h>
#include "App.h"
using namespace Ogre;

App::App(void)
    : mRoot(0),
      mCamera(0),
      mSceneMgr(0),
      mWindow(0),
      mResourcesCfg(Ogre::StringUtil::BLANK),
      mPluginsCfg(Ogre::StringUtil::BLANK),
      mTrayMgr(0),
      mCameraMan(0),
      mDetailsPanel(0),
      mCursorWasVisible(false),
      mShutDown(false),
      mInputManager(0),
      mMouse(0),
      mKeyboard(0) {
}

App::~App(void) {
    if (mTrayMgr) delete mTrayMgr;
    if (mCameraMan) delete mCameraMan;

    //Remove ourself as a Window listener
    Ogre::WindowEventUtilities::removeWindowEventListener(mWindow, this);
    windowClosed(mWindow);
    delete mRoot;
}

bool App::configure(void) {
    if(mRoot->restoreConfig()) {
        // If returned true, user clicked OK so initialise
        // Here we choose to let the system create a default rendering window by passing 'true'
        mWindow = mRoot->initialise(true, "ParticleUniverse Render Window");
        

        // Let's add a nice window icon
        HWND hwnd;
        mWindow->getCustomAttribute("WINDOW", (void*)&hwnd);

        DWORD style = ::GetWindowLong(hwnd, GWL_EXSTYLE);
        SetWindowLong(hwnd,  GWL_EXSTYLE, style | WS_EX_LAYERED);      

        return true;
    } else {
        return false;
    }
}

void App::createScene(void){
    ParticleUniverse::ParticleSystemManager*pManager =
        ParticleUniverse::ParticleSystemManager::getSingletonPtr();
    ParticleUniverse::ParticleSystem*pSys = pManager->createParticleSystem("mysys",
        "example_014", mSceneMgr);

    mSceneMgr->getRootSceneNode()->attachObject(pSys);
    pSys->start();
}

void App::chooseSceneManager(void) {
    mSceneMgr = mRoot->createSceneManager(Ogre::ST_GENERIC);
}

void App::createCamera(void) {
    // Create the camera
    mCamera = mSceneMgr->createCamera("PlayerCam");

    // Position it at 500 in Z direction
    mCamera->setPosition(Ogre::Vector3(0,0,20));
    // Look back along -Z
    mCamera->lookAt(Ogre::Vector3(0,0,-300));
    mCamera->setNearClipDistance(5);

    mCameraMan = new OgreBites::SdkCameraMan(
        mCamera);   // create a default camera controller
}

void App::createFrameListener(void) {
    Ogre::LogManager::getSingletonPtr()->logMessage("*** Initializing OIS ***");
    OIS::ParamList pl;
    size_t windowHnd = 0;
    std::ostringstream windowHndStr;

    mWindow->getCustomAttribute("WINDOW", &windowHnd);
    windowHndStr << windowHnd;
    pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));

    mInputManager = OIS::InputManager::createInputSystem( pl );

    mKeyboard = static_cast<OIS::Keyboard*>(mInputManager->createInputObject(
            OIS::OISKeyboard, true ));
    mMouse = static_cast<OIS::Mouse*>(mInputManager->createInputObject(
                                          OIS::OISMouse, true ));

    mMouse->setEventCallback(this);
    mKeyboard->setEventCallback(this);

    //Set initial mouse clipping size
    windowResized(mWindow);

    //Register as a Window listener
    Ogre::WindowEventUtilities::addWindowEventListener(mWindow, this);

    mTrayMgr = new OgreBites::SdkTrayManager("InterfaceName", mWindow, mMouse,
            this);
    mTrayMgr->showFrameStats(OgreBites::TL_BOTTOMLEFT);
    mTrayMgr->showLogo(OgreBites::TL_BOTTOMRIGHT);
    mTrayMgr->hideCursor();

    // create a params panel for displaying sample details
    Ogre::StringVector items;
    items.push_back("cam.pX");
    items.push_back("cam.pY");
    items.push_back("cam.pZ");
    items.push_back("");
    items.push_back("cam.oW");
    items.push_back("cam.oX");
    items.push_back("cam.oY");
    items.push_back("cam.oZ");
    items.push_back("");
    items.push_back("Filtering");
    items.push_back("Poly Mode");

    mDetailsPanel = mTrayMgr->createParamsPanel(OgreBites::TL_NONE, "DetailsPanel",
                    200, items);
    mDetailsPanel->setParamValue(9, "Bilinear");
    mDetailsPanel->setParamValue(10, "Solid");
    mDetailsPanel->hide();

    mRoot->addFrameListener(this);
}

void App::destroyScene(void) {
}


void App::createViewports(void) {
    texture = TextureManager::getSingleton().createManual( "RttTex",
        ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D,
        mWindow->getWidth(), mWindow->getHeight(), 0, PF_A8R8G8B8, TU_RENDERTARGET );
    RenderTarget *rttTex = texture->getBuffer()->getRenderTarget();
    Viewport *vp = rttTex->addViewport(mCamera);
    vp->setBackgroundColour(Ogre::ColourValue(0, 0, 0, 0));

    // Create one viewport, entire window
    //Ogre::Viewport* vp = mWindow->addViewport(mCamera);
    //vp->setBackgroundColour(Ogre::ColourValue(0, 0, 0, 0));

    // Alter the camera aspect ratio to match the viewport
    mCamera->setAspectRatio(
        Ogre::Real(vp->getActualWidth()) / Ogre::Real(vp->getActualHeight()));
}

void App::setupResources(void) {
    // Load resource paths from config file
    Ogre::ConfigFile cf;
    cf.load(mResourcesCfg);

    // Go through all sections & settings in the file
    Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();

    Ogre::String secName, typeName, archName;
    while (seci.hasMoreElements()) {
        secName = seci.peekNextKey();
        Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext();
        Ogre::ConfigFile::SettingsMultiMap::iterator i;
        for (i = settings->begin(); i != settings->end(); ++i) {
            typeName = i->first;
            archName = i->second;
            Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
                archName, typeName, secName);
        }
    }
}

void App::createResourceListener(void) {

}

void App::loadResources(void) {
    Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
}

using namespace Ogre;


void App::UpdateWindow(Ogre::PixelBox& pixelbox) {
    HWND hwnd;
    mWindow->getCustomAttribute("WINDOW", (void*)&hwnd);

    int width  = pixelbox.getWidth();
    int height = pixelbox.getHeight();

    HDC winhdc = ::GetDC(hwnd);
    HDC memhdc = CreateCompatibleDC(winhdc);

    RECT rcWindow;
    GetWindowRect(hwnd, &rcWindow);
     
    BITMAPINFOHEADER header = { 0 };
    header.biSize           = sizeof(BITMAPINFOHEADER);
    header.biWidth          = width;
    header.biHeight         = -height;
    header.biPlanes         = 1;
    header.biBitCount       = 32;
    header.biCompression    = BI_RGB;

    PVOID pvBits = NULL;
    HBITMAP bmp = ::CreateDIBSection(NULL, (PBITMAPINFO)&header,
        DIB_RGB_COLORS, &pvBits, NULL, 0);

    HGDIOBJ oldbmp = ::SelectObject( memhdc, bmp);
    UINT* data = static_cast<UINT*>(pvBits);
    for (int y = 0; y < height; y++) { 
        for (int x = 0; x < width; x++) { 
            Ogre::ColourValue color = pixelbox.getColourAt(x, y, 0);
            *data++ = color.getAsARGB();
        }
    }

    BLENDFUNCTION blend = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
    POINT srcpos = { 0, 0};
    POINT ptWinPos = { rcWindow.left, rcWindow.top };
    SIZE sizeWindow = {width, height};
    ::UpdateLayeredWindow(hwnd, winhdc, &ptWinPos, &sizeWindow, memhdc, &srcpos, 0,
        &blend, ULW_ALPHA);

    ::SelectObject(memhdc, oldbmp);
    ::DeleteObject(bmp);

    ::DeleteDC(memhdc);
    ::ReleaseDC(hwnd, winhdc);
}


void App::go(void) {
    mResourcesCfg = "resources.cfg";
    mPluginsCfg = "plugins.cfg";

    if (!setup())
        return;

    //mRoot->startRendering();

    mRoot->getRenderSystem()->_initRenderTargets();

    // Clear event times
    mRoot->clearEventTimes();
    Ogre::PixelBox* pixel = NULL;
    while(true) {
        //Pump messages in all registered RenderWindow windows
        Ogre::WindowEventUtilities::messagePump();
        if (!mRoot->renderOneFrame())
            break;

        Ogre::HardwarePixelBufferSharedPtr handle = texture->getBuffer();
        if(!pixel){
            int width = handle->getWidth(); 
            int height= handle->getHeight();
            char* buffer = new char[handle->getSizeInBytes()]; 
            pixel = new Ogre::PixelBox(handle->getWidth(), 
                                    handle->getHeight(), 
                                    handle->getDepth(), 
                                    handle->getFormat(), 
                                    buffer); 
        }
        handle->blitToMemory(*pixel);

        UpdateWindow(*pixel);
    }

    // clean up
    destroyScene();
}

bool App::setup(void) {
    mRoot = new Ogre::Root(mPluginsCfg);

    setupResources();

    bool carryOn = configure();
    if (!carryOn) return false;

    chooseSceneManager();
    createCamera();
    createViewports();

    // Set default mipmap level (NB some APIs ignore this)
    Ogre::TextureManager::getSingleton().setDefaultNumMipmaps(5);

    // Create any resource listeners (for loading screens)
    createResourceListener();
    // Load resources
    loadResources();

    // Create the scene
    createScene();
//不想看到帧率面板,可把这里注掉
    createFrameListener();

    return true;
};

bool App::frameRenderingQueued(const Ogre::FrameEvent& evt) {
    if(mWindow->isClosed())
        return false;

    if(mShutDown)
        return false;

    //Need to capture/update each device
    mKeyboard->capture();
    mMouse->capture();

    mTrayMgr->frameRenderingQueued(evt);

    if (!mTrayMgr->isDialogVisible()) {
        mCameraMan->frameRenderingQueued(
            evt);   // if dialog isn't up, then update the camera
        if (mDetailsPanel->isVisible()) { // if details panel is visible, then update its contents
            mDetailsPanel->setParamValue(0,
                                         Ogre::StringConverter::toString(mCamera->getDerivedPosition().x));
            mDetailsPanel->setParamValue(1,
                                         Ogre::StringConverter::toString(mCamera->getDerivedPosition().y));
            mDetailsPanel->setParamValue(2,
                                         Ogre::StringConverter::toString(mCamera->getDerivedPosition().z));
            mDetailsPanel->setParamValue(4,
                                         Ogre::StringConverter::toString(mCamera->getDerivedOrientation().w));
            mDetailsPanel->setParamValue(5,
                                         Ogre::StringConverter::toString(mCamera->getDerivedOrientation().x));
            mDetailsPanel->setParamValue(6,
                                         Ogre::StringConverter::toString(mCamera->getDerivedOrientation().y));
            mDetailsPanel->setParamValue(7,
                                         Ogre::StringConverter::toString(mCamera->getDerivedOrientation().z));
        }
    }

    return true;
}

bool App::keyPressed( const OIS::KeyEvent &arg ) {
    if (mTrayMgr->isDialogVisible()) return
            true;   // don't process any more keys if dialog is up

    if (arg.key == OIS::KC_F) { // toggle visibility of advanced frame stats
        mTrayMgr->toggleAdvancedFrameStats();
    } else if (arg.key ==
               OIS::KC_G) { // toggle visibility of even rarer debugging details
        if (mDetailsPanel->getTrayLocation() == OgreBites::TL_NONE) {
            mTrayMgr->moveWidgetToTray(mDetailsPanel, OgreBites::TL_TOPRIGHT, 0);
            mDetailsPanel->show();
        } else {
            mTrayMgr->removeWidgetFromTray(mDetailsPanel);
            mDetailsPanel->hide();
        }
    } else if (arg.key == OIS::KC_T) { // cycle polygon rendering mode
        Ogre::String newVal;
        Ogre::TextureFilterOptions tfo;
        unsigned int aniso;

        switch (mDetailsPanel->getParamValue(9).asUTF8()[0]) {
        case 'B':
            newVal = "Trilinear";
            tfo = Ogre::TFO_TRILINEAR;
            aniso = 1;
            break;
        case 'T':
            newVal = "Anisotropic";
            tfo = Ogre::TFO_ANISOTROPIC;
            aniso = 8;
            break;
        case 'A':
            newVal = "None";
            tfo = Ogre::TFO_NONE;
            aniso = 1;
            break;
        default:
            newVal = "Bilinear";
            tfo = Ogre::TFO_BILINEAR;
            aniso = 1;
        }

        Ogre::MaterialManager::getSingleton().setDefaultTextureFiltering(tfo);
        Ogre::MaterialManager::getSingleton().setDefaultAnisotropy(aniso);
        mDetailsPanel->setParamValue(9, newVal);
    } else if (arg.key == OIS::KC_R) { // cycle polygon rendering mode
        Ogre::String newVal;
        Ogre::PolygonMode pm;

        switch (mCamera->getPolygonMode()) {
        case Ogre::PM_SOLID:
            newVal = "Wireframe";
            pm = Ogre::PM_WIREFRAME;
            break;
        case Ogre::PM_WIREFRAME:
            newVal = "Points";
            pm = Ogre::PM_POINTS;
            break;
        default:
            newVal = "Solid";
            pm = Ogre::PM_SOLID;
        }

        mCamera->setPolygonMode(pm);
        mDetailsPanel->setParamValue(10, newVal);
    } else if(arg.key == OIS::KC_F5) { // refresh all textures
        Ogre::TextureManager::getSingleton().reloadAll();
    } else if (arg.key == OIS::KC_SYSRQ) { // take a screenshot
        mWindow->writeContentsToTimestampedFile("screenshot", ".jpg");
    } else if (arg.key == OIS::KC_ESCAPE) {
        mShutDown = true;
    }

    mCameraMan->injectKeyDown(arg);
    return true;
}

bool App::keyReleased( const OIS::KeyEvent &arg ) {
    mCameraMan->injectKeyUp(arg);
    return true;
}

bool App::mouseMoved( const OIS::MouseEvent &arg ) {
    if (mTrayMgr->injectMouseMove(arg)) return true;
    mCameraMan->injectMouseMove(arg);
    return true;
}

bool App::mousePressed( const OIS::MouseEvent &arg,
                                    OIS::MouseButtonID id ) {
    if (mTrayMgr->injectMouseDown(arg, id)) return true;
    mCameraMan->injectMouseDown(arg, id);
    return true;
}

bool App::mouseReleased( const OIS::MouseEvent &arg,
                                     OIS::MouseButtonID id ) {
    if (mTrayMgr->injectMouseUp(arg, id)) return true;
    mCameraMan->injectMouseUp(arg, id);
    return true;
}

//Adjust mouse clipping area
void App::windowResized(Ogre::RenderWindow* rw) {
    unsigned int width, height, depth;
    int left, top;
    rw->getMetrics(width, height, depth, left, top);

    const OIS::MouseState &ms = mMouse->getMouseState();
    ms.width = width;
    ms.height = height;
}

//Unattach OIS before window shutdown (very important under Linux)
void App::windowClosed(Ogre::RenderWindow* rw) {
    //Only close for window that created OIS (the main window in these demos)
    if( rw == mWindow ) {
        if( mInputManager ) {
            mInputManager->destroyInputObject( mMouse );
            mInputManager->destroyInputObject( mKeyboard );

            OIS::InputManager::destroyInputSystem(mInputManager);
            mInputManager = 0;
        }
    }
}

#include <windows.h>

#include "App.h"

using namespace Ogre;


INT WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR cmdLine, INT) {    
    App app;

    app.go();

    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值