Sign in to follow this  
doesnotcompute

Spotlight attenuation

Recommended Posts

In Frank Luna's DX9 book he gives the equation for spotlight attenuation as: max(dot(-L,d),0)^s. The light direction dotted with the vector from the light to the vertex/pixel position raised to some exponent.

He then says that an exponent of s=8 gives approximately a 45 degree (half-angle) cone of light. Does anybody know where this value comes from, i.e. how to determine the exponent for a given angle?

Share this post


Link to post
Share on other sites
Quote:
Original post by doesnotcompute
In Frank Luna's DX9 book he gives the equation for spotlight attenuation as: max(dot(-L,d),0)^s. The light direction dotted with the vector from the light to the vertex/pixel position raised to some exponent.

He then says that an exponent of s=8 gives approximately a 45 degree (half-angle) cone of light. Does anybody know where this value comes from, i.e. how to determine the exponent for a given angle?


The dot between two normalized vectors equals cos(x) (x= angle between both vectors). Now enter cos(x) and cos(x)^8 in a function plotter and you will see that using cos(x) you will get positive values up to ~1.5 (PI/2=90 degree). This values are your spotlight intensity. When you take a look at the cos(x)^8 function curve you will see that notable values are only up to ~1 (~54 degree), whereas these values are almost 0.

The author just simplified the statement by telling the reader that it is approximately 45 degree when you will start noticing a spotlight. Increasing the exponent will move the curve further to the left, infact decreasing the cone in which a light will produce a spotlight.

Share this post


Link to post
Share on other sites
It's really just a vague estimation, there's nothing special about the numbers, but the higher you raise the power the faster the cone dies off.

The value you get from the dot product will be between 0 and 1, and raising this to a power decreases the value. At 45 degrees you'll have a dot product of 0.707, to the 8th power this is just something like 0.06, which is close to zero. By 50 degrees its down to 0.02.

Basically just guess and plug in numbers till you find something that you like.

Share this post


Link to post
Share on other sites
Well the idea is the let an artist specify the angle and match that in the shader, so just trying a bunch of values isn't really an option. Anyway, thanks for taking a look. I was hoping there was some magic formula he used to arrive at those numbers, I guess not.

Share this post


Link to post
Share on other sites
With trivial algebra it's easy to solve the equation the other way around.

Right now you have cos(angle)^s = attenuation, you could take cutoff angle as an argument and solve for attenuation = 0.05 or something close to zero.

i.e.:

cos(cutoff)^s = 0.05
log(cos(cutoff)^s) = log(0.05)
s* log(cos(cutoff)) = log(0.05)
s = log(0.05)/log(cos(cutoff))
s = log(0.05/cos(cutoff))

So given a cutoff of 45 degrees, you'd get an exponent of 8.64, which is about what you found.

Share this post


Link to post
Share on other sites
That's the thing though, the 0.05 factor is completely arbitrary. Let's say I want to use 0.01 as the cutoff instead, that gives an exponent of 13.28, 0.001 gives an exponent of 19.92.

I guess I could base everything off of the 0.05 factor though since it apparently gives a good result for 45 degrees, and use that to set the scale for everything else. I'm just curious how other games/applications handle this. I know you can enforce a hard cut-off in the shader at that angle, but I don't think it looks very nice when the light just suddenly vanishes.

By the way, log(0.05)/log(cos(cutoff)) != log(0.05/cos(cutoff)

Share this post


Link to post
Share on other sites
Well yes it is arbitrary, but it's not something that needs to change a whole lot. You can't just use '0' because the value will asymptotically approach zero at 90 degrees, so you'll never be exactly zero before then. You just have to pick a value that is acceptable such that it's low enough that the cutoff is mostly unnoticeable. You can pick 0.01 or 0.05 or 0.0123 or whatever looks best to you, and use the same value for all degrees of cutoff. Either that or give your artists more variables than just cutoff angle to define the light distribution inside the cone.

You're making it into a bigger problem than it really is.

Share this post


Link to post
Share on other sites
It's a simple algebra. I started with this:

angle = arccos(pow(LIGHT_SPOT_THRESOLD, 1 / exponent))

with LIGHT_SPOT_THRESOLD a small value near to zero.

I don't remember how, but eventually I reached this:

m_spotExponent = log(LIGHT_SPOT_THRESOLD) / log(cos(halfFOV * DEGRAD));

So given halfFOV, you obtain the exponent. It works fine in my engine.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this