自從在一家創業小公司當了客戶端主程以後,就忙的沒有時間寫博客了,整個公司沒有一個人有完整的項目經驗,所有一切都在摸索中前進,但初生牛犢不怕虎,項目還算進展順利。但我始終認爲,安靜下來總結整理一下工作心得是必要的,可惜這個願望恐怕得等到這個項目忙完以後。
週末有點時間,還是可以抽空隨便寫點東西。
lightmap的重要性不用多說,沒必要所有陰影都動態去渲染,那些一輩子也不會動的靜態物體,貼一張lightmap就行了,可惜Ogre只提供動態陰影給我們,幫人也不幫到底。
如何生成天龍八部一樣lightmap,如果你去百度一下,他們會告訴你各種方法,什麼光線追蹤,shader,之類
以上都是告訴你,自己去產生一個陰影。但是Ogre已經幫我們產生了動態陰影,我們就沒必要再自己去生成陰影,
只要用動態陰影的渲染一張靜態陰影圖,保存下來不就行了麼。
那麼如何用Ogre的動態陰影去產生一張靜態的陰影圖呢?
1)先學會渲染一張minimap的縮略圖,縮略圖大家都應該會吧,創建一個垂直俯瞰的攝像機,平行投影拍一張就是
2)改進minimap,讓垂直俯瞰的攝像機的視口只渲染地形隊列。不渲染其他隊列
這樣拍出來的minimap就只有陰影和地形紋理混合後效果了
Ogre::RenderQueueInvocationSequence* rqis =
Ogre::Root::getSingleton().createRenderQueueInvocationSequence(“Lightmap maker”);
Ogre::RenderQueueInvocation* rqi =
rqis->add(Ogre::RENDER_QUEUE_WORLD_GEOMETRY_1, “World Geometry”);
viewport->setRenderQueueInvocationSequenceName(“Lightmap maker”);
3)再改進一下,把地形材質設置爲BaseWhite,全白,那麼minimap就變成了lightmap了。
4)Ogre的陰影並不好用,所以你需要優化,怎麼優化,或者用shader實現,以後再寫。
//////////這是動態陰影的圖片、、、、、、、、、、、、、、、、、、、、、、、、、、
//////////////////////////這是貼上lightmap的圖片
./////////////這是陰影圖、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
附上代碼,看看思路就好!
- /*
- @filename WXLightMapMaker.h
- @creator LuoYinan
- @data 2010.6.14
- @remarks 創建場景光照圖
- */
- #ifndef __WX_LIGHTMAP_MAKER_H__
- #define __WX_LIGHTMAP_MAKER_H__
- #include ”SceneManipulator.h”
- namespace WX
- {
- class LightMapMaker
- {
- public:
- LightMapMaker(SceneManipulator* manipulator);
- ~LightMapMaker(void);
- // 初始化,包括創建render texture,camera等
- void initial(void);
- // 銷燬render texture
- void destroy(void);
- // 保存光照圖到文件
- // 格式 ”emei.lightmap.png”,也支持全路徑,比如../../Data/Scene/emei.lightmap.png”
- void outputTexture(const Ogre::String& fileName);
- protected:
- SceneManipulator* mSceneManipulator;
- Ogre::RenderTexture* mRenderTexture;
- };
- }
- #endif
- #include ”WXLightMapMaker.h”
- #include ”GameScene/TerrainData.h”
- #include ”GameScene/WXScene.h”
- #include ”GameScene/WXSceneInfo.h”
- #include ”GameScene/WXStaticEntityObject.h”
- #include ”GameScene/WXModelObject.h”
- namespace WX
- {
- //———————————————————————————-
- LightMapMaker::LightMapMaker(SceneManipulator* manipulator)
- : mSceneManipulator(manipulator)
- , mRenderTexture(0)
- {
- }
- //——————————————————————————–
- LightMapMaker::~LightMapMaker(void)
- {
- }
- //——————————————————————————–
- void LightMapMaker::initial(void)
- {
- // 確保地形已經載入
- TerrainData* data = mSceneManipulator->getTerrainData();
- assert(data && “TerrainData* == NULL”);
- // 創建lightmap攝像機,垂直俯瞰整個地圖
- Ogre::SceneManager* mSceneManager = mSceneManipulator->getSceneManager();
- //if (mSceneManipulator->getTerrainData()->mLightmapImage == NULL)
- {
- static const String msLightmapMaker(“Lightmap maker”);
- Ogre::Camera* camera = 0;
- try
- {
- camera = mSceneManager->getCamera(msLightmapMaker);
- }
- catch (const Ogre::Exception& e)
- {
- // 只提示異常,而不退出程序
- if (e.getNumber() == e.ERR_ITEM_NOT_FOUND)
- {
- //MessageBox(NULL, e.what(), ”An exception has occured!”, MB_OK | MB_ICONERROR | MB_TASKMODAL);
- }
- else
- {
- throw;
- }
- }
- if (!camera)
- {
- camera = mSceneManager->createCamera(msLightmapMaker);
- camera->setAutoAspectRatio(true);
- camera->setProjectionType(Ogre::PT_ORTHOGRAPHIC); // 平行投影
- // 在Ogre1.6版本中,平行投影的大小改爲setOrthoWindowWidth和setOrthoWindowHeight來決定,
- // 而不是以前版本用的FOV和近截面,so…
- camera->setFOVy(Ogre::Degree(90));
- camera->setOrthoWindowWidth(mSceneManipulator->getTerrainData()->getXSize()*mSceneManipulator->getBaseScale());
- camera->setOrthoWindowHeight(mSceneManipulator->getTerrainData()->getZSize()*mSceneManipulator->getBaseScale());
- Ogre::Quaternion orientation;
- orientation.FromAxes(Ogre::Vector3::UNIT_X, Ogre::Vector3::NEGATIVE_UNIT_Z, Ogre::Vector3::UNIT_Y);
- camera->setOrientation(orientation);
- }
- // 計算所有對象包圍盒,以此來決定攝像機的參數
- Ogre::AxisAlignedBox aabb;
- Ogre::SceneManager::MovableObjectIterator itm =
- mSceneManager->getMovableObjectIterator(Ogre::EntityFactory::FACTORY_TYPE_NAME);
- while (itm.hasMoreElements())
- {
- Ogre::MovableObject* movable = itm.getNext();
- aabb.merge(movable->getWorldBoundingBox(true));
- }
- camera->setNearClipDistance(32 * mSceneManipulator->getBaseScale() / 2);
- camera->setFarClipDistance(camera->getNearClipDistance() + aabb.getMaximum().y - aabb.getMinimum().y);
- camera->setPosition(0, camera->getNearClipDistance() + aabb.getMaximum().y, 0);
- // 調整陰影參數
- Ogre::Real distance = camera->getNearClipDistance() * Ogre::Math::Sqrt(1 + Ogre::Math::Sqr(camera->getAspectRatio()));
- mSceneManager->setShadowFarDistance(distance);
- Ogre::Real camHeight = camera->getPosition().y;
- mSceneManager->setShadowDirLightTextureOffset(camHeight / distance);
- // 創建lightmap的Rtt紋理,和天龍一樣,設爲地形大小的8倍
- Ogre::TexturePtr pTexture = (Ogre::TexturePtr)Ogre::TextureManager::getSingleton().getByName(“LightmapRttTex”);
- if (pTexture.isNull())
- {
- size_t width = data->getXSize() * 8;
- size_t height = data->getZSize() * 8;
- pTexture = Ogre::TextureManager::getSingleton().createManual(
- “LightmapRttTex”, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
- Ogre::TEX_TYPE_2D,
- width, height, 1, 0, Ogre::PF_BYTE_RGB,
- Ogre::TU_RENDERTARGET, 0);
- }
- Ogre::HardwarePixelBufferSharedPtr pBuffer = pTexture->getBuffer(0, 0);
- mRenderTexture = pBuffer->getRenderTarget(0);
- // 創建lightmap的視口
- Ogre::Viewport* viewport = mRenderTexture->addViewport(mSceneManipulator->getSceneManager()->getCamera(“Lightmap maker”));
- viewport->setOverlaysEnabled(false);
- viewport->setSkiesEnabled(false);
- viewport->setShadowsEnabled(true);
- // 自定義一個渲染隊列調用組,只渲染地形隊列,這是關鍵,我們只要陰影,不要其他的.
- // 如果你全部都渲染了,那就變成了minimap,縮略圖了.
- Ogre::RenderQueueInvocationSequence* rqis =
- Ogre::Root::getSingleton().createRenderQueueInvocationSequence(“Lightmap maker”);
- Ogre::RenderQueueInvocation* rqi =
- rqis->add(Ogre::RENDER_QUEUE_WORLD_GEOMETRY_1, “World Geometry”);
- viewport->setRenderQueueInvocationSequenceName(“Lightmap maker”);
- }
- }
- //——————————————————————————–
- void LightMapMaker::destroy(void)
- {
- if (mRenderTexture)
- {
- mSceneManipulator->getSceneManager()->destroyCamera(“Lightmap maker”);
- mRenderTexture->removeAllViewports();
- Ogre::TextureManager::getSingleton().remove(“LightmapRttTex”);
- mRenderTexture = NULL;
- }
- }
- //——————————————————————————–
- void LightMapMaker::outputTexture(const Ogre::String& fileName)
- {
- // 如果已經有lightmap了,跳過
- if (mSceneManipulator->getTerrainData()->mLightmapImage)
- {
- // 需要提示麼?
- return;
- }
- // 讓所有靜態物體都可以投射陰影,來製作lightmap
- Scene::ObjectsByTypeRange objests = mSceneManipulator->getSceneInfo()->findObjectsByType(StaticEntityObject::msType);
- for (Scene::ObjectsByTypeIterator it = objests.first; it != objests.second; ++ it)
- {
- ObjectPtr object = (*it);
- object->setPropertyAsString(“cast shadows”, “true”);
- //object->setPropertyAsString(“receive shadows”, ”true”);
- }
- objests = mSceneManipulator->getSceneInfo()->findObjectsByType(ModelObject::msType);
- for (Scene::ObjectsByTypeIterator it = objests.first; it != objests.second; ++ it)
- {
- ObjectPtr object = (*it);
- object->setPropertyAsString(“cast shadows”, “true”);
- //object->setPropertyAsString(“receive shadows”, ”true”);
- }
- // 用BaseWhite代替原來的地形材質,並重構地形
- TerrainData::MaterialTemplates& materials = mSceneManipulator->getTerrainData()->mMaterialTemplates;
- TerrainData::MaterialTemplates materialsCopy(materials);
- materials["OneLayer"] = “BaseWhite”;
- materials["OneLayerLightmap"] = “BaseWhite”;
- materials["TwoLayer"] = “BaseWhite”;
- materials["TwoLayerLightmap"] = “BaseWhite”;
- mSceneManipulator->getTerrain()->buildGeometry(mSceneManipulator->getBaseSceneNode(), true);
- // 更新
- //mSceneManipulator->getSceneManager()->_updateSceneGraph(mSceneManipulator->getSceneManager()->getCamera(“Lightmap maker”));
- mRenderTexture->update();
- // 保存lightmap到文件
- Ogre::String LightmapFileName(fileName);
- String baseName, path, outExtention;
- if (fileName.empty())
- {
- WX::TerrainData* data = mSceneManipulator->getTerrainData();
- Ogre::StringUtil::splitBaseFilename(data->mHeightmapFilename, baseName, outExtention);
- LightmapFileName = baseName + “.lightmap.png”;
- }
- mRenderTexture->writeContentsToFile(LightmapFileName);
- // 載入lightmap
- static const String TEMP_GROUP_NAME = “#TEMP#”; // 臨時資源組
- Ogre::StringUtil::splitFilename(LightmapFileName, baseName, path);
- mSceneManipulator->getTerrainData()->mLightmapFilename = baseName;
- Ogre::ResourceGroupManager& rgm = Ogre::ResourceGroupManager::getSingleton();
- rgm.addResourceLocation(path, “FileSystem”, TEMP_GROUP_NAME, false);
- // 這個函數本來是protected,以後最好還是重新載入整個地形,而不是單獨載入lightmap
- mSceneManipulator->getTerrainData()->_loadLightmap(baseName, “image”, TEMP_GROUP_NAME);
- // 換回原來的地形材質,並重構地形
- std::swap(materials, materialsCopy);
- mSceneManipulator->getTerrain()->buildGeometry(mSceneManipulator->getBaseSceneNode(), true);
- // 所有靜態物體不再需要投射陰影了,因爲我們有lightmap
- objests = mSceneManipulator->getSceneInfo()->findObjectsByType(StaticEntityObject::msType);
- for (Scene::ObjectsByTypeIterator it = objests.first; it != objests.second; ++ it)
- {
- ObjectPtr object = (*it);
- object->setPropertyAsString(“cast shadows”, “false”);
- //object->setPropertyAsString(“receive shadows”, ”true”);
- }
- objests = mSceneManipulator->getSceneInfo()->findObjectsByType(ModelObject::msType);
- for (Scene::ObjectsByTypeIterator it = objests.first; it != objests.second; ++ it)
- {
- ObjectPtr object = (*it);
- object->setPropertyAsString(“cast shadows”, “false”);
- //object->setPropertyAsString(“receive shadows”, ”true”);
- }
- // 銷燬臨時資源組
- rgm.destroyResourceGroup(TEMP_GROUP_NAME);
- }
- }