axial billboard

Discuss about anything related to the Irrlicht Engine, or read announcements about any significant features or usage changes.
calimero
Posts: 45
Joined: Sun Aug 08, 2004 4:31 pm
Location: Nice, France

axial billboard

Post by calimero »

hello,

today I have some spare time and I make a custom node to have axial billboards (to make stuff like laser or energy ray or just trees over a terrain)

I post my code to show you how I make it, I have no pretention to universality. If severals are interested I can make a more complete stuff with more functionnalities (just ask :) )

sorry I'm french (bad english, bad temper , ...)

a little explication : for a ray the node position is the origin of the ray. the end of the ray is given by position + orientation (orientation is the axis above which the billboard can turn) largeur is the width of the ray. You have to provide a texture (for a ray use an image that blend from black to red to white to red to black, blend from left to right of the image)

here is an image of billboards used to make a sort of grid
Image

include file -edited- now you can use it directly (I hope):

Code: Select all

#ifndef __C_AXIALBB_NODE_H_INCLUDED__
#define __C_AXIALBB_NODE_H_INCLUDED__

// jfh custom node
// this is an axial billboard node

#include <irrlicht.h>

using namespace irr;
using namespace core;
using namespace video;

class CAxialBBNode : public scene::ISceneNode
    {
    public:
    CAxialBBNode(scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id, 
    vector3df orientation, f32 largeur,ITexture* texture);
		
	void OnPreRender();
    void render();
    const core::aabbox3d<f32>& getBoundingBox() const;
    s32 getMaterialCount();
    video::SMaterial& getMaterial(s32 i);
    
    private:
    core::aabbox3d<f32> Box;
	video::S3DVertex vertices[4];
	u16 indices[6];
	video::SMaterial Material;
	vector3df orientation;
	f32 largeur;
    };

#endif
cpp file :

Code: Select all

CAxialBBNode::CAxialBBNode(scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id,
    vector3df orientation, f32 largeur, ITexture* texture)
 : scene::ISceneNode(parent, mgr, id)
    {
    this->orientation = orientation;
    this->largeur = largeur/2;
    
	indices[0] = 0;
	indices[1] = 1;
	indices[2] = 2;
	indices[3] = 0;
	indices[4] = 2;
	indices[5] = 3;
	
	Material.Lighting = false;
    Material.BackfaceCulling = false; 
    this->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
	this->setMaterialTexture(0,texture);
    SColor color = SColor(255,255,255,255);
    vertices[0].TCoords.set(0.0f, 0.0f);
	vertices[0].Color = color;
	vertices[1].TCoords.set(1.0f, 0.0f);
	vertices[1].Color = color;
	vertices[2].TCoords.set(1.0f, 1.0f);
	vertices[2].Color = color;
	vertices[3].TCoords.set(0.0f, 1.0f);
	vertices[3].Color = color;

    }
 

    
    
       
void CAxialBBNode::OnPreRender()
	{
		if (IsVisible)
			SceneManager->registerNodeForRendering(this);

		ISceneNode::OnPreRender();
	}

	
void CAxialBBNode::render()
	{
	ISceneNode* camera = SceneManager->getActiveCamera();
  
	IVideoDriver* driver = SceneManager->getVideoDriver();

	vector3df pos = getAbsolutePosition();
	vector3df campos = camera->getAbsolutePosition();
    vector3df perp = orientation.crossProduct(campos - pos);
    perp.normalize();
    perp *= largeur;
    
    vertices[0].Pos = pos - perp;
	vertices[1].Pos = pos + perp;
	vertices[2].Pos = pos + perp + orientation;
	vertices[3].Pos = pos - perp + orientation;
	
	driver->setMaterial(Material);
	matrix4 mat;
	driver->setTransform(video::ETS_WORLD, mat);
	driver->drawIndexedTriangleList(vertices, 4, indices, 2);

	}

	
const core::aabbox3d<f32>& CAxialBBNode::getBoundingBox() const
	{
		return Box;
	}

s32 CAxialBBNode::getMaterialCount()
	{
		return 1;
	}

video::SMaterial& CAxialBBNode::getMaterial(s32 i)
	{
		return Material;
	}
example of use:

Code: Select all

// essai axial bb
	CAxialBBNode* myNode2 = 0;
    for (int i=0;i<9;i++)
        {
        myNode2 = new CAxialBBNode(smgr->getRootSceneNode(), smgr,1000,vector3df(100,0,0),3,yourtexture);
        myNode2->setPosition(vector3df(-50,i*10,0));
        myNode2->drop();
        }	    
Last edited by calimero on Mon Aug 09, 2004 6:57 pm, edited 2 times in total.
nitroman

Post by nitroman »

cool ! I will try it :D
cmoibenlepro
Posts: 237
Joined: Thu May 27, 2004 3:18 pm
Location: Canada

Post by cmoibenlepro »

I tested it and it compiled fine. I just needed to add the #include<irrlicht> and namspaces in the include file...

If it helps you, I'm using VC++ toolkit 2003 and Relo.

It's a great addition to irrlicht and it does not seem to have bugs.
:D
you should add it to irrlichtNX (they will love it)
knightoflight
Posts: 199
Joined: Sun Aug 24, 2003 5:47 pm
Location: Germany

Post by knightoflight »

please, do you have a nice example-pic, too ?
(Tell me and I'll forget. Show me and I'll remember ... Konfuzius ) ;-)
Guest

Post by Guest »

It's nice some people find my stuff interesting !!!

Sorry for the include file I made a copy paste from a file with several personal nodes and so I forgot all the standard stuff like namespace ...

for a picture example I have one on my disk but don't know where to put it on the web. Have you an idea ? (perhaps some free space where I can upload my pic)

thank for reading.

p.s. For now i just make test with the billboard attached to the root node. I think there may be problems if you put the node as a child of another node.
If I have time I will conduct more tests on it.
calimero
Posts: 45
Joined: Sun Aug 08, 2004 4:31 pm
Location: Nice, France

Post by calimero »

sorry, forgot to log in.

I've edited the post to add a picture, enjoy !!!

p.s. : the 3d models are not made be me :( but are md2 taken from the web.
cmoibenlepro
Posts: 237
Joined: Thu May 27, 2004 3:18 pm
Location: Canada

Post by cmoibenlepro »

great screenshot :D

continue your great work
ManakelArena

Post by ManakelArena »

Hello Calimero,

What kind of game are you working on?

i'm working on a multiplay MedFan arena game and i love your screenshots!!!


PS i'm french too...
calimero
Posts: 45
Joined: Sun Aug 08, 2004 4:31 pm
Location: Nice, France

Post by calimero »

Hi

I want to make a sort of turned based battle with just a few characters, a little bit like battle phase of HOMM2 or golden sun on GBA. It's an opprtunity to play with the irrlicht engine and implement some ideas I want to test.
My main problem is to have 3d characters that look like I want. because I'm not good at modeling and haven't the right softwares & knowledge.
knightoflight
Posts: 199
Joined: Sun Aug 24, 2003 5:47 pm
Location: Germany

Post by knightoflight »

thanks for the code and the pic :)
Very cool !

now i tried and have two questions:
- from some camerapositions the billboard-ray is invisible, a problem
with uv-maps or backfaceculling or such things or im a loser ? you have
the same effect ?
- you use the startposition from a node. Is it easy to change, that the
startposition is a parameter, too and we have a new 3d-line instead
of the normal boring 3d-line ?
the parameters of CAxialBBNode::CAxialBBNode and
the positions in CAxialBBNode::render ?
A better 3D-line would be cool, too.
calimero
Posts: 45
Joined: Sun Aug 08, 2004 4:31 pm
Location: Nice, France

Post by calimero »

hello knightoflight,

I think you can easily alter my code if you want to set the position of the node directly in the constructor. I'm at work and can't test it but try to add

Code: Select all

vector3df pos 
in the parameters of the constructor and simply add the line

Code: Select all

setPosition(pos);  
in the constructor.

for the problem of the billboard invisible at certain position of the camera, I have experimented it sometimes. I think it may occurs if one extremity of the node is too near of the camera position (a sort of near plane clipping ?). Perhaps some irrlicht expert has an explication ?

if you want a 3d line a good idea may be to create a new constructor of the billboard with parameters (point1, point2) instead of (pos,orientation) or just orientation.
I will try it when at home.
Electron
Posts: 874
Joined: Sun Mar 14, 2004 12:05 am
Location: Massachusetts USA

Post by Electron »

Thanks very much, I got it compiled easily (though I modified things a bit to make creating one an action for the scenemanager, as with any other scenenode)

I did notice that when t\close to the camera there were problems with it's angle looking odd (sticking out the wrong way) or being completely invisible. Billboards, however, are not really suited to being viewed closely and it may not be at all easy or even possible to make one that does not move strangely when the camera is close
You do a lot of programming? Really? I try to get some in, but the debugging keeps me pretty busy.

Crucible of Stars
calimero
Posts: 45
Joined: Sun Aug 08, 2004 4:31 pm
Location: Nice, France

Post by calimero »

hello eclectron,

i'm interested to know what you have done. have you add methods like addAxialBBnode to the scenemamanger class ?
It does imply to recomplie Irrlicht, isn't it ?

for the problem of angle, my code may suffer from low/no test. but generally axialbillboard can't look good if the axis of the billboard is near the same as the view of the camera.
Electron
Posts: 874
Joined: Sun Mar 14, 2004 12:05 am
Location: Massachusetts USA

Post by Electron »

Okay, here's what I've done. I've made some changes(not important, simply the way I like doing things better) besides adding the functions to the scenemanager. Things could easily be kept more the way calimero had them, while still being added to the scenemanager. My main unimportant changes are

1) changed the name of the class from CAxialBBNode to CAxialBillboardSceneNode because that seems to me to better follow the naming convention of other nodes and BB always makes me think of bounding box.
3)the constructor no longer deals with the texture. The constructor of no other node takes a texture parameter, so I saw no reasonwhy this one should

IAxialBillboardSceneNode.h as follows. This is the interface class for CAxialBillboardSceneNode

Code: Select all

#ifndef __I_AXIALBB_NODE_H_INCLUDED__ 
#define __I_AXIALBB_NODE_H_INCLUDED__ 

// jfh custom node 
// this is an axial billboard node
//original code by  calimero,slightly modified by me, JAMES

#include "ISceneNode.h"
 

namespace irr
{
namespace scene
{

class IAxialBillboardSceneNode : public ISceneNode 
{ 
public: 
IAxialBillboardSceneNode(scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id,
const core::vector3df& position = core::vector3df(0,0,0) )
: ISceneNode(parent, mgr, id, position) {} 

void OnPreRender()=0; 
void render()=0; 
const core::aabbox3d<f32>& getBoundingBox() const=0; 
s32 getMaterialCount()=0; 
video::SMaterial& getMaterial(s32 i)=0; 
 
}; 

} // end namespace scene
} // end namespace irr

#endif 
CAxialBillboardSceneNode.h

Code: Select all

#ifndef __C_AXIALBB_NODE_H_INCLUDED__ 
#define __C_AXIALBB_NODE_H_INCLUDED__ 

// jfh custom node 
// this is an axial billboard node
//original code by  calimero,slightly modified by me, JAMES

#include "IAxialBillboardSceneNode.h"
#include "S3DVertex.h"
 

namespace irr
{
namespace scene
{

class CAxialBillboardSceneNode : public scene::IAxialBillboardSceneNode 
{ 
public: 
CAxialBillboardSceneNode(scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id, 
core::vector3df position,core::vector3df orientation, f32 width); 

void OnPreRender(); 
void render(); 
const core::aabbox3d<f32>& getBoundingBox() const; 
s32 getMaterialCount(); 
video::SMaterial& getMaterial(s32 i); 

private: 
core::aabbox3d<f32> Box; 
video::S3DVertex vertices[4]; 
u16 indices[6]; 
video::SMaterial Material; 
core::vector3df orientation; 
f32 width; 
}; 

} // end namespace scene
} // end namespace irr

#endif 
CAxialBillboardSceneNode.cpp

Code: Select all

//original code by calimero, modified slightly by me, JAMES
#include "CAxialBillboardSceneNode.h"
#include "IVideoDriver.h"
#include "ISceneManager.h"
#include "ICameraSceneNode.h"
#include "os.h"

namespace irr
{
namespace scene
{

CAxialBillboardSceneNode::CAxialBillboardSceneNode(scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id, 
core::vector3df position,core::vector3df orientation, f32 width) 
: IAxialBillboardSceneNode(parent, mgr, id, position)
{ 
this->orientation = orientation; 
this->width = width/2; 

indices[0] = 0; 
indices[1] = 1; 
indices[2] = 2; 
indices[3] = 0; 
indices[4] = 2; 
indices[5] = 3; 

Material.Lighting = false; 
Material.BackfaceCulling = false; 
this->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);  
video::SColor color = video::SColor(255,255,255,255); 
vertices[0].TCoords.set(0.0f, 0.0f); 
vertices[0].Color = color; 
vertices[1].TCoords.set(1.0f, 0.0f); 
vertices[1].Color = color; 
vertices[2].TCoords.set(1.0f, 1.0f); 
vertices[2].Color = color; 
vertices[3].TCoords.set(0.0f, 1.0f); 
vertices[3].Color = color; 

} 





void CAxialBillboardSceneNode::OnPreRender() 
{ 
   if (IsVisible) 
   SceneManager->registerNodeForRendering(this); 
   
   ISceneNode::OnPreRender(); 
} 


void CAxialBillboardSceneNode::render() 
   { 
   // ok in this function is the interesting stuff 
   // jfh "calimero" 11august2004 nice france 
   // the axial billboard has two end, the first is the position of the node 
   // the other is given by orientation in LOCAL coordinates. 
   // for node attached to rootscenenode it behaves like the previous version 
   // in this version orientation is expressed in local coordinates of the node 
   // I think it's more interesting because it gives a more standard behaviour 
   // if the node is attached to a parent different from rootscenenode 
   // you can also attach animator to the node (like rotation) 
    // and I hope it will behave like you expect 
    // 
    // known problem : node disappears if position gets too near of the camera 
    
   core::vector3df orientationglobal; // to store the end of the billboard in world coordinates 
   core::matrix4 mat; // to get an identity matrix for final render 
   core::matrix4 matnode = getAbsoluteTransformation(); // get the transformation of the node 
    
    ISceneNode* camera = SceneManager->getActiveCamera(); 
     video::IVideoDriver* driver = SceneManager->getVideoDriver(); 
    
    
   core::vector3df pos = getAbsolutePosition(); 
   core::vector3df campos = camera->getAbsolutePosition(); 
   matnode.transformVect(orientation,orientationglobal); 
    core::vector3df perp = (orientationglobal-pos).crossProduct(campos - pos); 
    
    // perhaps here I should test if perp is null before normalize it ? 
    // it doesn't seem to be necessary --> to investigate 
    perp.normalize(); 
    perp *= width; 
      
    // here I update the coordinates of the billboard in GLOBAL space 
    vertices[0].Pos = pos - perp; 
   vertices[1].Pos = pos + perp; 
   vertices[2].Pos = orientationglobal + perp  ; 
   vertices[3].Pos = orientationglobal - perp; 
    
   driver->setMaterial(Material); 
    
   // doesn't seem to be necessary probably the default constructor 
   // build the identity matrix 
   //mat.makeIdentity(); 
     driver->setTransform(video::ETS_WORLD, mat); 
   // finally I draw it 
   driver->drawIndexedTriangleList(vertices, 4, indices, 2); 

   }


const core::aabbox3d<f32>& CAxialBillboardSceneNode::getBoundingBox() const 
{ 
return Box; 
} 

s32 CAxialBillboardSceneNode::getMaterialCount() 
{ 
return 1; 
} 

video::SMaterial& CAxialBillboardSceneNode::getMaterial(s32 i) 
{ 
return Material; 
} 


} // end namespace scene
} // end namespace irr
Here begins the new stuff, to create the axial billboardfrom the scene manager

I added the following function to ISceneManager.h (with =0 at the end)and to CSceneManager.h

Code: Select all

    virtual IAxialBillboardSceneNode *addAxialBillboardSceneNode(ISceneNode* parent = 0,const core::vector3df& orientation = core::vector3df(1,1,1), f32 width=1.0f,const core::vector3df& position = core::vector3df(0,0,0),s32 id=-1)=0;
and the forward declared class in ISceneManager

Code: Select all

class IAxialBillboardSceneNode;
and the implementation in CSceneManager.cpp

Code: Select all

#include "CAxialBillboardSceneNode.h"
IAxialBillboardSceneNode *CSceneManager::addAxialBillboardSceneNode(ISceneNode* parent,
         const core::vector3df& orientation, f32 width,
         const core::vector3df& position, s32 id)
{
	if (!parent)
		parent = this;

	IAxialBillboardSceneNode* node = new CAxialBillboardSceneNode(parent, this, id, position, 
     orientation, width);
	node->drop();

	return node;
}
to Irrlicht.h add

Code: Select all

#include "IAxialBillboardSceneNode.h"
sorry that was rather long

THIS CODE HAS BEEN EDITED
Last edited by Electron on Thu Aug 12, 2004 4:06 pm, edited 3 times in total.
You do a lot of programming? Really? I try to get some in, but the debugging keeps me pretty busy.

Crucible of Stars
VeneX
Posts: 228
Joined: Sun Nov 30, 2003 3:32 pm
Location: The Netherlands
Contact:

Post by VeneX »

Calimero, why do you use a pointer variable for the texture filename?
I don't understand at all why pointers are used so much...
Visit my website @ www.venex.be
Plethora project will be added to the site
AMD AthlonXP 2600+, 512MB DDR, Radeon M10 (mobile 9600) PRO 64MB, WinXP
Post Reply