This project is read-only.

Light Bounds optimization?

May 14, 2012 at 10:17 PM

I don't know if this has been posted before, and I know how to use search, so bear with me. Also, my first language is Portuguese, still I was born in England so I have no excuse. :P

I was noticing some performance issues with Krypton in a medium-sized tile map with ~25 lights. Those lights varied from 100 to 1000 in Range, and from 0.3f to 1f in Intensity. My first thought was straight to some possible inefficiency in light culling (only drawing lights on screen), and I was mostly correct.

How did I try to confirm it?

Basically, when I drew light primitives (I copied the DrawDebug method from the TestBed, Krypton 2.0 Feb 14 2011), I noticed some lights with intensity < 1f were not on screen but were still getting drawn, their bounds appearing on-screen even if the lights themselves weren't.

So, I went straight to the source, and I noticed this...

 

public BoundingRect Bounds
{
	get
	{
		BoundingRect rect;

		rect.Min.X = this.mPosition.X - this.mRange;
		rect.Min.Y = this.mPosition.Y - this.mRange;
		rect.Max.X = this.mPosition.X + this.mRange;
		rect.Max.Y = this.mPosition.Y + this.mRange;

		return rect;
	}
}

...and I thought: "but lights with lower intensities have shorter bounds, how can they be drawn?" Then I tried to think of possible solutions, and this equation came to mind (not exactly this equation, obviously):

rect.Zzz.Z = this.mPositionZ (-/+) this.mRange * this.mIntensity;

"What if I could multiply the range by the intensity?" I wondered. This way, since the light radius gets smaller when the intensity is lower than 1f (basic math, everyone), the bounds would be shorter.

This would possibly lead to drawing less lights on screen, and, as an extra, also be prone to less calculations against hulls, since the light doesn't even reach it anyway (or so I understand).

Still, there would be a problem. If the light radius doesn't get bigger when the intensity is >1f, then the bounds would be giant. We have to compensate for that. Therefore, I came up with this:

rect.Zzz.Z = this.mPositionZ (-/+) this.mRange * (this.mIntensity < 1f ? this.mIntensity : 1f);

This way, the bounds wouldn't be screwed up if mIntensity was higher than 1f.

So, to make this a lot easier for my game in the long term, I made up a private variable:

private float mBound = 1;

...and created a new accessor for it:

public float Bound
{
	get { return this.mRange * (this.mIntensity < 1f ? this.mIntensity : 1f); }
}

(please don't mind the variable's name, I just needed a random name, feel free to change it, lol)

Also, instead of calculating this mBound inside the Light2D.Bounds acessor, I calculated it whenever mRange or mIntensity were changed, since those are the values that affect it. Like this:

public float Range
{
	get { return this.mRange; }
	set
	{
		this.mRange = value;
		this.mBound = this.Bound;
	}
}

(...)

public float Intensity
{
	get { return this.mIntensity; }
	set
	{
		this.mIntensity = MathHelper.Clamp(value, 0.01f, 3f);
		this.mBound = this.Bound;
	}
}

...and I made the Light2D.Bounds accessor to look like this:

public BoundingRect Bounds
{
	get
	{
		BoundingRect rect;

		rect.Min.X = this.mPosition.X - this.mBound;
		rect.Min.Y = this.mPosition.Y - this.mBound;
		rect.Max.X = this.mPosition.X + this.mBound;
		rect.Max.Y = this.mPosition.Y + this.mBound;

		return rect;
	}
}

So, now is the time when you ask: "Did it work?".

Oh, yes. Yes it did. It nearly doubled the FPS on my laptop (which is dying and overheats frequently).

My PC (i7 870 @ 3.2GHz, AMD HD6970), 1920x1080, fullscreen:

Before: ~243 FPS
After: ~412 FPS

My Laptop (Pentium T3400 @ 2.16GHz, GeForce G105M), 800x600, window mode:

Before: ~35 FPS
After: ~68 FPS

That's my 2 cents. I don't know if this is good code or anything, but I'd appreciate some feedback to see if I'm doing this right. :D

Cheers.

 

May 18, 2012 at 12:30 PM

Really awesome! Thanks, I'll try it at home to see how it performs :)

May 22, 2012 at 9:56 PM

Interesting. Your concept makes sense, so I'll test this out once I get a chance. If Xixonia likes this enough we'll post some kudos to you on the front page :)

Jun 7, 2012 at 11:18 PM

Hokay, so this is the first time I've seen this post, and engine-wise, this is the first significant performance improvement submitted by the community (that I can remember).

I'm not sure how often people will be using intensities less than 1f, but when they do, this will definitely increase performance!

Thanks for the contribution! :)