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 } }