We are developing a first-person diving game using Unity HDRP, and we need some advice on how to implement an underwater flashlight to help the player illuminate the sea floor during exploration.
We’ve tried using Unity’s point lights and achieved a satisfactory result by setting the intensity to very high values. However, this approach causes some objects to react as if “holding a powerful sun in hand,” resulting in blinding reflections for the player.
Does anyone have solutions to address this issue? We are open to trying different approaches as long as they are effective. Any help or suggestions would be greatly appreciated!
Using light layers sounds like an interesting approach. Unfortunately, due to project constraints, we can’t exclude objects from receiving the flashlight in this way. Do you have any other ideas or alternatives that could help us achieve a similar effect without using light layers?
So, the reason you need to have a spotlight with high intensity is because your water has a low absorption distance (based on your video). What you need is to use a reasonable spotlight intensity.
So you can either increase that distance (or increase the absorption distance multiplier in the underwater section) and thus reduce that spotlight intensity since there’s less fog to go through.
OR, you can maybe use a local volumetric fog tied to the spotlight (like in overwrite mode with a huge fog distance) thus removing the fog in front of the spotlight to be able to reduce that spotlight intensity. In an ideal world this local volumetric fog should match the shape of the spotlight cone so that it’s “invisible”.
If I understand correctly, the reason my flashlight doesn’t illuminate with a reasonable intensity is because the fog absorbs too much light? So your advice is either to do an override with a local volume attached to the flashlight that overwrites the fog values in the illuminated area, or to manage the fog values. The idea of trying to override with a local volume sounds great.
I believe you got it right, indeed. “Hard” part would be probably be to reproduce the spotlight cone procedurally and hoping that we don’t see a seam with the froxel, but it can may be masked by having a larger “fog substraction cone”, idk.
Thank you very much for the responses and suggestions.
I did some tests with the behaviors you recommended, and it turns out that the issue isn’t with the fog absorption but with the light exposure. The person who set up the volume for the underwater effect set the exposure very low, which causes this problem. The fog is only used to hide the edges of the map.
Do you have any advice on how to correctly set up the volumes for scene exposure? Currently, we are using two volumes: one that manages the outside of the water and another for the underwater side.
Thank you for the advice, and I apologize for not responding sooner, but I was running tests and don’t work over the weekend. I followed your suggestions exactly: I set up an automatic exposure with min and max limits for the exterior volume and an automatic exposure without limits for the underwater volume. I also set the sun’s intensity to decrease based on the depth. Now, even with a “normal” light, I have a fairly functional flashlight.
One issue remains: I wanted to use the fog differently in the underwater volume and liked your idea of using a volume tied around the flashlight to push the fog away. However, I couldn’t manage to achieve what you described, specifically the tied behaviour. Do you have any advice on this?
You need to create a Local Volumetric Fog volume, set it to overwrite and set it to a much higher fog distance so that there’s less fog in the volume than around it.
Then, puting this LVF as a child and at the origin of your spotlight will make it follow to movement / rotation of the spotlight.
Lastly, to tweak it better, you need to use a texture or a material to make the shape of the LVF roughly match the cone of the spotlight.
So… @chap-unity if I may ask a follow up on that.
One thing you mention seems consistent with what I see, but to me, makes not sense.
That is true (ish) for any light that exists outside of the water, sure. Let’s assume air doesn’t absorb light but water does.
But that assumption breaks down when the light is under the water. In my case I kill the sunlight, set a camera + spotlight + mesh and I get to see how both direct and GI light get dimmer the further down the spotlight + receiver + mesh combo gets. Close to the surface it is really easy to see the effect of the spotlight, at 10meters it is harder, at 100 the spotlight is essentially muted.
Again, there’s no directional light, just a couple of objects whose relative positions don’t change as they go further down into the water.
Now, the absorption distance the light travels: light->object->camera remains the same, I don’t see any reason to make the water more absorbent the deeper you go (which is also not the way water behaves)
so.. is that a bug? is there a proportional turbidity to depth (maybe?) setting that I can control?
I took the time to investigate a little, and from what I’ve seen, the way it’s been done doesn’t take into account the fact you can bring a punctual light with you along with the camera to the depths.
The attenuation is directly proprotional to the water depth regardless of light position thus why the spotlight gets attenuated.
I will log something and see what’s actually possible or not but from my onw point of view, it indeed feels like a bug and not a limitation of the system. I’ll keep you posted.
Yep, so there’s been some discussions and currently, there’s no simple way of doing what we want (basically know if the light is also below the water surface and attenuate it based on its distance to the camera). I say simple way because we could technically, but it would end up being super costly for everyone and useful for very few people.
What I would suggest, if you are game to customize stuff, is to tinker with the HDRP files. For example, if you don’t have a dir light and only have spotlight underwater. You can modify the behavior to get rid of the depth attenuation for example.
You can poke through the file called com.unity.render-pipelines.high-definition\Runtime\Lighting\AtmosphericScattering\AtmosphericScattering.hlsl
In there, look for the keyword SUPPORT_WATER_ABSORPTION and opticalDepth variable, you should be able to modify some of the behavior for all the lights at once.
Hey man, thanks for getting back to me.
I think you guys might be thinking weirdly about one detail, though. It isn’t about whether it is costly and not useful to a lot of people, I think it is more about what is correct. I would humbly propose this is about the system behaving “as expected”, and not so much about making it “cheap and okay looking”, (maybe?) particularly not for HDRP. And you can always throw it as an optional #define
I’ll dig into the code and will see what I can find.
Thanks!
Yep, sometimes, correct is just too costly as well :).
Think about having accurate / correct shadows, raytracing can do that but is too costly for most. Shadows maps are the cheaper alternative !
Yes, but it depends on what you are trying to solve. I’d agree that shadows and, dunno, order independent transparency are algorithmically hard but I’d argue what you guys have (though I am not aware of all the details) is not a cost thing, is a complexity of implementation issue.
I have proper underwater abortion/scattering setup in a different project (done with URP, running on mid-end mobile) and there’s essentially no cost associated with doing it right