用Ogre生成天龙八部的lightmap和minimap的简单方法

自从在一家创业小公司当了客户端主程以后,就忙的没有时间写博客了,整个公司没有一个人有完整的项目经验,所有一切都在摸索中前进,但初生牛犊不怕虎,项目还算进展顺利。但我始终认为,安静下来总结整理一下工作心得是必要的,可惜这个愿望恐怕得等到这个项目忙完以后。

周末有点时间,还是可以抽空随便写点东西。

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的图片

 

.

.//这是阴影图、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、

附上代码,看看思路就好!

view plaincopy to clipboardprint?
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
/* 
@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 
/*
@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 view plaincopy to clipboardprint?
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
#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);  
    }  
 
 

原创文章,转载请注明,谢谢!


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/qq18052887/archive/2010/08/15/5812611.aspx

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值