Quadratic Attenuation For Radius

Started by
2 comments, last by L. Spiro 9 years, 4 months ago

Hey,

I have a light, with a radius, and I want to calculate the attenuation for it given a radius. I've looked at several equations and tried out a few myself, but I can't seem to find the one that looks just right. Anyone have any good equations for it?

Advertisement

So your "standard" quadratic attenuation function is just 1 / d^2. The problem with that is that it never actually hits 0, and so you can't bound it by a radius. The easiest way to do that is to just compute the attenuation value at the desired radius, and then subtract that from the attenuation factor:

float attenuation = max(1.0f / (distance * distance) - 1.0f / (radius * radius), 0.0f);

If you'd like you can pre-compute the 1 / r^2 part ahead of time on the CPU, since it's constant for that light source.

So your "standard" quadratic attenuation function is just 1 / d^2. The problem with that is that it never actually hits 0, and so you can't bound it by a radius. The easiest way to do that is to just compute the attenuation value at the desired radius, and then subtract that from the attenuation factor:


float attenuation = max(1.0f / (distance * distance) - 1.0f / (radius * radius), 0.0f);

If you'd like you can pre-compute the 1 / r^2 part ahead of time on the CPU, since it's constant for that light source.

I was aware of the quadratic approach never reaching 0, I just wanted something that would come close enough so you wouldn't be able to notice the cut off, and what you gave me worked great. Thanks.

Epic outlined another formula here: Lighting Model
falloff = (saturate(1 ? (distance/lightRadius)4)2) ÷ (distance2 + 1)

Here is a test scene with all 3 equations. There are 3 point lights.

#1: Physically correct quadratic fall-off (scaled by light radius).
float Falloff( in float _fDistance, in float _fRadius ) {
	float fFalloff = 1.0 / Sqr( _fDistance );
	return fFalloff;
}
[attachment=25241:FalloffD2.png]
It indeed never reaches 0, but all 3 lights have approximately the correct visible ranges (you would still see the cut-off if you dropped to 0 at “range” units though).

#2: Epic’s fall-off.
float Falloff( in float _fDistance, in float _fRadius ) {
	float fFalloff = 0;
	float fDistOverRadius = _fDistance / _fRadius;
	float fDistOverRadius2 = Sqr( fDistOverRadius );
	float fDistOverRadius4 = Sqr( fDistOverRadius2 );
	fFalloff = Sqr( saturate( 1.0 - fDistOverRadius4 ) );
	fFalloff /= Sqr( _fDistance ) + 1.0;
	return fFalloff;
}
[attachment=25242:FalloffEpic.png]
Gives a very good fall-off. They outlined the artistic intent in the paper.

#3: The above formula.
float Falloff( in float _fDistance, in float _fRadius ) {
	float fFalloff = max( 1.0 / Sqr( _fDistance ) - 1.0 / Sqr( _fRadius ), 0.0 );
	return fFalloff;
}
[attachment=25240:FalloffMod.png]
Looks almost the same as Epic’s—only a few pixels in the specular around the headlights are different. The artistic intent is different however, and may give noticeably different results in other situations.


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

This topic is closed to new replies.

Advertisement