More line drawing options

You are an experienced programmer and have a problem with the engine, shaders, or advanced effects? Here you'll get answers.
No questions about C++ programming or topics which are answered in the tutorials!
Post Reply
MolokoTheMole
Posts: 109
Joined: Tue Jan 09, 2007 1:18 pm

More line drawing options

Post by MolokoTheMole »

I would like some more options to draw 3D lines. Can you guide me how to do it?

I'd like these features:
1. Use alpha channel when drawing line (setting it in the color doesn't work)
2. Antialiasing
3. dotted line / segmented line / textured line ?
4. Gradient colored line
Crimson Glory full Irrlicht game source code!
What I Do - my blog & dev log
Currently developing Link-Dead
Radikalizm
Posts: 1215
Joined: Tue Jan 09, 2007 7:03 pm
Location: Leuven, Belgium

Post by Radikalizm »

Line drawing is done by uploading 2 vertices and drawing them as a linelist
This means that a line is actually just a piece of geometry to which shaders can be applied

This would also mean that a dotted line or a transparent line would have to be drawn in a transparent render pass, and this would kind of wreck the current implementation

You shouldn't see the line drawing function in irrlicht as a tool to create visual effects, since its actually meant for debugging (drawing bounding boxes, normals, ...)

If you want 3D lines with fancy effects and what not, I'd suggest you implement a scene node for it
zillion42
Posts: 324
Joined: Wed Aug 29, 2007 12:32 am
Location: Hamburg, Germany

Post by zillion42 »

I'd love vertex colors with alpha working on the drawIndexedPrimitiveList aswell. I mean of course color works, but alpha doesn't. For segmented lines, its not so hard to program.

In fact I have a snippet. There is this node that someone made long time ago, CIndexedPrimitiveNode and you can use it with the following function to make really long lines from an array of vector3df's. Unfortunately as it looks I've removed the dottet option, but if you try, it's really not that hard

EDIT: Gradient colors work of course, aswell as antialiasing.

For an implementation with gradient colors I have another function, where velocity represents color, but you also need an HSV to RGB function, I'll post both below... Also it takes core::array< core::array<f64> > as input where the inner array is just triplets of f64's instead of vector3df's

Code: Select all

scene::ISceneNode* makeLine(core::array<core::vector3df> positions, video::SColor color, f32 thickness)
{
	scene::ISceneNode* returnNode = smgr->addEmptySceneNode();


	u32 originalSize = 2000;
	u32 SegmentsNeeded = core::ceil32( ((f32)positions.size()/(f32)originalSize) );

	u32 SegmentSize = 2000;
	u32 finishedSegments = 2000;

	if(SegmentsNeeded == 1)
	{
		SegmentSize = positions.size();
		finishedSegments = positions.size();
	}

	for(u32 i=0; i<SegmentsNeeded; i++)
	{
		scene::SMeshBuffer *segmentBuffer = new scene::SMeshBuffer();

		for(u32 j=0; j<SegmentSize; j++)
		{
			segmentBuffer->Indices.push_back(j);

			if(j !=0 && j != positions.size() - 1)
				segmentBuffer->Indices.push_back(j);

			segmentBuffer->Vertices.push_back(video::S3DVertex(
				positions[i*originalSize+j].X,
				positions[i*originalSize+j].Y,
				positions[i*originalSize+j].Z,
				1,1,1,
				color,
				1,1));
		}

		segmentBuffer->getMaterial().Thickness = thickness;

		CIndexedPrimitiveNode* segNode = new CIndexedPrimitiveNode(returnNode,smgr,-1,segmentBuffer,
			segmentBuffer->Indices.size()/2,
			scene::EPT_LINES);

		segNode->setMaterialFlag(video::EMF_LIGHTING, false);
		segNode->setMaterialFlag(video::EMF_BACK_FACE_CULLING, false);

		if(finishedSegments + 2000 < positions.size())
		{
			finishedSegments += 2000;
		}
		else
		{
			u32 remainder = positions.size() - finishedSegments;
			SegmentSize = remainder;
		}
	}

	return returnNode;
}

Code: Select all

#include "IndexedPrimitiveNode.h"
#include "ISceneManager.h"
#include "IVideoDriver.h"


using namespace irr;
using namespace scene;

//
CIndexedPrimitiveNode::CIndexedPrimitiveNode(irr::scene::ISceneNode* parent,
											 irr::scene::ISceneManager* mgr,
											 irr::s32 id,
											 scene::SMeshBuffer* pMesh,
											 irr::u32 primitiveCount,
											 irr::scene::E_PRIMITIVE_TYPE primitiveType) : scene::ISceneNode(parent,
																						mgr,id),
																						m_pMesh(pMesh),
																						m_primitiveCount(primitiveCount),
																						m_primitiveType(primitiveType)
{
	
	this->setAutomaticCulling(EAC_OFF);
	//pMesh->grab();
	//m_primitiveType  = scene::EPT_LINES;   
}


//
CIndexedPrimitiveNode::~CIndexedPrimitiveNode()
{
   m_pMesh->drop();
   //this->remove();
}

//
void CIndexedPrimitiveNode::OnRegisterSceneNode()
{
   if (IsVisible)
	   SceneManager->registerNodeForRendering(this, ESNRP_SOLID);

   ISceneNode::OnRegisterSceneNode();
}

//
void CIndexedPrimitiveNode::render()
{
   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());   

}

//
const core::aabbox3d<f32>& CIndexedPrimitiveNode::getBoundingBox() const
{
   return m_pMesh->getBoundingBox();
}

//
irr::u32 CIndexedPrimitiveNode::getMaterialCount() const
{
   return 1;
}

//
irr::video::SMaterial& CIndexedPrimitiveNode::getMaterial(irr::u32 i)
{
   return m_pMesh->getMaterial();
} 

Code: Select all

#pragma once

#include <ISceneNode.h>
#include "CMeshBuffer.h"

//////////////////////////////////////////////////////////////////////////////////
//Frei nach http://irrlicht.sourceforge.net/docu/example003.html


//
class CIndexedPrimitiveNode : public irr::scene::ISceneNode
{
   public:
      //
      CIndexedPrimitiveNode(irr::scene::ISceneNode* parent,
							irr::scene::ISceneManager* mgr,
							irr::s32 id,
							irr::scene::SMeshBuffer* pMesh,
							irr::u32 primitiveCount,
							irr::scene::E_PRIMITIVE_TYPE primitiveType);
      ~CIndexedPrimitiveNode();

      //
      void setNewMesh(irr::scene::SMeshBuffer* pMesh,irr::u32 primitiveCount)
      {
         m_pMesh->drop();
         m_pMesh = pMesh;
         m_pMesh->grab();
         m_primitiveCount = primitiveCount;
      }

      //
      void setPrimitiveType(irr::scene::E_PRIMITIVE_TYPE type) { m_primitiveType = type; }

      //zu ¸berschreiben aus Basisklasse
      virtual void OnRegisterSceneNode();
       
      //zu ¸berschreiben aus Basisklasse
      virtual void render();

      //zu ¸berschreiben aus Basisklasse
      virtual const irr::core::aabbox3d<irr::f32>& getBoundingBox() const;

      //zu ¸berschreiben aus Basisklasse
      virtual irr::u32 getMaterialCount() const;

      //zu ¸berschreiben aus Basisklasse
      virtual irr::video::SMaterial& getMaterial(irr::u32 i);


   private:
      //das zu rendernde Mesh samt Material
      irr::scene::SMeshBuffer* m_pMesh;
      //der gew‰hlte Primitiv-Typ
      irr::scene::E_PRIMITIVE_TYPE m_primitiveType;
      //Anzahl der zu rendernden Primitive
      irr::u32 m_primitiveCount;
}; 

Code: Select all

scene::ISceneNode* makeLineDouble(core::array< core::array<f64> > positions, core::array< core::array<f64> > velocity, video::SColor color, f32 thickness)
{
	scene::ISceneNode* returnNode = smgr->addEmptySceneNode();


	u32 originalSize = 2000;
	u32 SegmentsNeeded = core::ceil32( ((f32)positions.size()/(f32)originalSize) );

	u32 SegmentSize = 2000;
	u32 finishedSegments = 2000;

	if(SegmentsNeeded == 1)
	{
		SegmentSize = positions.size();
		finishedSegments = positions.size();
	}
	
	f64 max = 0;

	for(u32 v=0; v<velocity.size(); v++)
	{
		f64 current = mag(velocity[v]);
		if(current > max)
			max = current;
	}

	for(u32 i=0; i<SegmentsNeeded; i++)
	{
		scene::SMeshBuffer *segmentBuffer = new scene::SMeshBuffer();

		for(u32 j=0; j<SegmentSize; j++)
		{
			segmentBuffer->Indices.push_back(j);

			if(j !=0 && j != positions.size() - 1)
				segmentBuffer->Indices.push_back(j);
			
			f64 currentVel = mag(velocity[i*originalSize+j]);
			f64 percentVel = currentVel/max;
			f32 red,green,blue;

			HSVtoRGB(&red,&green,&blue,percentVel*360,1,1);
			video::SColor color3 = video::SColor(255,red*255,green*255,blue*255);
			
			segmentBuffer->Vertices.push_back(video::S3DVertex(
				positions[i*originalSize+j][0]/scaleF,
				positions[i*originalSize+j][1]/scaleF,
				positions[i*originalSize+j][2]/scaleF,
				1,1,1,
				color3,
				1,1));
		}

		segmentBuffer->getMaterial().Thickness = thickness;

		CIndexedPrimitiveNode* segNode = new CIndexedPrimitiveNode(returnNode,smgr,-1,segmentBuffer,
			segmentBuffer->Indices.size()/2,
			scene::EPT_LINES);

		segNode->setMaterialFlag(video::EMF_LIGHTING, false);
		segNode->setMaterialFlag(video::EMF_BACK_FACE_CULLING, false);

		if(finishedSegments + 2000 < positions.size())
		{
			finishedSegments += 2000;
		}
		else
		{
			u32 remainder = positions.size() - finishedSegments;
			SegmentSize = remainder;
		}
	}

	return returnNode;
}

Code: Select all

void HSVtoRGB( float *r, float *g, float *b, float h, float s, float v )
{
	int i;
	float f, p, q, t;
	if( s == 0 ) {
		// achromatic (grey)
		*r = *g = *b = v;
		return;
	}
	h /= 60;			// sector 0 to 5
	i = floor( h );
	f = h - i;			// factorial part of h
	p = v * ( 1 - s );
	q = v * ( 1 - s * f );
	t = v * ( 1 - s * ( 1 - f ) );
	switch( i ) {
		case 0:
			*r = v;
			*g = t;
			*b = p;
			break;
		case 1:
			*r = q;
			*g = v;
			*b = p;
			break;
		case 2:
			*r = p;
			*g = v;
			*b = t;
			break;
		case 3:
			*r = p;
			*g = q;
			*b = v;
			break;
		case 4:
			*r = t;
			*g = p;
			*b = v;
			break;
		default:		// case 5:
			*r = v;
			*g = p;
			*b = q;
			break;
	}
}
MolokoTheMole
Posts: 109
Joined: Tue Jan 09, 2007 1:18 pm

Post by MolokoTheMole »

Thanks a lot for the code!
Crimson Glory full Irrlicht game source code!
What I Do - my blog & dev log
Currently developing Link-Dead
Post Reply