就是刀光拖尾效果,这个挺有意思,Ogre竟然单写了一个类来实现这个功能。名字叫做RibbonTrail。
不过这个类似乎并不太好用,实现的效果是从手握武器的位置沿相对衬的两个方向延伸出片,这样的话,如果手里是把剑,那么效果就不对了。如果手里的武器是长枪,因为手握得位置也不是正中间,所以也不对。。。。
于是又有人写了一个WeaponTrial类来解决这个问题。但是他没有处理缩放问题,所以在连接点从父节点带来的缩放矩阵影响下,刀光的宽度就会有问题,除非你的人物的骨骼完全没有缩放。
另外这个WeaponTrial的计算方法确实是相当费。需要重新更新整个的骨骼动画。
Ogre的一些周边代码的水平大抵都是如此,基本的意思有了,不过照工业标准总是差着一些。拿回来需要好好的修改才行。但用来玩玩还是足够的。
下面是修改后的截图和代码。
//.h
#pragma once
#include<list>
#include "Ogre.h"
using namespace Ogre;
class WeaponTrail
{
public:
WeaponTrail(Ogre::String name, SceneManager* s );
virtual ~WeaponTrail();
/// Set the weapon entity to which the trail is attached
void setWeaponEntity(Entity* p_WeaponEntity);
/// update the weapon trail
void onUpdate(float p_DeltaT);
/// Set the name of the material to use for the trail
void setMaterialName(const String& p_MaterialName);
/// set the initial color of the start of segments
void setSegmentStartInitialColor(const Ogre::ColourValue& p_Color);
/// get the initial color of the start of segments
const Ogre::ColourValue& getSegmentStartInitialColor() const;
/// set the initial color of the end of segments
void setSegmentEndInitialColor(const Ogre::ColourValue& p_Color);
/// get the initial color of the end of segments
const Ogre::ColourValue& getSegmentEndInitialColor() const;
/// set how the color of the start of segments will change over time
void setSegmentStartColorChange(const Ogre::ColourValue& p_ColorChange);
/// get how the color of the start of segments will change over time
const Ogre::ColourValue& getSegmentStartColorChange() const;
/// set how the color of the start of segments will change over time
void setSegmentEndColorChange(const Ogre::ColourValue& p_ColorChange);
/// get how the color of the start of segments will change over time
const Ogre::ColourValue& getSegmentEndColorChange() const;
/// Return the max vertex count of the trail
inline int getMaxSegmentCount() const {return m_MaxSegmentCount;}
/// set the width
void setWidth(float p_Width) {m_Width = p_Width;}
/// get the width
float getWidth() const {return m_Width;}
/// Set whether new segments are added
void setActive(bool p_Active = true);
/// Get whether new segments are added
bool isActive() const;
/// Get whether there are currently segments in the list
bool isVisible() const;
protected:
/// a trail segment
struct TrailSegment
{
/// start position
Vector3 segmentStart;
/// end position
Vector3 segmentEnd;
/// current segment start color
Ogre::ColourValue segmentStartColor;
/// current segment end color
Ogre::ColourValue segmentEndColor;
}; // end TrailSegment struct declaration
/// typedef for a list of trail segments
typedef std::list<TrailSegment> TrailSegmentList;
/// the list of currently active trail segments
TrailSegmentList m_SegmentList;
/// Initializes the manual object
void init();
/// Uninitializes the manual object
void uninit();
ManualObject* m_TrailObject; //!< the dynamically changed mesh representing the trail
Entity* m_WeaponEntity; //!< the entity representing the weapon;
Node* m_WeaponNode; //!< the node the tracked entity is attached to
SceneNode* m_TrailNode; //!< the node the manual object is attached to
String m_MaterialName; //!< the name of the material to use
const int m_MaxSegmentCount; //!< the maximum number of segments the trail will consist of
Ogre::ColourValue m_SegmentStartInitialColor; //!< the initial color of start segments
Ogre::ColourValue m_SegmentEndInitialColor; //!< the initial color of end segments
Ogre::ColourValue m_SegmentStartColorChange; //!< how the color of start segments will change over time
Ogre::ColourValue m_SegmentEndColorChange; //!< how the color of end segments will change over time
float m_Width; //!< the width of the trail
bool m_IsActive; //!< flag indicating whether new segments are generated
SceneManager* mSceneMgr;
Ogre::String mName;
}; // end of WeaponTrail class declaration
//.cpp
#include "WeaponTrail.h"
//---------------------------------------------------------------------------//
WeaponTrail::WeaponTrail(Ogre::String name, SceneManager* s )
:m_TrailObject(0),
m_MaxSegmentCount(30),
mSceneMgr(s),
m_IsActive(true)
{
m_SegmentStartColorChange = Ogre::ColourValue(1.0,1.0,1.0,1.0);
m_SegmentEndColorChange = Ogre::ColourValue(1.0,1.0,1.0,1.0);
m_SegmentStartInitialColor = Ogre::ColourValue(0.6,0.5,0.8,1);
m_SegmentEndInitialColor = Ogre::ColourValue(1.0,0.2,1.0,1);
m_SegmentStartColorChange *= 3.0;
m_SegmentEndColorChange *= 3.0;
m_Width = 30.0;
setWeaponEntity(0);
init();
}
//---------------------------------------------------------------------------//
WeaponTrail::~WeaponTrail()
{
uninit();
}
//---------------------------------------------------------------------------//
void WeaponTrail::init()
{
// create object
m_TrailObject =
mSceneMgr->createManualObject(mName);
m_TrailObject->estimateVertexCount(m_MaxSegmentCount * 2);
m_TrailObject->setDynamic(true);
m_TrailObject->begin("mat_trail", Ogre::RenderOperation::OT_TRIANGLE_STRIP);
// fill the object (the actual data does not matter here)
for(int i=0; i<m_MaxSegmentCount; ++i)
{
m_TrailObject->position(0, 0, -i*20);
m_TrailObject->textureCoord(0,0);
m_TrailObject->colour(1,0,0,1);
m_TrailObject->position(0, 30, -i*20);
m_TrailObject->textureCoord(1,0);
m_TrailObject->colour(1,0,0,1);
}
m_TrailObject->end();
// create node and attach object
m_TrailNode =
mSceneMgr->getRootSceneNode()->createChildSceneNode();
m_TrailNode->attachObject(m_TrailObject);
m_TrailObject->setVisible(false);
}
//---------------------------------------------------------------------------//
void WeaponTrail::uninit()
{
m_IsActive = false;
// detach object and remove node
m_TrailNode->detachObject(m_TrailObject);
mSceneMgr->getRootSceneNode()->
removeAndDestroyChild(m_TrailNode->getName());
// remove object
m_TrailObject->setVisible(false);
mSceneMgr->destroyManualObject(m_TrailObject);
}
//---------------------------------------------------------------------------//
void WeaponTrail::setWeaponEntity(Entity* p_WeaponEntity)
{
m_WeaponEntity = p_WeaponEntity;
if (m_WeaponEntity)
{
m_WeaponNode = m_WeaponEntity->getParentNode();
}
else
{
m_WeaponNode = 0;
}
}
//---------------------------------------------------------------------------//
void WeaponTrail::onUpdate(float p_DeltaT)
{
// early out
if(!isActive() && !isVisible())
{
return;
}
if (!m_WeaponEntity || !m_WeaponNode)
{
return;
}
if (!m_TrailObject)
{
return;
}
m_TrailObject->setVisible(true);
// iterate over the current segments, apply alpha change
for(TrailSegmentList::iterator it = m_SegmentList.begin();
it != m_SegmentList.end();)
{
(*it).segmentStartColor -= m_SegmentStartColorChange * p_DeltaT;
(*it).segmentEndColor -= m_SegmentEndColorChange * p_DeltaT;
(*it).segmentStartColor.saturate();
(*it).segmentEndColor.saturate();
if((*it).segmentStartColor == Ogre::ColourValue::ZERO && (*it).segmentEndColor == Ogre::ColourValue::ZERO)
{
it = m_SegmentList.erase(it);
}
else
{
++it;
}
}
// throw away the last element if the maximum number of segments is used
if(m_SegmentList.size() >= m_MaxSegmentCount)
{
m_SegmentList.pop_back();
}
// only add a new segment if active
if(isActive())
{
// the segment to add to the trail
TrailSegment newSegment;
// initial the trail
newSegment.segmentStartColor = getSegmentStartInitialColor();
newSegment.segmentEndColor = getSegmentEndInitialColor();
newSegment.segmentStart = m_WeaponNode->_getDerivedPosition();
Vector3 pos = m_WeaponNode->getPosition();
// probably quite costly way to get the second position
m_WeaponNode->translate(Vector3(0, m_Width, 0), SceneNode::TS_LOCAL);
newSegment.segmentEnd = m_WeaponNode->_getDerivedPosition();
m_WeaponNode->setPosition(pos);
Vector3 _verDir = newSegment.segmentEnd - newSegment.segmentStart;
_verDir.normalise();
newSegment.segmentEnd = newSegment.segmentStart + _verDir * m_Width;
m_SegmentList.push_front(newSegment);
}
// update the manual object
m_TrailObject->beginUpdate(0);
int segmentCount = 0;
for(TrailSegmentList::iterator it = m_SegmentList.begin();
it != m_SegmentList.end(); ++it)
{
m_TrailObject->position((*it).segmentStart);
m_TrailObject->textureCoord(0,0);
m_TrailObject->colour((*it).segmentStartColor);
m_TrailObject->position((*it).segmentEnd);
m_TrailObject->textureCoord(1,0);
m_TrailObject->colour((*it).segmentEndColor);
++segmentCount;
}
// use the last position to render the invisible part of the trail
// as degenerate triangles
Vector3 lastPos = Vector3::ZERO;
if(!m_SegmentList.empty())
{
lastPos = m_SegmentList.back().segmentStart;
}
for(int i=segmentCount*2;i<m_MaxSegmentCount * 2;++i)
{
m_TrailObject->position(lastPos);
}
// end the update
m_TrailObject->end();
}
//---------------------------------------------------------------------------//
void WeaponTrail::setMaterialName(const String& p_MaterialName)
{
m_MaterialName = p_MaterialName;
if(m_TrailObject)
{
m_TrailObject->setMaterialName(0, m_MaterialName);
}
}
//---------------------------------------------------------------------------//
void WeaponTrail::setSegmentStartColorChange(const Ogre::ColourValue& p_ColorChange)
{
m_SegmentStartColorChange = p_ColorChange;
}
//---------------------------------------------------------------------------//
const Ogre::ColourValue& WeaponTrail::getSegmentStartColorChange() const
{
return m_SegmentStartColorChange;
}
//---------------------------------------------------------------------------//
void WeaponTrail::setSegmentEndColorChange(const Ogre::ColourValue& p_ColorChange)
{
m_SegmentEndColorChange = p_ColorChange;
}
//---------------------------------------------------------------------------//
const Ogre::ColourValue& WeaponTrail::getSegmentEndColorChange() const
{
return m_SegmentEndColorChange;
}
//---------------------------------------------------------------------------//
void WeaponTrail::setSegmentStartInitialColor(const Ogre::ColourValue& p_Color)
{
m_SegmentStartInitialColor = p_Color;
}
//---------------------------------------------------------------------------//
const Ogre::ColourValue& WeaponTrail::getSegmentStartInitialColor() const
{
return m_SegmentStartInitialColor;
}
//---------------------------------------------------------------------------//
void WeaponTrail::setSegmentEndInitialColor(const Ogre::ColourValue& p_Color)
{
m_SegmentEndInitialColor = p_Color;
}
//---------------------------------------------------------------------------//
const Ogre::ColourValue& WeaponTrail::getSegmentEndInitialColor() const
{
return m_SegmentEndInitialColor;
}
//---------------------------------------------------------------------------//
void WeaponTrail::setActive(bool p_Active)
{
m_IsActive = p_Active;
}
//---------------------------------------------------------------------------//
bool WeaponTrail::isActive() const
{
return m_IsActive;
}
//---------------------------------------------------------------------------//
bool WeaponTrail::isVisible() const
{
return !m_SegmentList.empty();
}
//---------------------------------------------------------------------------//