将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::FrameListenervirtual bool frameRenderingQueued(const Ogre::FrameEvent& evt);// OIS::KeyListenervirtual bool keyPressed( const OIS::KeyEvent &arg );virtual bool keyReleased( const OIS::KeyEvent &arg );// OIS::MouseListenervirtual 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 areavirtual 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;// OgreBitesOgreBites::SdkTrayManager* mTrayMgr;OgreBites::SdkCameraMan* mCameraMan;// basic camera controllerOgreBites::ParamsPanel* mDetailsPanel; // sample details panelbool mCursorWasVisible;// was cursor visible before dialog appearedbool mShutDown;//OIS Input devicesOIS::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 listenerOgre::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 iconHWND 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 cameramCamera = mSceneMgr->createCamera("PlayerCam");// Position it at 500 in Z directionmCamera->setPosition(Ogre::Vector3(0,0,20));// Look back along -ZmCamera->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 sizewindowResized(mWindow);//Register as a Window listenerOgre::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 detailsOgre::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 viewportmCamera->setAspectRatio(Ogre::Real(vp->getActualWidth()) / Ogre::Real(vp->getActualHeight()));}void App::setupResources(void) {// Load resource paths from config fileOgre::ConfigFile cf;cf.load(mResourcesCfg);// Go through all sections & settings in the fileOgre::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 timesmRoot->clearEventTimes();Ogre::PixelBox* pixel = NULL;while(true) {//Pump messages in all registered RenderWindow windowsOgre::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 updestroyScene();}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 resourcesloadResources();// Create the scenecreateScene();//不想看到帧率面板,,可把这里注掉createFrameListener();return true;};bool App::frameRenderingQueued(const Ogre::FrameEvent& evt) {if(mWindow->isClosed())return false;if(mShutDown)return false;//Need to capture/update each devicemKeyboard->capture();mMouse->capture();mTrayMgr->frameRenderingQueued(evt);if (!mTrayMgr->isDialogVisible()) {mCameraMan->frameRenderingQueued(evt); // if dialog isn’t up, then update the cameraif (mDetailsPanel->isVisible()) { // if details panel is visible, then update its contentsmDetailsPanel->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()) returntrue; // don’t process any more keys if dialog is upif (arg.key == OIS::KC_F) { // toggle visibility of advanced frame statsmTrayMgr->toggleAdvancedFrameStats();} else if (arg.key ==OIS::KC_G) { // toggle visibility of even rarer debugging detailsif (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 modeOgre::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 modeOgre::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 texturesOgre::TextureManager::getSingleton().reloadAll();} else if (arg.key == OIS::KC_SYSRQ) { // take a screenshotmWindow->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 areavoid 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;}

愚者用肉体监视心灵,智者用心灵监视肉体

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

相关文章:

你感兴趣的文章:

标签云: