How can I access the properties of point lights or spot lights in a shader?

Hi . I would like to access the properties of lights in a shader. Properties like positions, attenuation , etc.
I know I can access them up to 4 point lights or spot lights but if I want more than four, How can I handle that?
and How can I access to directional light/directional lights intensity in a frag shader?

Normally you can access only one real time “important” light at a time due to how Unity’s forward rendering path works. Non-important and/or the first four brightest non-directional lights after the per pixel lights get put into the per vertex light values and can be accessed in the forward base pass. The per vertex lights are only approximations in terms of the attenuation and spot light cone compared to the per pixel lights. The per vertex lights use an effectively infinite falloff curve where as per pixel lights use a range and a fall off curve stored in a look up texture.

The brightest directional light is the _WorldSpaceLightPos0 and _LightColor0 values in the forward base pass, and additional per pixel directional lights use the same two variables in forward add passes. Otherwise they get baked into the spherical harmonics used for ambient lighting and there isn’t a way of extract these at all.

The upcoming HD and Lightweight scriptable render pipelines pass all of the necessary lights to the shaders so the “base” pass has access to them. If you move to those renderers it’d be possible to get access to more lights, but neither are really ready for use. For now you’ll need to collect the data yourself using a C# script and pass it to your shader(s) manually.

2 Likes

Thank you. So if I have ten important point lights (I have selected important in the inspector), I can not access them in a frag shader? or change the number in quality setting

You can’t access all of them at once, no. One at a time, yes, and only if they affect the particular mesh (bounds overlap, same layer, etc), and the number of affecting lights does not exceed the Pixel Light Count in Quality Settings.

Unity’s forward renderer does multiple per pixel lights by rendering a mesh an additional time for each light with the forward add pass. So each pass only has access to one light at a time (always stored in the same _WorldSpaceLightPos0 and _LightColor0 variables).

If you’re using the deferred pipeline and a deferred compatible shader, then no per pixel lights are accessible at all when a mesh is rendered since that’s handled later and each light is effectively rendered on it’s own reading from the gbuffers.

1 Like

https://docs.unity3d.com/Manual/SL-UnityShaderVariables.html
I can see differently.
unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0 ->They are float4 for four point lights. We do not access them at same time, therefore why were they defined?! or you mean if I want to access “important” lights I need to use several passes in forward rendering with _LightColor0 and _WorldSpaceLightPos0.
The docs is so awful and confusing.

In my previous post I was speaking specifically about important lights, which is what you had asked about. Those are only accessible one at a time with the built in variables. As you noted at the start, up to four __non-__important lights can be accessed at once.

Again, if you want more than the 1 important (or auto) directional light and 4 non-important point lights accessible in the base pass you must manually collect this data and pass it to the material yourself using a C# script.

Technically you could also set your shader to use “LightMode”=“Vertex” and have access up to 8 point, spot, and/or directional lights in one pass.

1 Like

Perfect Thank you