Line3D
From Ogre Wiki
This is a fine code snippet to create a line in 3D space.
Independent of distance to the camera, it's always visible with one pixel width (unless there is no object between).
ManualObject* myManualObject = mSceneMgr->createManualObject("manual1");
SceneNode* myManualObjectNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("manual1_node");
MaterialPtr myManualObjectMaterial = MaterialManager::getSingleton().create("manual1Material","debugger");
myManualObjectMaterial->setReceiveShadows(false);
myManualObjectMaterial->getTechnique(0)->setLightingEnabled(true);
myManualObjectMaterial->getTechnique(0)->getPass(0)->setDiffuse(0,0,1,0);
myManualObjectMaterial->getTechnique(0)->getPass(0)->setAmbient(0,0,1);
myManualObjectMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(0,0,1);
myManualObject->begin("manual1Material", Ogre::RenderOperation::OT_LINE_LIST);
myManualObject->position(3, 2, 1);
myManualObject->position(4, 1, 0);
// etc
myManualObject->end();
myManualObjectNode->attachObject(myManualObject);
See also
Old version
Derived from code posted in the community previously:
Line3D.h
#ifndef __LINE3D_H__
#define __LINE3D_H__
#include "Ogre.h"
#include <vector>
using namespace Ogre;
using namespace std;
#define POSITION_BINDING 0
#define TEXCOORD_BINDING 1
class Line3D:public SimpleRenderable
{
public:
Line3D(void);
~Line3D(void);
void addPoint(const Vector3 &p);
const Vector3 &getPoint(unsigned short index) const;
unsigned short getNumPoints(void) const;
void updatePoint(unsigned short index, const Vector3 &value);
void drawLine(Vector3 &start, Vector3 &end);
void drawLines(void);
Real getSquaredViewDepth(const Camera *cam) const;
Real getBoundingRadius(void) const;
protected:
//void getWorldTransforms(Matrix4 *xform) const;
const Quaternion &getWorldOrientation(void) const;
const Vector3 &getWorldPosition(void) const;
vector<Vector3> mPoints;
bool mDrawn;
};
#endif /* __LINE3D_H__ */
Line3D.cpp
#include "Line3D.h"
Line3D::Line3D(void)
{
mRenderOp.vertexData = new VertexData();
mDrawn = false;
this->setMaterial("BaseWhiteNoLighting");
}
Line3D::~Line3D(void)
{
delete mRenderOp.vertexData;
}
void Line3D::addPoint(const Vector3 &p)
{
mPoints.push_back(p);
}
const Vector3 &Line3D::getPoint(unsigned short index) const
{
assert(index < mPoints.size() && "Point index is out of bounds!!");
return mPoints[index];
}
unsigned short Line3D::getNumPoints(void) const
{
return (unsigned short)mPoints.size();
}
void Line3D::updatePoint(unsigned short index, const Vector3 &value)
{
assert(index < mPoints.size() && "Point index is out of bounds!!");
mPoints[index] = value;
}
void Line3D::drawLine(Vector3 &start, Vector3 &end)
{
if(mPoints.size())
mPoints.clear();
mPoints.push_back(start);
mPoints.push_back(end);
drawLines();
}
void Line3D::drawLines(void)
{
if(mDrawn)
return;
else
mDrawn = true;
// Initialization stuff
mRenderOp.indexData = 0;
mRenderOp.vertexData->vertexCount = mPoints.size();
mRenderOp.vertexData->vertexStart = 0;
mRenderOp.operationType = RenderOperation::OT_LINE_STRIP; // OT_LINE_LIST, OT_LINE_STRIP
mRenderOp.useIndexes = false;
VertexDeclaration *decl = mRenderOp.vertexData->vertexDeclaration;
VertexBufferBinding *bind = mRenderOp.vertexData->vertexBufferBinding;
decl->addElement(POSITION_BINDING, 0, VET_FLOAT3, VES_POSITION);
HardwareVertexBufferSharedPtr vbuf =
HardwareBufferManager::getSingleton().createVertexBuffer(
decl->getVertexSize(POSITION_BINDING),
mRenderOp.vertexData->vertexCount,
HardwareBuffer::HBU_STATIC_WRITE_ONLY);
bind->setBinding(POSITION_BINDING, vbuf);
// Drawing stuff
int size = mPoints.size();
Vector3 vaabMin = mPoints[0];
Vector3 vaabMax = mPoints[0];
Real *prPos = static_cast<Real*>(vbuf->lock(HardwareBuffer::HBL_DISCARD));
for(int i = 0; i < size; i++)
{
*prPos++ = mPoints[i].x;
*prPos++ = mPoints[i].y;
*prPos++ = mPoints[i].z;
if(mPoints[i].x < vaabMin.x)
vaabMin.x = mPoints[i].x;
if(mPoints[i].y < vaabMin.y)
vaabMin.y = mPoints[i].y;
if(mPoints[i].z < vaabMin.z)
vaabMin.z = mPoints[i].z;
if(mPoints[i].x > vaabMax.x)
vaabMax.x = mPoints[i].x;
if(mPoints[i].y > vaabMax.y)
vaabMax.y = mPoints[i].y;
if(mPoints[i].z > vaabMax.z)
vaabMax.z = mPoints[i].z;
}
vbuf->unlock();
mBox.setExtents(vaabMin, vaabMax);
}
Real Line3D::getSquaredViewDepth(const Camera *cam) const
{
Vector3 vMin, vMax, vMid, vDist;
vMin = mBox.getMinimum();
vMax = mBox.getMaximum();
vMid = ((vMin - vMax) * 0.5) + vMin;
vDist = cam->getDerivedPosition() - vMid;
return vDist.squaredLength();
}
Real Line3D::getBoundingRadius(void) const
{
return Math::Sqrt(max(mBox.getMaximum().squaredLength(), mBox.getMinimum().squaredLength()));
//return mRadius;
}
/*
void Line3D::getWorldTransforms(Matrix4 *xform) const
{
// return identity matrix to prevent parent transforms
*xform = Matrix4::IDENTITY;
}
*/
const Quaternion &Line3D::getWorldOrientation(void) const
{
return Quaternion::IDENTITY;
}
const Vector3 &Line3D::getWorldPosition(void) const
{
return Vector3::ZERO;
}
Somewhere inside a scene
Line3D *myLine = new Line3D(); myLine->addPoint(Vector3(0.0, 9.6, 0.0)); myLine->addPoint(Vector3(160.0, 9.6, 0.0)); myLine->addPoint(Vector3(160.0, 9.6, 160.0)); myLine->addPoint(Vector3(0.0, 9.6, 160.0)); myLine->addPoint(Vector3(0.0, 9.6, 0.0)); myLine->drawLines(); SceneNode *myNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); myNode->attachObject(myLine);
Notes:
- Based on a combination of SimpleSpline and WireBoundingBox.
- No ability to batch add points yet (a simple loop through a vector should do the trick).
- I haven't figured out how to make changes to the points and then rebuild the buffer (hence the bool to prevent attempting to redraw). I'm extremely green when it comes to hardware buffers (as you can probably tell by looking at my code here).
- Simply uncomment the lines for getWorldTransforms() to disable movement and rotation.
Something to be careful of here is how you have defined Real. If Real is not Float, this code may not work as you expect. If Real is Double you may have problems (probably will depend on your graphics card), but some graphics cards only support Float. Actually with Real defined as Double, the program above can throw errors upon exiting the application.
Here is an alternative piece of code. It doesn't use vbuf->lock() and unlock() [not sure of the difference - probably will work with lock]. mDataBuffer is defined as pointer to float.
void Line3D::drawLines(void)
{
if(mDrawn)
return;
else
mDrawn = true;
// Initialization stuff
mRenderOp.indexData = 0;
mRenderOp.vertexData->vertexCount = mPoints.size();
mRenderOp.vertexData->vertexStart = 0;
mRenderOp.operationType = RenderOperation::OT_POINT_LIST; // OT_POINT_LIST; // OT_LINE_LIST, OT_LINE_STRIP
mRenderOp.useIndexes = false;
VertexDeclaration *decl = mRenderOp.vertexData->vertexDeclaration;
VertexBufferBinding *bind = mRenderOp.vertexData->vertexBufferBinding;
size_t offset;
offset = 0;
decl->addElement(0, offset, VET_FLOAT3, VES_POSITION);
offset += VertexElement::getTypeSize(VET_FLOAT3);
HardwareVertexBufferSharedPtr vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
3*sizeof(float),
mRenderOp.vertexData->vertexCount,
HardwareBuffer::HBU_STATIC_WRITE_ONLY);
bind->setBinding(0, vbuf);
// Drawing stuff
int size = mPoints.size();
Vector3 vaabMin = mPoints[0];
Vector3 vaabMax = mPoints[0];
float *prPos;
mDataBuffer=0;
mDataBuffer = new float[size * 3];
prPos = &mDataBuffer[0];
for(int i = 0; i < size; i++)
{
*prPos++ = mPoints[i].x;
*prPos++ = mPoints[i].y;
*prPos++ = mPoints[i].z;
if(mPoints[i].x < vaabMin.x)
vaabMin.x = mPoints[i].x;
if(mPoints[i].y < vaabMin.y)
vaabMin.y = mPoints[i].y;
if(mPoints[i].z < vaabMin.z)
vaabMin.z = mPoints[i].z;
if(mPoints[i].x > vaabMax.x)
vaabMax.x = mPoints[i].x;
if(mPoints[i].y > vaabMax.y)
vaabMax.y = mPoints[i].y;
if(mPoints[i].z > vaabMax.z)
vaabMax.z = mPoints[i].z;
}
// update buffer
vbuf->writeData(0, vbuf->getSizeInBytes(), mDataBuffer);
mBox.setExtents(vaabMin, vaabMax);
}
The same will apply for the dynamic lines examples in this Wiki.

