[Fixed]Bilboards culling bug + all node's speed improvement

You discovered a bug in the engine, and you are sure that it is not a problem of your code? Just post it in here. Please read the bug posting guidelines first.
Pr3t3nd3r
Posts: 186
Joined: Tue Feb 08, 2005 6:02 pm
Location: Romania
Contact:

[Fixed]Bilboards culling bug + all node's speed improvement

Post by Pr3t3nd3r »

I remember reading some where in the documentation that billboard node's doesn't need culling ...
FALSE
I added few hundred billboards and the fps dropped a lot.

Fix code:

Code: Select all

//! constructor
CBillboardSceneNode::CBillboardSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id,	
const core::vector3df& position, const core::dimension2d<f32>& size)
: IBillboardSceneNode(parent, mgr, id, position)
{
	#ifdef _DEBUG
	setDebugName("CBillboardSceneNode");
	#endif

	setSize(size);

	//AutomaticCullingEnabled = false;
//lsize,position.Z-lsize,position.X+lsize,position.Y+lsize,position.Z+lsize);
	f32 lsize = size.Height>size.Width ? size.Height/2:size.Width/2;	
	BBox = core::aabbox3d<f32>(-lsize,-lsize,-lsize,lsize,+lsize,+lsize);
............

Code: Select all

//! sets the size of the billboard
void CBillboardSceneNode::setSize(const core::dimension2d<f32>& size)
{
	Size = size;	
	f32 lsize = size.Height>size.Width ? size.Height/2:size.Width/2;	
	BBox = core::aabbox3d<f32>(-lsize,-lsize,-lsize,lsize,+lsize,+lsize);
}
cbillboardscenenode.cpp

Code: Select all

//! Sets the color of the billboard. useful for color animator
//! Sets the color of the billboard.
 void CBillboardSceneNode::setColor(const video::SColor& color)
{
	vertices[0].Color = color;
	vertices[1].Color = color;
	vertices[2].Color = color;
	vertices[3].Color = color;	
}
cbillboardscenenode.h

//! Sets the color of the billboard.
virtual void setColor(const video::SColor& color);
Ibillboardscenenode.h
//! Sets the color of the billboard.
virtual void setColor(const video::SColor& color) =0;
From here on I'm using ISceneNode.h ::::


Now i cand add thousand of nodes.
The only bad think is that now:

Code: Select all

		virtual void OnPostRender(u32 timeMs)
		{....
				// update absolute position
				updateAbsolutePosition();
                                 ....

i get thousand of useless updateAbsolutePosition();
more exactly:

Code: Select all

		virtual core::matrix4 getRelativeTransformation() const
		{
			core::matrix4 mat;
			mat.setRotationDegrees(RelativeRotation);
			mat.setTranslation(RelativeTranslation);

			if (RelativeScale != core::vector3df(1,1,1))
			{
				core::matrix4 smat;
				smat.setScale(RelativeScale);
				mat *= smat;
			}

			return mat;
		}
slow and time consuming function what can be easy optimized with:

Code: Select all

		virtual core::matrix4 getRelativeTransformation() const
		{
			core::matrix4 mat;
			if (RelativeRotation != core::vector3df(0,0,0))
				mat.setRotationDegrees(RelativeRotation);

				mat.setTranslation(RelativeTranslation);

			if (RelativeScale != core::vector3df(1,1,1))
			{
				core::matrix4 smat;
				smat.setScale(RelativeScale);
				mat *= smat;
			}

			return mat;
		}
... removing setRotationDegrees update for node rotation at every frame: no more

sin,cos,transformations and lot's of operations if the node isn't rotated.

Normaly the update for relativetransformation sould be made only in:
setPosition
setRotation
setScale functions.

Fix code

in ISceneNode.h add and modify:

Code: Select all

	protected:
	//! relative transformation of the node.
	core::matrix4 RelativeTransformation; 

Code: Select all

		//! Returns the relative transformation of the scene node.
		//! The relative transformation is stored internally as 3 vectors:
		//! translation, rotation and scale. To get the relative transformation
		//! matrix, it is calculated from these values.
		//! \return Returns the relative transformation matrix.
		virtual core::matrix4 getRelativeTransformation() const
		{			
			return RelativeTransformation;
		}

Code: Select all


		//! Sets the rotation of the node. This only modifies
		//! the relative rotation of the node.
		//! \param roation: New rotation of the node in degrees.
		virtual void setRotation(const core::vector3df& rotation)
		{
			RelativeRotation = rotation;
			RelativeTransformation.setRotationDegrees(RelativeRotation);
//not sure if need it
			if (RelativeScale != core::vector3df(1,1,1))
			{
				core::matrix4 smat;
				smat.setScale(RelativeScale);
				RelativeTransformation*= smat;
			}
		}

Code: Select all

		virtual void setPosition(const core::vector3df& newpos)
		{
			RelativeTranslation = newpos;
			RelativeTransformation.setTranslation(RelativeTranslation);
//not sure if need it
			if (RelativeScale != core::vector3df(1,1,1))
			{
				core::matrix4 smat;
				smat.setScale(RelativeScale);
				RelativeTransformation *= smat;
			}
		}

Code: Select all

		//! Sets the scale of the scene node. 
		//! \param scale: New scale of the node
		virtual void setScale(const core::vector3df& scale)
		{
			RelativeScale = scale;
				core::matrix4 smat;
				smat.setScale(RelativeScale);
				RelativeTransformation*= smat;
		}

Code: Select all

		//! Constructor
		ISceneNode(	ISceneNode* parent, ISceneManager* mgr, s32 id=-1,
					const core::vector3df& position = core::vector3df(0,0,0),
					const core::vector3df& rotation = core::vector3df(0,0,0),
					const core::vector3df& scale = core::vector3df(1.0f, 

1.0f, 1.0f))
			: IsVisible(true), ID(id), Parent(parent), SceneManager(mgr),
				AutomaticCullingEnabled(true), DebugDataVisible(false),
				TriangleSelector(0), RelativeTranslation(position),
				RelativeRotation(rotation), RelativeScale(scale)

		{
			if (Parent)
				Parent->addChild(this);

			//new update relative pozition 
				RelativeTransformation.setRotationDegrees(RelativeRotation);
				RelativeTransformation.setTranslation(RelativeTranslation);
				core::matrix4 smat;
				smat.setScale(RelativeScale);
				RelativeTransformation*= smat;

			updateAbsolutePosition();
		}

Code: Select all

		//! updates the absolute position based on the relative and the parents position	

		virtual void updateAbsolutePosition()
		{			
			if (Parent)	AbsoluteTransformation = 					

			Parent->getAbsoluteTransformation() * RelativeTransformation;			

			else
			AbsoluteTransformation = RelativeTransformation;
		}
And this is also fixing the problems with node updating of node pozitions (setPozition(bla)

setVissble(true) ... node first apears on old pozition an then jump to new pozition no more).
Last edited by Pr3t3nd3r on Tue Aug 02, 2005 10:02 am, edited 1 time in total.
Pr3t3nd3r
Posts: 186
Joined: Tue Feb 08, 2005 6:02 pm
Location: Romania
Contact:

Post by Pr3t3nd3r »

oh well ... it seems that nobody need speed .. :cry:
... even if there are some complains about that on Beginners Help or advanced ... don't remember ...
... many scene node's ==> low fps ...
etcaptor
Posts: 871
Joined: Fri Apr 09, 2004 10:32 pm
Location: Valhalla
Contact:

Post by etcaptor »

:D Thanks for exploration. I will try it next week and than will be able to give any answer about this.
ImageImage
Site development -Rock and metal online
--- etcaptor.com ------freenetlife.com
Reiyn
Posts: 23
Joined: Sat Mar 05, 2005 7:51 pm
Location: Canada

Post by Reiyn »

I'm going to try this aswell in the next few days, :)

Thank you very much, it looks and sounds really awesome!
Good job!! :D
Reiyn
Creating "Chimera", an Online RPG
DAoC - Guinevere - Druid rr11
WoW - Gorgonnash - Druid 55
puh
Posts: 356
Joined: Tue Aug 26, 2003 3:53 pm

Post by puh »

Hey, Pr3t3nd3r, thanks for the great patch.
I have few thoughts:
1. there is a typo in your code right after //AutomaticCullingEnabled = false;
lsize,position.Z-lsize,position.X+lsize,position.Y+lsize,position.Z+lsize);
2. you have two different getRelativeTransformation() function and didn't say which one is correct. or am i missed smthg :)
3. you have added function setColor() and said nothing about it. Anyway this is out of the current thread, eh?

Thank you very much anyway!
Pr3t3nd3r
Posts: 186
Joined: Tue Feb 08, 2005 6:02 pm
Location: Romania
Contact:

Post by Pr3t3nd3r »

2.first getRelativeTransformation() is the old code, the second is optimized.
3. setColor() is use to change the color of billboard. Can be very useful if you want to animate the billboard (animator), make if fade or change color ... (example: if the sun is changing color, luminosity ... you can do that to the billboard too)
Pr3t3nd3r
Posts: 186
Joined: Tue Feb 08, 2005 6:02 pm
Location: Romania
Contact:

Post by Pr3t3nd3r »

an other think what must be optimized is the node drawing. Right now all node's are consired animated. Non animated node's sould have an diferent render function (i think is render ... not sure ..)
Pr3t3nd3r
Posts: 186
Joined: Tue Feb 08, 2005 6:02 pm
Location: Romania
Contact:

Post by Pr3t3nd3r »

Niko. you want to include this optimizations in next version ??? I tested them more than one mount and there are no problems with them.
Also how much do you estimate to be "big values of soon"?
Because I'm very happy to see:

quote:
--------------------------------------------------------------------------------
Originally posted by me again:
.Zbuffers (32bit without stencil, flexible, robust fallbacks)
.MipMaps (Work around using AF in card settings but not ideal)
.Anisotropic (very important in modern games while not being too "expensive")
--------------------------------------------------------------------------------
Niko
Agreed. Already on my list.
I believe that's what you are working on from the image.

Also if anyone have made some good using of: EMT_LIGHTMAP ... EMT_LIGHTMAP_LIGHTING ... EMT_SPHERE_MAP, EMT_REFLECTION_2_LAYER please show me an picture with an object ... because i get only stupid results ...
niko
Site Admin
Posts: 1759
Joined: Fri Aug 22, 2003 4:44 am
Location: Vienna, Austria
Contact:

Post by niko »

Pr3t3nd3r wrote:Niko. you want to include this optimizations in next version ???
Yes, sorry for not answering. I think I'm going to try it out, or at least optimize some nodes this way. I only fear that this will cause some already existing nodes not to work correctly anymore. Thanks for posting all this.
Pr3t3nd3r
Posts: 186
Joined: Tue Feb 08, 2005 6:02 pm
Location: Romania
Contact:

Post by Pr3t3nd3r »

Maybe I'm the first to tell you this,, but sometimes you act like an big corporation. You should really write that on your CV :D .

The first optimization(creating bounding box for billboards), is OK and needed. When you add 10-20 billboards there is no big difference between optimized and unoptimized. But when the number of billboards grow... the optimisation is very visible (few hundred). (not affecting any think except billboards).

Second optimization is applying to ALL nodes ( ISceneNode.h ). It have no hidden effects because what it does.
It take the getRelativeTransformation() what is time consuming because is called every frame update and is calling lot's of setRotation(....) (sin cos... etc) and is updating position and angle only on actual modifications (calls), and for updatepozition is using the stored actual value.
The code is very safe with no side effects. (is only making math when needed).



And there is on other problem. I don't really know where it is but this is it.
When you use an bbillboard it is drawing 1 pixel more than required (right and down). I think that is because when you use get size of texture is returning the number of pixels but when you draw it you should use NR_of_pixels-1. (because 0 is counted too).
I don't know if this little bug affects other textures or only billboards. if you use an billboard with an line on the x=0 of texture. you will see 2 lines one on the left and one on the right.
If this bug is affecting other nodes this is causing the engine to be slower because taking for all the textures the first line of the texture an drawing it at end ... lot's of copying and memory jumps ...
I think is in material or something. You should realy check this. The last pixel drawed of an 16/16 pixel's should be 15/15 (... counting 0 .... i'm verry sure you know).

Ps. nice changes in the last version some of the i wasn't expectin so fast...
and you added:
//! rotates the point around a center by an amount of degrees.
void rotateTrigBy(f64 degrees, const vector2d<T>& center)
... what i post'it long long time ago in the forum (only 4 version until it get in the desired file :) ... ) o well at least now i don't have to make the changes any more ...

but still it take me few hours to make all my changes ...
GX

Post by GX »

I implemented the above optimisation for reducing update calls. It improved my framerate in given test app by around 10-20fps in DIRECT3D8. In open GL it was the same or slightly less. Though this is a simple app. I can see that as you add more and more nodes the improvements would show even better!! :)


however... Unless I am mistaken, it DID affect some functionality. I was trying to do some on the fly iterative scaling of some nodes (+0.1f each loop) and the nodes were just dissapearing instead of getting larger.

I double checked everything, then I went back to my custom irrlicht build and commented out your optimization (and uncommented the orginal code) - rebuild, relinked and it worked fine as expected.

Not sure if I am now expected to call update manually or something but that didnt seem to work either. So it seems there is a problem with the code when scaling (rotation/translation worked fine and it was good to see the fix added for a visible node being at 0,0,0 before the new position). however, for now I must live without that as the scaling fault is more important.

rgds
Guest

Post by Guest »

Should point out - in the above - I meant that under OpenGL there was no apparent speed improvement only a loss if anything - but this could be because my scene was not node heavy.

cheers
Pr3t3nd3r
Posts: 186
Joined: Tue Feb 08, 2005 6:02 pm
Location: Romania
Contact:

Post by Pr3t3nd3r »

leave that //not sure if need it
I tried and it works fine ... what type of node's are you trying to scale ?
Guest

Post by Guest »

I am trying it with IAnimatedMeshSceneNodes. I will give it a try with the part left out above, though as someone asked before (and you misunderstood them) you have posted 2 GetRelativeTranslations (not including the original code) - one with a lot of code in the function body and one with just 1 line of code. Was this intentional? Are they overloaded?

Code: Select all

 virtual core::matrix4 getRelativeTransformation() const
      {         
         return RelativeTransformation;
      } 
thanks
Pr3t3nd3r
Posts: 186
Joined: Tue Feb 08, 2005 6:02 pm
Location: Romania
Contact:

Post by Pr3t3nd3r »

I tried on IAnimatedMeshSceneNodes and it's working fine.
The speed improvements depends on how many node's you have ... for hundred or more the speed improvement is more visible. The speed improvement is not dx, og related ... ... but if you have few nodes or low fps .. the improvement will not be that visible ...


The code's for
ISceneNode.h: (replace old functions)

Code: Select all

   protected: 
   //! relative transformation of the node. 
   core::matrix4 RelativeTransformation;


		//! Returns the relative transformation of the scene node.
		//! The relative transformation is stored internally as 3 vectors:
		//! translation, rotation and scale. To get the relative transformation
		//! matrix, it is calculated from these values.
		//! \return Returns the relative transformation matrix.
		virtual core::matrix4 getRelativeTransformation() const
		{			
			return RelativeTransformation;
		}





		//! Sets the rotation of the node. This only modifies
		//! the relative rotation of the node.
		//! \param roation: New rotation of the node in degrees.
		virtual void setRotation(const core::vector3df& rotation)
		{
			RelativeRotation = rotation;
			RelativeTransformation.setRotationDegrees(RelativeRotation);
			if (RelativeScale != core::vector3df(1,1,1))
			{
				core::matrix4 smat;
				smat.setScale(RelativeScale);
				RelativeTransformation *= smat;
			}
		}



		//! Sets the position of the node. Note that the position is
		//! relative to the parent.
		//! \param newpos: New relative postition of the scene node.
		virtual void setPosition(const core::vector3df& newpos)
		{
			RelativeTranslation = newpos;
			RelativeTransformation.setTranslation(RelativeTranslation);
			if (RelativeScale != core::vector3df(1,1,1))
			{
				core::matrix4 smat;
				smat.setScale(RelativeScale);
				RelativeTransformation *= smat;
			}
		}





		//! Sets the position of the node. Note that the position is
		//! relative to the parent.
		//! \param newpos: New relative postition of the scene node.
		virtual void setPosition(const core::vector3df& newpos)
		{
			RelativeTranslation = newpos;
			RelativeTransformation.setTranslation(RelativeTranslation);
			if (RelativeScale != core::vector3df(1,1,1))
			{
				core::matrix4 smat;
				smat.setScale(RelativeScale);
				RelativeTransformation *= smat;
			}
		}




//! constructor
CCameraSceneNode::CCameraSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id, 
	const core::vector3df& position, const core::vector3df& lookat)
	: ICameraSceneNode(parent, mgr, id, position, core::vector3df(0.0f, 0.0f, 0.0f),
			core::vector3df(1.0f, 1.0f, 1.0f)), InputReceiverEnabled(true)
{
	#ifdef _DEBUG
	setDebugName("CCameraSceneNode");
	#endif

	BBox.reset(0,0,0);

	// set default view

	UpVector.set(0.0f, 1.0f, 0.0f);
	Target.set(lookat);

	// set default projection

	fovy = core::PI / 2.5f;	// Field of view, in radians. 
	aspect = 4.0f / 3.0f;	// Aspect ratio. 
	zn = 1.0f;				// value of the near view-plane. 
	zf = 3000.0f;			// Z-value of the far view-plane. 

	video::IVideoDriver* d = mgr->getVideoDriver();
	if (d)
	{
		screenDim.Width = (f32)d->getScreenSize().Width;
		screenDim.Height = (f32)d->getScreenSize().Height;
		aspect = screenDim.Height / screenDim.Width;
	}

	recalculateProjectionMatrix();
}





		//! updates the absolute position based on the relative and the parents position
		virtual void updateAbsolutePosition()
		{
			if (Parent)
				AbsoluteTransformation = 
					Parent->getAbsoluteTransformation() * RelativeTransformation;
			else
				AbsoluteTransformation = RelativeTransformation;
		}

Post Reply