This site uses strictly necessary cookies. More Information

X- 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 overwhelming 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, determined 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

### Welcome to Unity Answers

The best place to ask and answer questions about development with Unity.

To help users navigate the site we have posted a site navigation guide.

If you are a new user to Unity Answers, check out our FAQ for more information.

Make sure to check out our Knowledge Base for commonly asked Unity questions.

If you are a moderator, see our Moderator Guidelines page.

We are making improvements to UA, see the list of changes.

### Follow this Question

### Related Questions

Refraction Shader. Strange Artifacts 0 Answers

_LightMatrix0 and Directional Light 1 Answer

Detailed gradient shader 0 Answers

CG: How to NOT write the pixel 1 Answer

Best way to make an unlit Cg shader 2 Answers