2010年4月3日

,

RT Shader System in OGRE 1.7.0

前言

OGRE在1.7.0版中,最重要的feature之一就是real-time shader system (RT Shader System),它的功能就是從OGRE的material script中自動產生shader (HLSL/CG或GLSL檔案)來取代或增加原本fix pipeline的功能。 使用RT Shader System好處呢?

  1. 美術和程式分工

    以往要要在Ogre中使用normal map必需大費周張的寫vertex shader和pixel shader再把全域變數(global variable)關連到OGRE裡的光源(lights)和座標轉換(transforms),在團隊裡程式人員和美術人員往往是不同一群人,因此新增新的美術資料,就必需勞動程式再編輯material script,分工不完全使得團隊效率降低。

  2. 開發快速

    因為shader是從shader範本(template)中產生出來,而範本函蓋大部分的繁覆的工作,所以開發人員能過集中精力去處理shader裡較重要的部份(藉由撰寫RT Shader System的plugin),使得實作新的shader更快速。而撰寫好的plugin又能在material script透過參數使用,使得整合也更快速。

使用

  1. 設罝開發環境

    使用RT Shader System需先在程式專案中連結OgreRTShaderSystem.lib (Debug組態是OgreRTShaderSystem_d.lib),放在OgreSDK\lib中。並且在初始化OGRE和RT Shader System的cpp檔include RT Shader System的header:

    #include "OGRE/RTShaderSystem/OgreRTShaderSystem.h"


  2. 初始化

    RT Shader System必須早於任何一個Resource Group初始化,通常是在產生第一個RenderWindow之後。

    RenderWindow* window = Root::getSingleton().initialise(true, windowTitle);
    //在這裡初始化RT Shader System
    _initializeRTShaderSystem();

    ResourceGroupManager::getSingleton().initialiseAllResourceGroups();

    以下是_initializeRTShaderSystem()的definition

    bool _initializeRTShaderSystem()
    {
    if (RTShader::ShaderGenerator::initialize())
    {
    //先取得ShaderGenerator的pointer
    _shaderGenerator =
    RTShader::ShaderGenerator::getSingletonPtr();
    //設定ShaderSystem所使用的Shader語言
    _shaderGenerator->setTargetLanguage("hlsl");
    //你可以指定一個目錄來暫存RT Shader System產生的Shader,
    //這樣就不需要重覆產生Shader
    //但1.7.0的RT Shader System只接受絕對路徑,
    //因此此處使用boost::filesystem把相對路徑轉換成絕對路徑
    namespace fs = boost::filesystem;
    std::string shaderCachePath =
    fs::system_complete( fs::path("./ShaderCache/") ).string();
    _shaderGenerator->setShaderCachePath(shaderCachePath);

    //指定一個material listener給material manager,此處稍後說明
    _rtssMaterialListener =
    new RtShaderSystemListener(_shaderGenerator);
    MaterialManager::getSingleton().addListener(
    _rtssMaterialListener);
    return true;
    }
    return false;
    }

    RtShaderSystemListener繼承MaterialManager::Listener,是從OGRE Sample裡抄出來的class。

    /**
    當RtShaderSystemListener被註冊給MaterialManager之後,一旦找不到適當的tecnique
    來render 某一個material,便會喚起handleSchemeNotFound這個member function。因
    此我們要在handleSchemeNotFound把原本的material technique交給ShaderGenerator
    來產生以Shader為基礎的tecnique並回傳。
    */
    class RtShaderSystemListener : public MaterialManager::Listener
    {
    public:

    RtShaderSystemListener(RTShader::ShaderGenerator* pShaderGenerator)
    {
    mShaderGenerator = pShaderGenerator;
    }

    /**
    當Entity要被render時,OGRE會依指定給viewport的scheme name從material挑選符合
    的technique(在我們清況中,會指定ShaderGenerator::DEFAULT_SCHEME_NAME給
    viewport)因為material裡tecnique的scheme name預設是
    MaterialManager::DEFAULT_SCHEME_NAME,
    所以handleSchemeNotFound便會被呼叫來處理"找不到technique"事件。
    */

    virtual Technique* handleSchemeNotFound(
    unsigned short schemeIndex,
    const String& schemeName,
    Material* originalMaterial,
    unsigned short lodIndex,
    const Renderable* rend)
    {
    Technique* generatedTech = NULL;

    //
    //Case this is the default shader generator scheme.
    if (schemeName == RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME)
    {
    bool techniqueCreated;

    // Create shader generated technique for this material.
    techniqueCreated = mShaderGenerator->createShaderBasedTechnique(
    originalMaterial->getName(),
    MaterialManager::DEFAULT_SCHEME_NAME,
    schemeName);

    // Case technique registration succeeded.
    if (techniqueCreated)
    {
    // Force creating the shaders for the generated technique.
    mShaderGenerator->validateMaterial(schemeName,
    originalMaterial->getName());

    // Grab the generated technique.
    Material::TechniqueIterator itTech =
    originalMaterial->getTechniqueIterator();

    while (itTech.hasMoreElements())
    {
    Technique* curTech = itTech.getNext();

    if (curTech->getSchemeName() == schemeName)
    {
    generatedTech = curTech;
    break;
    }
    }
    }
    }
    return generatedTech;
    }
    protected:
    /// The shader generator instance.
    Ogre::RTShader::ShaderGenerator* mShaderGenerator;
    };
    最後,我們必需要讓OGRE使用RT Shader System所產生的technique(亦即以shader為基礎的technique)。因此我們設定viewport所要使用的scheme name。
    viewport->setMaterialScheme(
    RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME);
Publisher: Unknown - 星期六, 4月 03, 2010

2009年9月2日

Memory Continuity of "std::vector"

寫了那麼久的C++, 一直無法確定std::vector的元素(element)到底有沒有被置放在連續的記憶體(memory)上。

Ogre的Forum上有人給了解答, 摘自C++ 2003 standard:

"23.2.4 Class template vector [lib.vector]
1 A vector is a kind of sequence that supports random access iterators. In addition, it supports (amortized) constant time insert and erase operations at the end; insert and erase in the middle take linear time. Storage management is handled automatically, though hints can be given to improve efficiency. The elements of a vector are stored contiguously, meaning that if v is a vector where T is some type other than bool, then it obeys the identity &v[n] == &v[0] + n for all 0 <= n < v.size()."
Publisher: Unknown - 星期三, 9月 02, 2009

2009年6月15日

,

Event Model in .NET

在.NET中 ( C# and C++/CLI )

delegate可以想成 class of function pointer array

delegate void EventHandler( int arg );

等同於 C / C++中的

typedef void (*EventHandler)( int arg );


delegate是一種型別(class), 要宣告後才能使用.

eg. of C#

class Foo{
public:
EventHandler myEvent;
}

// class that recv event!
class Listener{
public void recvFunc( int arg ){
//print arg
}
}

// func that fire event!
void fireFunc(){

Foo myfoo = new Foo();
Listener listener = new Listener();
myfoo.myEvent += listener.recvFunc;
myfoo.myEvent( 5 );
}


這樣就會印出5

其實有了delegate 就可以實作event系統,
但event是幹嘛用的呢?

event 這個keyword是一個修飾詞 就像 const, static, virtual一樣,
他專門修飾delegate,
例如
class Foo{
//修飾  型別(class)  物件(object)
event EventHandler myEvent;
}



那event修飾了什麼?
如果delegate沒有event修飾, 它可以被物件外的程式碼呼叫,
例如前例的
myfoo.myEvent(5);

但加上event後則不能,
所以
myfoo.myEvent(5);

這一行compiler就不會過。
但是delegate仍可以被物件以外的程式嗎加掛 recv function
所以
myfoo.myEvent += listener.recvFunc;

還是合法的。

這樣的設計,
就好像說話,
只有我自己可以用我的嘴說話,
沒人可以用我的嘴說話, 不然會產生很多誤會。
但聽的人可以自由的告訴我, 他想聽什麼,
當我要說他想聽的東西的時候, 就會去跟他說。
Publisher: Unknown - 星期一, 6月 15, 2009