This is a derived SceneNode class which allows you to quickly create a scene node for a static 3D path by generating a collection of vertices and edges that sample the path's defining function. Probably that's not a good explanation, so this should help:


Note that these are not wire-frames of predefined models, they are generated programmatically from a coded function.
UPDATE: Added code to generate bounding box in constructor, Removed unnecessary grab() in constructor (thanks vitek)
The code for the class is here:
CPathNode.h
Code: Select all
/**
* \file CPathNode.h
* \date: Aug 4, 2009
* \brief:
*
* detail:
*/
#ifndef CPATHNODE_H_
#define CPATHNODE_H_
#include <irrlicht.h>
#include "CIndexedPrimitiveNode.h"
#include "IVectorFunction.h"
namespace irr
{
namespace scene
{
/**
* A PathNode is a scene node which contains a visible path, which is a thin
* line represented in the visual system as line segments connecting vertices.
* The path is defined by a three dimensional function of a single parameter
* (often time).
*/
class CPathNode : public CIndexedPrimitiveNode
{
private:
SMeshBuffer *m_pMeshBuf;
public:
/**
* \brief generates a collection of vertices from the supplied
* function over the supplied range and with the supplied
* resolution
*
* \param parent the parent node to this node in the scene graph
* \param mgr the scene manager managing this node
* \param id the id of this node (may be -1)
* \param first the start value of the scalar input parameter
* \param last the end value of the scalar input parameter
* \param nSegments the number of line segments to generate
* \return
*/
CPathNode( ISceneNode* parent, ISceneManager* mgr,
s32 id, core::IVectorFunction *function,
f32 first, f32 last, u32 nSegments );
/**
* \brief destroys the generated collection of vertices
*/
virtual ~CPathNode();
};
}
}
#endif /* CPATHNODE_H_ */
CPathNode.cpp
Code: Select all
/**
* \file CPathNode.cpp
* \author: Joshua J Bialkowski (jbialk@mit.edu)
* \date: Aug 4, 2009
* \brief:
*
* detail:
*/
#include <iostream>
#include "CPathNode.h"
using namespace irr;
using namespace scene;
using namespace core;
/**
*
* \todo: update bounding box prior to rendering, either by overloading the
* render() function for CPathNode, or by updating it in the
* constructor
*/
CPathNode::CPathNode( ISceneNode* parent, ISceneManager* mgr,
s32 id, IVectorFunction *function,
f32 first, f32 last, u32 nSegments ) :
CIndexedPrimitiveNode( parent, mgr, id, 0, nSegments, EPT_LINE_STRIP),
m_pMeshBuf(new SMeshBuffer())
{
u32 nIndices = nSegments+1;
vector3df min = function->f(first);
vector3df max = function->f(first);
SMeshBuffer& meshBuf = *m_pMeshBuf;
meshBuf.Vertices.set_used(nIndices);
meshBuf.Indices.set_used(nIndices);
// map the indices to their index
for (u32 i = 0; i < nIndices; ++i)
meshBuf.Indices[i] = i;
// define the step size
f32 step = (last-first)/nSegments;
// define the vertex positions
for (u32 i = 0; i < nIndices; ++i)
{
vector3df point = function->f(first + i*step);
meshBuf.Vertices[i].Pos = point;
if( point.X < min.X )
min.X = point.X;
if( point.Y < min.Y )
min.Y = point.Y;
if( point.Z < min.Z )
min.Z = point.Z;
if( point.X > max.X )
max.X = point.X;
if( point.Y > max.Y )
max.Y = point.Y;
if( point.Z > max.Z )
max.Z = point.Z;
}
aabbox3df bounds( min, max );
meshBuf.setBoundingBox( bounds );
setNewMesh(m_pMeshBuf, nSegments);
}
CPathNode::~CPathNode()
{
m_pMeshBuf->drop();
}
CIndexedPrimitiveNode.h
Code: Select all
/**
* \file CIndexedPrimitiveNode.h
* \date: Aug 4, 2009
* \brief:
*
* detail:
*/
#pragma once
#include <ISceneNode.h>
#include "CMeshBuffer.h"
namespace irr
{
namespace scene
{
/**
* A scene node which is composed of indexed primitives for drawing a particle
* cloud or line drawing
*/
class CIndexedPrimitiveNode : public ISceneNode
{
public:
/**
* \brief Creates the scene node from a pre-existing collection of
* vertices as an object of the IMeshBuffer interface
*
* \param parent the parent scene node
* \param mgr the scene manager for this node
* \param id the nodes id
* \param pMesh pointer to the collection of vertices to
* use
* \param primitiveCount the number of primitives that are defined by
* the vertices in the MeshBuffer
*/
CIndexedPrimitiveNode(ISceneNode* parent,
ISceneManager* mgr,
s32 id,
IMeshBuffer* pMesh,
u32 primitiveCount,
E_PRIMITIVE_TYPE primitiveType = EPT_LINES);
/**
* \brief drops grabbed references
*/
~CIndexedPrimitiveNode();
/**
* \brief redefine the underlying mesh buffer that this node contains
* \param pMesh pointer to an object implementing the
* IMeshBuffer interface
* \param primitiveCount the number of primitives stored in the mesh
* buffer
*/
void setNewMesh(IMeshBuffer* pMesh, u32 primitiveCount)
{
if(m_pMesh)
m_pMesh->drop();
m_pMesh = pMesh;
m_pMesh->grab();
m_primitiveCount = primitiveCount;
}
/**
* \brief redefine the primitive type that the underlying mesh buffer
* represents
* \param type member of the E_PRIMITIVE_TYPE union specifiying the
* primative type of the underlying mesh buffer
*/
void setPrimitiveType(E_PRIMITIVE_TYPE type) { m_primitiveType = type; }
/**
* \brief ensures that this node is registered with the renderer
* \see irr::scene::ISceneNode::OnRegisterSceneNode()
*/
virtual void OnRegisterSceneNode();
/**
* \brief renders this node
* \see irr::scene::ISceneNode::render()
*/
virtual void render();
/**
* \brief returns the bounding box that defines a region that is
* guarenteed to contain all of the geometry of this node
* \return the bounding box
* \see irr::scene::ISceneNode::getBoundingBox()
*/
virtual const core::aabbox3d<f32>& getBoundingBox() const;
/**
* \brief returns the number of materials used by this node, which is
* incidentally only one
* \return 1, there is only one material
* \see irr::scene::ISceneNode::getMatrialCount()
*/
virtual u32 getMaterialCount() const;
/**
* \brief return a reference to the [i]th material of this node
* \param i the index of the material to return
* \return a reference to the [i]th material
*/
virtual video::SMaterial& getMaterial(u32 i);
private:
IMeshBuffer* m_pMesh; ///< pointer to the underlying
/// mesh buffer
E_PRIMITIVE_TYPE m_primitiveType; ///< defines how to interpret
/// the underlying mesh buffer
u32 m_primitiveCount; ///< number of total things to
/// draw
};
}
}
Code: Select all
/**
* \file CIndexedPrimitiveNode.cpp
* \author: Joshua J Bialkowski (jbialk@mit.edu)
* \date: Aug 4, 2009
* \brief:
*
* detail:
*/
#include "CIndexedPrimitiveNode.h"
#include "ISceneManager.h"
#include "IVideoDriver.h"
using namespace irr;
using namespace scene;
using namespace core;
CIndexedPrimitiveNode::CIndexedPrimitiveNode(
ISceneNode* parent,
ISceneManager* mgr,
s32 id,
IMeshBuffer* pMesh,
u32 primitiveCount,
E_PRIMITIVE_TYPE primitiveType):
ISceneNode(parent, mgr, id),
m_pMesh(pMesh),
m_primitiveType(primitiveType),
m_primitiveCount(primitiveCount)
{
if(pMesh)
pMesh->grab();
}
CIndexedPrimitiveNode::~CIndexedPrimitiveNode()
{
if(m_pMesh)
m_pMesh->drop();
}
void CIndexedPrimitiveNode::OnRegisterSceneNode()
{
if (IsVisible) SceneManager->registerNodeForRendering(this);
ISceneNode::OnRegisterSceneNode();
}
void CIndexedPrimitiveNode::render()
{
if(!m_pMesh)
return;
if (!m_pMesh->getVertexCount() || !m_pMesh->getIndexCount()) return;
video::IVideoDriver* driver = SceneManager->getVideoDriver();
driver->setMaterial(m_pMesh->getMaterial());
driver->setTransform(video::ETS_WORLD,AbsoluteTransformation);
driver->drawVertexPrimitiveList(m_pMesh->getVertices(),
m_pMesh->getVertexCount(),
m_pMesh->getIndices(),
m_primitiveCount,
m_pMesh->getVertexType(),
m_primitiveType,
m_pMesh->getIndexType());
}
/**
* \todo: what happens if m_pMesh is not yet defined?
*/
const aabbox3d<f32>& CIndexedPrimitiveNode::getBoundingBox() const
{
return m_pMesh->getBoundingBox();
}
u32 CIndexedPrimitiveNode::getMaterialCount() const
{
return 1;
}
/**
* \todo: what happens if m_pMesh is not yet defined?
*/
video::SMaterial& CIndexedPrimitiveNode::getMaterial(u32 i)
{
return m_pMesh->getMaterial();
}
IVectorFunction.h
Code: Select all
/**
* \file IVectorFunction.h
* \date: Aug 4, 2009
* \brief:
*
* detail:
*/
#ifndef IVECTORFUNCTION_H_
#define IVECTORFUNCTION_H_
#include <irrlicht.h>
namespace irr
{
namespace core
{
/**
* Interface for any object that maps a scalar input to a three dimensional
* vector output. The reason this is an interface, rather than just using
* a function pointer in it's place, is that the function may be parameterized
* by certain other static values.
*/
class IVectorFunction
{
public:
/**
* \brief function that takes a scalar input and returns a 3d vector
* value
* \param t scalar input parameter
* \return the value of the function evaluated at [t]
*/
virtual vector3df f( f32 t ) = 0;
};
}
}
#endif /* IVECTORFUNCTION_H_ */