- Home /
Mesh based volumetric lighting with RenderTexture
Hi there,
I have problem with the lighting which I implemented. I have a 3 dimensional space full of objects. The player's vehicle emits some lights, which are made of a 3d mesh and rendered with gradient texture. The implementation that I made, which works fine but is not performance wise, uses 2 render textures. One is used for rendering the scene, the second one only for lights and the final result is a combination of those two. Now, as I said the problem is with the performance, and also with the objects witch obscure the light cone (my light mesh). Those objects are closer to the camera eye, so it being obvious they shouldn't be lighted up (I've managed to 'get rid' of this problem using Layers, but still the performance is my current issue).
This morning I've been thinking how can I get it work, so that performance wouldn't be an issue any more. I figure out that I could render the world to the main render buffer. Then the lighting to a separate RenderTexture with depth information taken from main buffer (usage of Camera.SetTargetBuffers). This should prevent light being drawn on the objects which are closer to the camera eye). Finally I would render my light from RenderTexture into a simple rectangular mesh properly aligned with the main camera.
The bottom line is, it doesn't work... I'm not sure but maybe it's not possible to write to the RenderTexture object and at the same time utilizing the information from the main depth buffer (Camera.SetTargetBuffers(cam.targetTexture.colorBu ffer, Display.main.depthBuffer) ? idk... Any help or a solution highly appreciated!
It's not totally clear what effect you're trying to achieve and why you can't just use shadow casting lights. Can you post some screenshots here to help us understand the look you're going for?
I'm attaching two png files, one from the editor scene view and the second from the game window. Now...
The cube embodies the player which emits lights. Those lights are comprised of a regular mesh and a translucent material. Furthermore, two spherical bodies represent scene entities (enemies, obstacles etc). In the camera view the one closer to an camera eye has a lighting imprinted on it. This is of course not expected, but given the current implementation (explained above), unavoidable. The one further away is properly lighted up as this is what I want to achieve in my game.
The textured 2d rectangle visible within the editor is a result of combining two render textures: world render texture * (light texture (light mesh rendering result) + Color). This implementation gives me the opportunity to dim/obscure the scene entities outside of the lighting cone and leaving the ones from within it (by Color value manipulation).
If something is unclear please let me know and I will try to explain it more clearly. Of course the question stays the same: performance and the depth issues.
It looks like there was a problem with those images. Can you repost?
Answer by MakeCodeNow · Feb 19, 2014 at 04:25 PM
So, I think I understand what's going on here. I have two responses, hopefully one of them is helpful.
It sounds like you're basically trying to implement deferred rendering. If so, what you want to do should be possible with unity, and you can, AFAIK, re-use depth across cameras (as long as you don't clear it!). You should read up more on light-pre-pass and light-post-pass deferred rendering.
However, since Unity already has deferred rendering, I'll suggest a more conventional and possibly easier path. Most games in this situation use a dynamic spot light at each headlight. This allows it to light up other objects. Then, each headlight also has a light cone mesh (as you currently have) which represents the visible cone of the light (due to atmospheric light scattering). The light cone mesh is emissive/self-illuminated so that it stays bright in dark environments. If you need to turn the headlights on or off, you just update both elements together.
Lastly, there are much more sophisticated ways of rendering dynamic volumetric lights. There's even a very good product on the asset store that does this (called V-Lights).
It seems that the second approach you're pointing out could be what I need (with the meshed light cones). I have a question though, how it will impact the game performance on mobile, as I will have several light sources on my scene. Additionally all the objects that will end up within the boundaries of the light cone will be shaded based on the position of the light. What I want to achieve though, is to have them lighted up evenly (without the shades). To be more precise, on my scene there is one main directional light. Then at some point in the game all the scene gets darker and the light cones show up. And within those cones I would like to have my objects shaded using my main directional light. Can it be achieved?
Dynamic lights (deferred or otherwise) will be expensive on mobile. However, it seems like that's not even what you want/need.
If you want to take a more logic/CPU approach, you should make a cone shaped collider set to be a trigger and put that on each spotlight. Put a component on the light code that implementes OnTriggerEnter and OnTriggerExit. When it gets dark, put all objects in a layer that's not affected by the directional light. When you get an OnTriggerEnter, move the affected object into the layer that's affected by the directional light. When you get OnTriggerExit, move it back into the "dark" layer.
I'm trying stick to the meshed cones approach combined with the usage of spot lights. Unfortunately I'm having a bit of a problem with my toon shading. Objects that are affected by directional light only are properly shaded. On the other hand, those that are lit through the spot lights seems to take advantage of Lambert shading model. Here's the code of my surface lighting:
half4 LightingRamp (SurfaceOutput s, half3 lightDir, half atten) {
half NdotL = dot (s.Normal, lightDir);
half diff = NdotL * 0.5 + 0.5;
half3 ramp = tex2D (_Ramp, half2(diff)).rgb;
half4 c;
c.rgb = s.Albedo * _LightColor0.rgb * ramp * (atten * 2);
c.a = s.Alpha;
return c;
}
You need to implement at least one more lighting function for view dependent sources.
https://docs.unity3d.com/Documentation/Components/SL-SurfaceShaderLighting.html