(C++) Speed up in CCameraSceneNode

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
Post Reply
Spintz
Posts: 1688
Joined: Thu Nov 04, 2004 3:25 pm

(C++) Speed up in CCameraSceneNode

Post by Spintz »

Old way -

Image

New way -

Image

The columns in those screenshots are as follows, in order Left to Right -

Visits to function
% of root time
Time
Avg Time

and the rest don't matter.

The problem was in CCameraSceneNode.cpp, recalculateViewArea function -

Code: Select all

void CCameraSceneNode::recalculateViewArea()
{
	core::matrix4 mat = Projection * View;
	ViewArea = SViewFrustrum(mat);

	ViewArea.cameraPosition = getAbsolutePosition();
	ViewArea.recalculateBoundingBox();
}
If you look at the SViewFrustrum ctor, it already calls recalculateBoundingBox, and assumes cameraPosition is already set as well. To alleviate this problem, I added a set method to SViewFrustrum -

Code: Select all

//! Sets the frustrum based on a projection and/or view matrix and a camera position.
//! \param mat: View and/or Projection Matrix.
//! \param camPos: Position of the camera.
inline void SViewFrustrum::set(const core::matrix4& mat, const core::vector3df& camPos)
{
		cameraPosition = camPos; 

		// left clipping plane 
		planes[SViewFrustrum::VF_LEFT_PLANE].Normal.X = mat(3,0) + mat(0,0); 
		planes[SViewFrustrum::VF_LEFT_PLANE].Normal.Y = mat(3,1) + mat(0,1); 
		planes[SViewFrustrum::VF_LEFT_PLANE].Normal.Z = mat(3,2) + mat(0,2); 
		planes[SViewFrustrum::VF_LEFT_PLANE].D =		mat(3,3) + mat(0,3); 

		// right clipping plane                  
		planes[SViewFrustrum::VF_RIGHT_PLANE].Normal.X = mat(3,0) - mat(0,0); 
		planes[SViewFrustrum::VF_RIGHT_PLANE].Normal.Y = mat(3,1) - mat(0,1); 
		planes[SViewFrustrum::VF_RIGHT_PLANE].Normal.Z = mat(3,2) - mat(0,2); 
		planes[SViewFrustrum::VF_RIGHT_PLANE].D =        mat(3,3) - mat(0,3); 

		// top clipping plane                  
		planes[SViewFrustrum::VF_TOP_PLANE].Normal.X = mat(3,0) - mat(1,0); 
		planes[SViewFrustrum::VF_TOP_PLANE].Normal.Y = mat(3,1) - mat(1,1); 
		planes[SViewFrustrum::VF_TOP_PLANE].Normal.Z = mat(3,2) - mat(1,2); 
		planes[SViewFrustrum::VF_TOP_PLANE].D =        mat(3,3) - mat(1,3); 

		// bottom clipping plane                  
		planes[SViewFrustrum::VF_BOTTOM_PLANE].Normal.X = mat(3,0) + mat(1,0); 
		planes[SViewFrustrum::VF_BOTTOM_PLANE].Normal.Y = mat(3,1) + mat(1,1); 
		planes[SViewFrustrum::VF_BOTTOM_PLANE].Normal.Z = mat(3,2) + mat(1,2); 
		planes[SViewFrustrum::VF_BOTTOM_PLANE].D =        mat(3,3) + mat(1,3); 

		// near clipping plane                    
		planes[SViewFrustrum::VF_NEAR_PLANE].Normal.X = mat(2,0); 
		planes[SViewFrustrum::VF_NEAR_PLANE].Normal.Y = mat(2,1); 
		planes[SViewFrustrum::VF_NEAR_PLANE].Normal.Z = mat(2,2); 
		planes[SViewFrustrum::VF_NEAR_PLANE].D =        mat(2,3); 

		// far clipping plane                    
		planes[SViewFrustrum::VF_FAR_PLANE].Normal.X = mat(3,0) - mat(2,0); 
		planes[SViewFrustrum::VF_FAR_PLANE].Normal.Y = mat(3,1) - mat(2,1); 
		planes[SViewFrustrum::VF_FAR_PLANE].Normal.Z = mat(3,2) - mat(2,2); 
		planes[SViewFrustrum::VF_FAR_PLANE].D =        mat(3,3) - mat(2,3); 

		// normalize normals 
		f32 len; 
		len = (f32)( 1.0f / planes[0].Normal.getLength() ); 
		planes[0].Normal *= len; 
		planes[0].D *= len; 
		len = (f32)( 1.0f / planes[1].Normal.getLength() ); 
		planes[1].Normal *= len; 
		planes[1].D *= len; 
		len = (f32)( 1.0f / planes[2].Normal.getLength() ); 
		planes[2].Normal *= len; 
		planes[2].D *= len; 
		len = (f32)( 1.0f / planes[3].Normal.getLength() ); 
		planes[3].Normal *= len; 
		planes[3].D *= len; 
		len = (f32)( 1.0f / planes[4].Normal.getLength() ); 
		planes[4].Normal *= len; 
		planes[4].D *= len; 
		len = (f32)( 1.0f / planes[5].Normal.getLength() ); 
		planes[5].Normal *= len; 
		planes[5].D *= len; 

		// make bounding box 
		recalculateBoundingBox(); 
}
I got rid of the #define sw, and just swapped the args to the operator() of matrix4, and I also unrolled the for loop. This changes the code in CCameraSceneNode::recalculateViewArea to -

Code: Select all

void CCameraSceneNode::recalculateViewArea()
{
	ViewArea.set( Projection * View, getAbsolutePosition() );
}
And gives the speedup shown above. Before, the OnPreRender was taking 70 milliseconds, with the recalculateViewArea calls taking up 55 of those milliseconds. With this change, it reduces the time spent in the recalculateViewArea function by 24 milliseconds, which double checks by showing the OnPreRender being 25 milliseconds faster.

EDIT: Sorry, those time are in microseconds not milliseconds.

EDIT2: Had 1 typo in the matrix stuff, when getting rid of the sw macro stuff, edited the code above.
Image
IPv6
Posts: 188
Joined: Tue Aug 08, 2006 11:58 am

Post by IPv6 »

Thanks for fix!
BTW, what did you use for profiling your game?
I found usual tools almost unusable under debug versions of dx because anything became sooo slow... :(
Spintz
Posts: 1688
Joined: Thu Nov 04, 2004 3:25 pm

Post by Spintz »

It's called GlowCode, it's not free, I think it's $150 for 1 year license.

And it's more than just a profiler, detects memory leaks and all.
Image
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

gprof and valgrind also do a good job :D
Spintz
Posts: 1688
Joined: Thu Nov 04, 2004 3:25 pm

Post by Spintz »

We've tried other profilers and memory leak testers at work, and they all blow up. Our code at work is more than 1.5 million lines of code, and over 100 DLLs and with various Exes.

Most other ones we've tried crash and get confused, they can't handle mixed mode DLLs( managed and C++ ) in same DLL and many other reasons why. GlowCode is the best we've found.

Hey, they should give me money for plugging 'em like this.. :evil:
Image
IPv6
Posts: 188
Joined: Tue Aug 08, 2006 11:58 am

Post by IPv6 »

Thanks for tip!

1500 is not fair for home usage... but may be they have demo to try. i`ll go seeking :)

2hybrid: i`l check them too, thanks!
Spintz
Posts: 1688
Joined: Thu Nov 04, 2004 3:25 pm

Post by Spintz »

1500? Now, it's 150.

And yes they have a demo/trial version you can use.
Image
IPv6
Posts: 188
Joined: Tue Aug 08, 2006 11:58 am

Post by IPv6 »

Ups. sorry, i got stack overflow in my mind :)
$150 is quite fine for a good tool! :)
i`ll check it definitely
Post Reply