Jin

In me the tiger sniffs the rose.

11 Feb 2009

Ogre WeaponTrail

3d


A better realization of knife light class, here the idea is very worthy of learning. It can also be used to achieve ribbons.

WeaponTrail.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

WeaponTrail.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();
}
//---------------------------------------------------------------------------//