Effect:



You can download a demo (source code, image, exe and dll) here:
http://www.megaupload.com/?d=2L3T0VOY
Code: Select all
// CRotatingBillboardNode.h file
// gaz<@NOSPAM>bitplane.net - no rights reserved
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
class TRotatingBillboardSceneNode : public ISceneNode
{
private:
core::dimension2d<f32> Size;
core::aabbox3d<f32> BBox;
video::SMaterial Material;
s16 rotatecount, framecount, currentframe;
s16 lastimagex;
core::dimension2d<s32> imagesize;
core::dimension2d<s32> texturesize;
video::S3DVertex vertices[4];
u16 indices[6];
public:
// constructor
TRotatingBillboardSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id,
const core::vector3df& position = core::vector3df(0,0,0),
const core::dimension2d<f32>& size = dimension2d<f32>(10,10)) : ISceneNode(parent, mgr, id)
{
setSize(size);
AutomaticCullingEnabled = false;
indices[0] = 0;
indices[1] = 2;
indices[2] = 1;
indices[3] = 0;
indices[4] = 3;
indices[5] = 2;
vertices[0].TCoords.set(0.0f, 0.0f);
vertices[0].Color = 0xffffffff;
vertices[1].TCoords.set(0.0f, 1.0f);
vertices[1].Color = 0xffffffff;
vertices[2].TCoords.set(1.0f, 1.0f);
vertices[2].Color = 0xffffffff;
vertices[3].TCoords.set(1.0f, 0.0f);
vertices[3].Color = 0xffffffff;
}
~TRotatingBillboardSceneNode()
{
}
void TRotatingBillboardSceneNode::OnPreRender()
{
if (IsVisible)
{
SceneManager->registerNodeForRendering(this);
ISceneNode::OnPreRender();
}
}
void setSprites(s16 rotationframes, s16 animframes, core::dimension2d<s32> spritedimensions, s16 currentanimframe =0)
{
rotatecount = rotationframes;
framecount = animframes;
imagesize = spritedimensions;
currentframe = currentanimframe;
SMaterial t = getMaterial(0);
ITexture *tx = t.Textures[0];
texturesize = tx->getSize();
}
void setFrame(s16 framenumber)
{
currentframe = framenumber;
}
vector3df getTargetAngle(vector3df v, vector3df r)
{
//v -position
//r -target
vector3df angle;
float x,y,z;
x = r.X - v.X;
y = r.Y - v.Y;
z = r.Z - v.Z;
//angle in X-Z plane
angle.Y = atan2 (x, z);
angle.Y *= (180 / PI); //converting from rad to degrees
//angle.Y-=90;
//just making sure angle is somewhere between 0-360 degrees
if(angle.Y < 0) angle.Y += 360;
if(angle.Y >= 360) angle.Y -= 360;
//angle in Y-Z plane while Z and X axes are already rotated around Y
float z1 = sqrt(x*x + z*z);
angle.X = atan2 (z1, y);
angle.X *= (180 / PI); //converting from rad to degrees
//angle.X -= 90;
//just making sure angle is somewhere between 0-360 degrees
if(angle.X < 0) angle.X += 360;
if(angle.X >= 360) angle.X -= 360;
return angle;
}
//! render
void TRotatingBillboardSceneNode::render()
{
video::IVideoDriver* driver = SceneManager->getVideoDriver();
ICameraSceneNode* camera = SceneManager->getActiveCamera();
if (!camera || !driver)
return;
// make billboard look to Camera
core::vector3df pos = getAbsolutePosition();
core::vector3df campos = camera->getAbsolutePosition();
core::vector3df target = camera->getTarget();
core::vector3df up = camera->getUpVector();
core::vector3df view = target - campos;
view.normalize();
core::vector3df horizontal = up.crossProduct(view);
horizontal.normalize();
core::vector3df vertical = horizontal.crossProduct(view);
vertical.normalize();
horizontal *= 0.5f * Size.Width;
vertical *= 0.5f * Size.Height;
vertices[0].Pos = pos + horizontal + vertical;
vertices[1].Pos = pos + horizontal - vertical;
vertices[2].Pos = pos - horizontal - vertical;
vertices[3].Pos = pos - horizontal + vertical;
view *= -1.0f;
for (s32 i=0; i<4; ++i)
vertices[i].Normal = view;
// get rotation sprite number
vector3df selfrot=getRotation();
vector3df targetrot;
targetrot=getTargetAngle(pos,campos);
f32 rotadd=targetrot.Y-selfrot.Y;
s16 imagex = rotatecount-1 - int(rotadd / (360.0/rotatecount));
if (lastimagex != imagex) {
// get the texture position
f32 x1 = (imagex * imagesize.Width) ;
x1 /= texturesize.Width;
f32 y1 = (currentframe * imagesize.Height);
y1 /= texturesize.Height;
f32 x2 = ((imagex+1) * imagesize.Width);
x2 /= texturesize.Width;
f32 y2 = ((currentframe+1) * imagesize.Height);
y2 /= texturesize.Height;
// set texture
vertices[0].TCoords.set(x1, y2);
vertices[1].TCoords.set(x1, y1);
vertices[2].TCoords.set(x2, y1);
vertices[3].TCoords.set(x2, y2);
}
lastimagex = imagex;
// draw
core::matrix4 mat;
driver->setTransform(video::ETS_WORLD, mat);
driver->setMaterial(Material);
driver->drawIndexedTriangleList(vertices, 4, indices, 2);
}
//! returns the axis aligned bounding box of this node
const core::aabbox3d<f32>& TRotatingBillboardSceneNode::getBoundingBox() const
{
return BBox;
}
//! sets the size of the billboard
void TRotatingBillboardSceneNode::setSize(const core::dimension2d<f32>& size)
{
Size = size;
}
video::SMaterial& TRotatingBillboardSceneNode::getMaterial(s32 i)
{
return Material;
}
//! returns amount of materials used by this scene node.
s32 TRotatingBillboardSceneNode::getMaterialCount()
{
return 1;
}
//! gets the size of the billboard
const core::dimension2d<f32>& TRotatingBillboardSceneNode::getSize()
{
return Size;
}
};
Code: Select all
#include <stdio.h>
#include <wchar.h>
#include <irrlicht.h>
using namespace irr;
#include "CRotatingBillboardNode.h"
#pragma comment(lib, "Irrlicht.lib")
#define MAXSPRITES 50
scene::ISceneNode* node = 0;
TRotatingBillboardSceneNode* manysprites[MAXSPRITES];
IrrlichtDevice* device = 0;
int main()
{
device = createDevice(video::EDT_OPENGL, core::dimension2d<s32>(800, 600),
16, false, false, false);
video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager();
TRotatingBillboardSceneNode* node = new TRotatingBillboardSceneNode( smgr->getRootSceneNode(), smgr, 666);
node->setMaterialFlag(EMF_LIGHTING, false);
node->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR); //makes it transparent
ITexture * txture = driver->getTexture("fairy.bmp");
driver->makeColorKeyTexture (txture,position2d<s32>(0,0));
node->setMaterialTexture( 0, txture );
node->setSprites(16,1,core::dimension2d<s32>(64,103),0);
// we'll have a bank of sprites
for (int n=0;n<MAXSPRITES;n++) {
manysprites[n] = new TRotatingBillboardSceneNode( smgr->getRootSceneNode(), smgr, 667+n);
manysprites[n]->setMaterialTexture( 0, txture );
manysprites[n]->setMaterialFlag(EMF_LIGHTING, false);
manysprites[n]->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR); //makes it transparent
manysprites[n]->setSprites(16,1,core::dimension2d<s32>(64,103),0);
manysprites[n]->setPosition(vector3df((n - n%(MAXSPRITES/10) )*5+10,n %(MAXSPRITES/10)*-30,0));
}
ICameraSceneNode *camera = smgr->addCameraSceneNodeFPS(0, 100.0f, 100.0f);
device->getCursorControl()->setVisible(false);
int lastFPS = -1;
f32 rot=0.0;
while(device->run())
{
driver->beginScene(true, true, video::SColor(255,113,113,133));
smgr->drawAll();
driver->endScene();
rot +=0.1;
node->setRotation(vector3df(0,rot,0));
int fps = driver->getFPS();
if (lastFPS != fps)
{
wchar_t tmp[1024];
swprintf(tmp, 1024, L"Rotating Billboards! [%s] fps:%d",
driver->getName(), fps);
device->setWindowCaption(tmp);
lastFPS = fps;
}
}
/*
In the end, delete the Irrlicht device.
*/
device->drop();
return 0;
}
Note the code is not mine; i have not used, compiled or revised it. I dont know if it works with all driver types. Im just posting what i found somewhere i havent been able to find again.
The guy gaz<@NOSPAM>bitplane.net seems to be the author.
