- Home /
What is the proper way of calculating attentuation in Unity3D non-surface shaders?
In a CG vert/frag shader (NOT a surface shader), what is the proper way of calculating attenuation such that point lights with a small range do not cause hard edges to appear when the whole or partial light range is in view?
I have seen most examples of calculating light attenuation in Unity based on whether there is a directional light (1.0 attenuation) or point lights (subtracting _WorldSpaceLightPos0.xyz from world position and using the magnitude as distance). However, calculating attenuation for point lights in this way seems to have some strange behavior when fully or partially enclosed in view and stops flat instead of smoothly disappearing. Is there a better way of calculating it or perhaps a lighting macro in Lighting.cginc or another unity include I'm not aware of?
if(_WorldSpaceLightPos0.w == 0.0){ //directional light
atten = 1.0;
lightDirection = normalize(_WorldSpaceLightPos0.xyz);
}
else{
float3 fragmentToLightSource = _WorldSpaceLightPos0.xyz - IN.posWorld.xyz;
float distance = length(fragmentToLightSource);
atten = 1.0/distance;
lightDirection = normalize(fragmentToLightSource);
}
Have you looked at the standard attenuation math? It's been pretty well set for a decade, and not too difficult to read. The 1/(1+AD+BD^2) formula, where you tweak A and B.
I'd guess that just 1/D isn't giving enough fall-off. Then the "box" is Unity saying "O$$anonymous$$, the light is done for sure by now -- stop using it."
What factors do A and B represent in that equation? I've looked at some of the standard math, but this is what I was presented in the overwhel$$anonymous$$g majority of the tutorials I've seen for Unity CG shaders as how to calculate attenuation. Thank you for the plug on better attenuation formulas though, I've found better research for them since you posted. I've found since then that its not simply an attenuation problem anymore. See the updated question from my profile in just a moment.
A and B are just tweaks. Dividing by D^2 is real-world correct, but can give too small a circle. Dividing by D makes the light go a little too far. Dividing by D^1.8 might work, but a pain to compute. So, use a mix of /D and /D^2, deter$$anonymous$$ed by A and B.
1/(0.2D+0.8D^2) will be a little more puffed-out that just 1/D^2. If they don't add to one, no problem, but it just cancels out the brightness on top and makes it harder to read.
So A and B are user-set constants set to achieve a certain type of fallof then? I saw this equation on a few sites referencing OpenGL's default light attenuation, but I guess I didn't understand that the linear and quadratic factors were actually user manipulated.
Your answer
Follow this Question
Related Questions
CG Programming, Points Lights attenuation and light range 3 Answers
Shader that renders fragment behind 0 Answers
Need help with this Shader; camera Solid color is being rendered on skybox. 0 Answers
Find out if an object is in front of a target in fragment shader? 0 Answers
Blend textures in shader 0 Answers