- Home /
Change intensity of one light on specific objects
I have a somewhat open pseudo-2D world with caves (think minecraft, but constrained to 2D) lit largely by a directional light. For the outside, this is fine, but in the caves I want to use various point lights for the main source of lighting.
Outside / inside areas are continuous, and may be above / below each other (relative to the light). I define them with simple custom script that interpolates or sets a value over an area (so I can easily make gradual changes from outside to inside).
My issue is how to get the "inside" geometry to be less affected by the one directional light, but remain affected by other lighting. Is this possible? I'm open to shader solutions or whatever really.
What I've seen suggested for interior geometry seems to be either using a different layer, or shadows, but neither will work in this case.
Thanks!
im guessing he can't distinguish interior from exterior to allow it to be layered. if thats the case the problem is really seperating inside from outside. until you do that its not possible
As I understand it they're a binary thing. Either something's inside or outside. I want to use a float value from 0.0 to 1.0 to control the main light's contribution.
$$anonymous$$y best idea so far is to actually remove the main light, implementing it in a material by changing properties. I guess I'll have to write a custom surface shader that puts the resulting value in emission, or something.
Right well a shader should be able to do that. But you'd have to do the lighting yourself either affect all directional lights or the directional light most important to the objects.
Basically on a per pixel basis you need to compute the impact of a number of lights on the pixel being coloured. The lights position can be found in unity_LightPosition[0] (to n) and that is a float4 where the w component is 0 for directional lights. Normally you multiply the fragments position by that w component and take it aways from the xyz to get the distance and direction to the light - hence directional lights don't have a distance.
The easiest code would be to have a shader property for the impact of directional lights and then for each light with a 0 w you would multiply the lights impact by your float variable. If you wanted to affect only one directional light you'd have to detect if you'd seen it yet in a loop.
This all sounds pretty expensive at the fragment level.
So you could write a shader that ignores directional lights at the fragment level and calculates their impact in the vertex part of the shader. It would them pass this information to the fragment shader which would only shade point lights and add on the extra illu$$anonymous$$ation of the directional light.
unity_lightXXX[0] is the most important light, [1] the next and so on.
Answer by Matthew A · Mar 18, 2013 at 10:03 PM
In the end I went with my original idea - disabling the directional light in the scene, and using a surface shader to manually applies it from material properties instead.
After trying to use an editor script to apply properties to every material in the scene (waaaay too slow), I switched to using MaterialPropertyBlocks and Graphics.DrawMesh to draw everything. Which was a pain to set up (e.g. objects silently don't render if you put an invalid property in the block), but worked nicely in the end.
A GlobalLighting script is available for query by moving objects which need to update their directional lighting. Other objects are given a fixed value when the level is generated. (All the values are read in from a painted texture, so I can change the light color quickly and easily).
After this I do rather wonder why MaterialPropertyBlocks aren't just built into the standard pipeline instead of forcing you to use DrawMesh. Yet another questionable Unity design decision I guess... :-/
I still haven't considered shadows yet. Not sure how I'll go about doing that.
Answer by Omir · Mar 16, 2013 at 07:57 PM
Use Shader , It will be more efficient and cool then using basic scripting