饭后温柔

汉堡与老干妈同嚼 有可乐味
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

ogre ofusion材质动画使用shader实现

Posted on 2012-05-14 17:41  饭后温柔  阅读(981)  评论(0编辑  收藏  举报

ofusion导出3dmax中的动画到osm文件,其默认的osmscene加载,没有对material进行材质拷贝.当多个动画不同时播放,而又用到了相同的材质时,就会出现错误.因为ogre的实体默认使用的是全局的material引用.因此需要对material进行拷贝,然后实体重新载入新的material.

另一种方法是在shader中实现材质动画.主要处理alpha的变化,及纹理动画.

.h

View Code
#ifndef __ShaderAlphaAnimationComponent_h__
#define __ShaderAlphaAnimationComponent_h__

#include "AlphaAnimationComponent.h"

/************************************************************************/
/* 说明
    该组件在加载osm的回调函数中配合使用,实现材质的alpha动画
        在OnEntityCreate(Ogre::Entity *pEntity, rapidxml::xml_node<>* pEntityDesc)回调函数中
        使用addEntity(pEntity).
        在OnMaterialAnimatorLoaded(const oMaterialAnimation& materialAnim)回调函数中
        使用pushBack(materialAnim).
    之后即可如之前的alpha组件一样,调用enable,update正常使用.

*/
/************************************************************************/


    class ShaderPassAnimation;
    class ShaderAlphaAnimationComponent
    {
        typedef boost::shared_ptr<ShaderPassAnimation>  ShaderPassAnimationPtr;
        typedef std::vector<Ogre::Entity*>          EntityList;
    public:
        ShaderAlphaAnimationComponent(void);
        virtual ~ShaderAlphaAnimationComponent(void);
        
    private:

        bool enable(int times);
        bool update(TimeType time);
        void disable(void);
        void pushBack(const oMaterialAnimation& materialAnim);

        void addEntity(Ogre::Entity* entity);

        ComponentQueryInterface _query;    
        boost::scoped_ptr<ShaderAlphaAnimationInterface>    _saaInterface;
        std::vector<ShaderPassAnimationPtr> _passes;
        int _times;
        

    };

    class ShaderPassAnimation
    {
    public:
        typedef        std::vector<Ogre::SubEntity*>    MySubEntityList;

        ShaderPassAnimation(const oMaterialAnimation& materialAnim, const oPassAnimation& passAnim);
        ~ShaderPassAnimation(void);
        bool enable(void);
        bool update(TimeType time);
        void disable(void);
        void setTransparency(float transparency);
        void addSubEntity(Ogre::SubEntity* subEnt) { subEntityList.push_back(subEnt); }
    public:
        oPassAnimation  _passAnim;
        TimeType _time;
        std::string _materialName;
        unsigned int _techniqueIndex;
        float _currentTransparency;

        Ogre::ColourValue _ambient;
        Ogre::ColourValue _diffuse; 
        Ogre::SceneBlendType _SBT;
        oPassAnimation::AlphaKeyFramesList::iterator _it;

        
        Ogre::Technique*    _technique;
        MySubEntityList        subEntityList;


    };

#endif

.cpp

View Code
#include "ShaderAlphaAnimationComponent.h"



ShaderPassAnimation::ShaderPassAnimation(const oMaterialAnimation& materialAnim, const oPassAnimation& passAnim):
_passAnim(passAnim),
_time(0.f),
_materialName(materialAnim.materialName),
_techniqueIndex(materialAnim.techniqueIndex),
_SBT(Ogre::SBT_TRANSPARENT_ALPHA)
{
    _it = _passAnim.alphaKeyFrames.begin();
    _currentTransparency = 0.0f;

}
ShaderPassAnimation::~ShaderPassAnimation(void)
{

}

void ShaderPassAnimation::setTransparency(float transparency)
{

    _currentTransparency = transparency;
    if (_currentTransparency >= 0.0f) 
    {
        if (_currentTransparency > 1.0f)
            _currentTransparency = 1.0f;

        MySubEntityList::iterator it = subEntityList.begin();
        for(; it != subEntityList.end(); ++it)
        {
            Ogre::SubEntity* subEnt = *it;
            subEnt->setCustomParameter(1, Ogre::Vector4(0, 0, 0, _currentTransparency));
        }
    }
}

bool ShaderPassAnimation::enable(void)
{
    MySubEntityList::iterator it = subEntityList.begin();
    for(; it != subEntityList.end(); ++it)
    {
        Ogre::SubEntity* subEnt = *it;
        Ogre::MaterialPtr pMat = subEnt->getMaterial();
        int numTechniques = pMat->getNumTechniques();
        for (int i = 0; i < numTechniques; i++)
        {
            Ogre::Technique* pTechnique = pMat->getTechnique(i);
            int numPasses = pTechnique->getNumPasses();
            for (int j = 0; j < numPasses; j++)
            {
                Ogre::Pass* pPass = pTechnique->getPass(j);
                pPass->setVertexProgram("MaterialAlphaAnimatinVP");
                pPass->setFragmentProgram("MaterialAlphaAnimatinFP");
            }
        }
        break;
    }

    _time = 0.f;
    _it = _passAnim.alphaKeyFrames.begin();
    update(0.f);

    return true;
}
bool ShaderPassAnimation::update(TimeType time)
{
    _time += time;
    if(_time > _passAnim.alphaLength)
        return false;

    if(_it == _passAnim.alphaKeyFrames.end())
        return true;
    if(_time >= _it->first)
    {
        setTransparency(1.0f- _it->second);
        ++_it;
    }else if(_it != _passAnim.alphaKeyFrames.begin() && _it != _passAnim.alphaKeyFrames.end())
    {

        oPassAnimation::AlphaKeyFramesList::iterator last = _it;
        last--;
        

        float s = (_time - last->first)/ (_it->first - last->first);
        float alpha = (last->second) * (1.f-s) + (_it->second * s);
        setTransparency(1.0f- alpha);

    }

    return true;
}
void ShaderPassAnimation::disable(void)
{    
    MySubEntityList::iterator it = subEntityList.begin();
    for(; it != subEntityList.end(); ++it)
    {
        Ogre::SubEntity* subEnt = *it;
        subEnt->setCustomParameter(1, Ogre::Vector4(0, 0, 0, 1));
    }

}

//////////////////////////////////////////////////////////////////////////
ShaderAlphaAnimationComponent::ShaderAlphaAnimationComponent():
_times(0.f)
{

}

ShaderAlphaAnimationComponent::~ShaderAlphaAnimationComponent(void)
{

}

ComponentInterface * ShaderAlphaAnimationComponent::_queryInterface(const TypeInfo & info)
{
    return _query.queryInterface(info);
}


void ShaderAlphaAnimationComponent::pushBack(const oMaterialAnimation& materialAnim)
{

    BOOST_FOREACH(const oPassAnimation & pa, materialAnim.passAnims)
    {    
        ShaderPassAnimationPtr pp(new ShaderPassAnimation(materialAnim, pa));
        _passes.push_back(pp);
    }

}

void ShaderAlphaAnimationComponent::addEntity(Ogre::Entity* entity)
{
    if(entity == NULL) return;

    int subEntNum = entity->getNumSubEntities();
    for (int i = 0; i < subEntNum; i++)
    {
        Ogre::SubEntity* subEntity =  entity->getSubEntity(i);
        Ogre::String matName = subEntity->getMaterial()->getName();

        std::vector<ShaderPassAnimationPtr>::iterator it = _passes.begin();
        for (; it != _passes.end(); ++it)
        {
            if ((*it)->_materialName == matName)
                (*it)->addSubEntity(subEntity);
        }
    }

}

bool ShaderAlphaAnimationComponent::enable(int times)
{

    _times = times;
    BOOST_FOREACH(ShaderPassAnimationPtr pa  ,_passes)
    {

        if(!pa->enable())
            return false;

    }
    --_times;
    return true;
}
bool ShaderAlphaAnimationComponent::update(TimeType time)
{

    bool ret = false;

    BOOST_FOREACH(ShaderPassAnimationPtr pa  ,_passes)
    {
        ret = pa->update(time) | ret;
    }
    if(ret == false && _times == 0)
    {
        if( _times == 0)
        {
            return false;
        }
        else
        {
            _times--;
            disable();
        }
    }        
    return true;
}
void ShaderAlphaAnimationComponent::disable(void)
{
    BOOST_FOREACH(ShaderPassAnimationPtr pa  ,_passes)
    {
        pa->disable() ;
    }

}

oMaterialAnimation这个类在ofusion提供的osmscene加载文件中有定义.主要是将alpha变化值传入cg中.

.cg

void main_vp(float4 position    : POSITION,
             float2 uv            : TEXCOORD0, 
                // outputs
                out float4 oPosition    : POSITION,
                out float2 outUV : TEXCOORD0,
                // parameters
                uniform float4x4 texMatrix,
                uniform float4x4 worldViewProj)
{
    oPosition = mul(worldViewProj, position);
    outUV = mul(texMatrix,float4(uv,0,1)).xy;
}

void main_fp(out float4 color : COLOR,
                float2 uv : TEXCOORD0,
                uniform sampler2D texture : register(s0),
                uniform float4 alphaFactor
                )
{
    color = tex2D(texture, uv);
    color.xyz = color.w * color.xyz;
    color.w = 1 - alphaFactor.w;
}

注意顶点程序中的outUV = mul(texMatrix,float4(uv,0,1)).xy;纹理动画转换.

.program

vertex_program MaterialAlphaAnimatinVP cg
{
    source MaterialAlphaAnimation.cg
    entry_point main_vp
    profiles vs_1_1 arbvp1

    default_params
    {
        param_named_auto texMatrix texture_matrix   0
        param_named_auto worldViewProj worldviewproj_matrix
    }
}

fragment_program MaterialAlphaAnimatinFP cg
{
    source MaterialAlphaAnimation.cg
    entry_point main_fp
    profiles ps_1_1 arbfp1 fp20
 
    default_params
    {
        param_named_auto alphaFactor custom 1
    }
}