Capturing in-view light levels for a realistic exposure meter

Hi there. I’m currently working on a photography system for my game. I have a widget that has a meter at the bottom of it that I want to move between -2 and 2+ based on the brightness of what you are looking at. It doesn’t have to be accurate, I just want it to move based on the general light level.

My first thought was simply to shoot a trace from the middle and get the overall light level from whatever object it hits, or to possibly have a collision sphere wherever you’re looking and to see how much it overlaps any lights, but as a pretty newish dev I’ve no idea how to make these happen.

I’ve done some research and failed to find any direct answers. One of the more intuitive solutions was to get the actors distance from lights as well as each light’s intensity and then deduce it from that. This sounds solid, but I have no clue as to how I’d implement something like this. Anybody have any advice? Thanks in advance!

Use the plugin below, should work with 5.6 too. It would give very accurate results in terms of detecting light and luminance levels.

Simply you can create an actor, attach this Lightawareness component to it.
On mouse move, make a line trace cameraforward vector → normalize * 10000 +forward ---->SetActorWorldLocation(HitLocation)

Lightawareness->GetLightLevel

PS: Detecting light accurately is not easy as it seems in unreal engine afaik there is not built in method, could be something deep in megalights maybe (did not check). Since is no built in method, the nicest one is this plugin to detect light conditions on any actor independent of Light Source Type, Screen Effects and similar.

Other methods such as:

Getting light actors and checking distance or accessing their intensity, getting screen brighness etc still would not give you accurate results since light can bounce, reflect, depends on engine settings, angle and so on. This plugin is simply a reverse calculation.

Just cosmetic access can be done via:

Option A: You can get a very small render target on the object screen like 8x8 black and white, resolve pixels 0-255 and add all, then divide with 64 would be give or take the result you wanted.

Option B: Custom post process anode with eyeadaptation to output current exposure , this would be the least accurate on some cases however cosmeticly would work on most cases.

Thank you so much for recommending me this, it seems to be exactly what I’m searching for. I tried to initially install it in 5.5, but every time I getting told that the LightAwareness module is missing or built with a different engine version. When I say yes to rebuild I get this error:

Engine modules are out of date, and cannot be compiled while the engine is running. Please build through your IDE.

As a coding noob, this is really confusing and I can’t even find an .sln file to open in Visual Studio.

Interestingly, I installed it into 5.4, and I got the same errors, but after rebuilding it launched perfectly fine. I verified the 5.5.4 engine as some people suggested, but that didn’t do anything. I really would like to use 5.5, do you have any recommendations or should I ask on the Git page?

    • Download this content and overwrite to Drive:\YOURPROJECTFOLDER\Plugins\LightAwareness\Content
    • Rebuild your project, disable plugin if necessary

Sln (solution) is generated by IDE (Visual Studio) simply you can create a project pointing the project folder or you can just open .UProject

After opening project in VS simply you can click play (build) and it should recompile the projectwith the plugin as menioned " Engine modules are out of date, and cannot be compiled while the engine is running. Please build through your IDE."

You can ask here , its ok plugin creator is me.

Thank you for the help, so sorry for inconveniencing you still… I overrode the content folder, launched it and rebuilt it but I’m still getting the Please build through your IDE error.

I tried to open Visual Studio and open the project, but there is no .uProject file available to open. It simply doesn’t show up.

I attempted to Generate Visual Studio Project Files, but since I made the project blueprint based not C++ it says I need to add C++ source files to the project first. Should I remake the project with C++, or is there a different way for me to open the .UProject in Visual Studio?

You should be able to convert your project to C++

and you should have a .uproject file already over there, generate visual studio files and open as .sln or you can just show folder.
Better convert your project and open as .sln

It compiled and is working now! I can’t thank you enough! Though I am still having a bit of trouble with the plugin :face_with_peeking_eye:

I had some trouble following the directions you provided, so let me know if this is wrong. This isn’t the main problem though.

This is in my FirstPersonCharacter, which is where the LightAwareness component is supposed to be correct?

The issue however is that when dragging off of the LightAwareness node, there is no GetLightLevel function.

I’m so sorry to keep bothering you, I just really want this to work!!

Okay, I’m getting somewhere, though I think I’m doing the line tracing wrong. I used GetLightStatus instead and mapped the values between ±50.

Then in the widget, I set the position of the meters based on the float.

This is certainly moving the meter, but not in the right way. I assume I’m doing the trace wrong since it seems like the value is changing when it hits parts of the wall, and in this gif I have a light at one end of a room and darkness at the other, and the values don’t make sense.

In the instructions you wrote

On mouse move, make a line trace cameraforward vector → normalize * 10000 +forward ---->SetActorWorldLocation(HitLocation)

I don’t fully understand what you mean by >SetActorWorldLocation(HitLocation). I get the hit location, but what actor am I setting the WorldLocation?

Great news and you almost there,

So the LightAwarenessComponent if you added to FirstPersonCharacter its simply attached to the player. Thus it will move with the player itself not the position that you are looking at.

On the video you provided, simply when you walk the light values change, and when you rotate in place we can see slight changes in values cause it rotates with character too. Right now it should be like this.

Which we don’t prefer, we prefer it to be in a location we are looking at.

To actually get the locations light level that you are looking simply you need to place LightAwareness to the place you are looking basically with LineTrace →Hit Impact location

So what you need is to

  1. create a new blueprint class as actor. Let’s say name is PhotoLightDetectorActor_BP
  2. When you go photo mode, spawn this actor PhotoLightDetectorActor_BP as hold as variable in your FirstPersonCharacter. Better also PhotoLightDetectorActor_BP→GetComponentByClass(LightAwareness) and hold it as variable (LightAwarenessComponent).
  3. When line trace hits PhotoLightDetectorActor_BP→SetActorLocation to HitPoint
  4. Access LightAwarenessComponent→GetLightStatus

and you will be getting the accurate values of light.

For the settings of the component I would suggest the things below.

You got this, let me know.

PS: Upon exiting photomode→destroy(PhotoLightDetectorActor_BP) so you don’t have multiple spawned light detection actors that does nothing but once per session.

Thank you so much for the descriptive answers!! It’s beginning to work properly now and I couldn’t be more excited, though I still have a few small questions.

First, does the transform of the LightDetector_BP matter? I just used the default values here:

The other issue I have is with how real camera metering works. For a closer approximation to real life, the light level should be detected from the camera’s “lens”, not where the line trace hits a point.

I attempted to use a small line trace and just set the LightDetector at the TraceEnd, but it understandably tanked the performance. I assume putting the LightDetector in the Player and doing something like attaching it to a socket would be the proper thing to do, but is there any way I can change the top&bottom detection to just detect from one direction, straight forward?

(how its working currently. So close!)

I’m sure the plugin is insanely complicated, so sorry if I sound like I’m oversimplifying things. Once again thank you for the quick and detailed replies!

1 Like

That’s great I am glad that it is working and working as expected seems to be.

  1. While spawning transform doesn’t really matter, anyway you are setting actors location.

  2. You are getting light status on the tick, which I think it is unneccessary calculation every frame. I would recommend making a timer after the spawn, something like 0.1-0.2 seconds to get light status. Another alternative to that you can set LightDetectionMethod of the component to distance, so when position changes, it updates and you can bind to component update event automatically. (There is a demo for the plugin demonstrating usage cases in detail) If you prefer component updating itself like distance, after spawn you can bind to component updates like this

  3. In the LightDetector_BP on it’s LightAwarenessComponent, Sensivity→Low, DetectionDirection→Top with DetectionMethod→ManualRequest and if you request somewhat with lower frequency as mentioned 0.2 seconds, I think you will have more performing results out of the box.

  4. On you UI, when value changes you are setting indicator to new position. I am assuming either its an event or its on tick. Making location changes over FInterpTo would give you much more smoother results with the indicator (needle)

  5. In Real Life, camera exposures afaik works the same way, especially the digital age cameras. They basically sample spot, area or the entire screen depending on the choice available, so they get the light level and adjust timing on top of it. In digital cameras ofcourse we can see changes in real time (like in your project) and timing of exposure can be adjusted to achieve desired results (how much ligh should enter objective to added on top of the picture in order to achive correct light level)… In that terms your project right now works as a spot exposure meter.

  6. Well don’t worry and the plugin itself besides all the code, workarounds –> as working principle it is quite a simple plugin and does it’s job well. You put you hand under a desk lamp and you can understand how bright light it is by looking to you hand only. Ofcourse when you go deeper in to the subject and rendering it can get sophisticated like in everything. Till plugin renders the image, how lights calculated in the engine, how vertex is processed.. the deeper you go it can get sophisticated however this is not something hard but solves the problem nicely.

When I rethink about it, think I can have some time to enhance it even further as plugin creator. Maybe there can be some ultralight detection for the scenarios/use cases like your project. Also I can facelift my code abit or maybe built another one that can be experimental for me too which I thought about it but didn’t take that direction.

We can simply tap into the shader, which already getting histogram for the whole scene..define another one to just get a dedicated area, like a square box on screen and resolve light values over there. Which will give approximately the same results , in a longer way but more performant solve possibly. We can just solve area of interest back to screen cordinate and would be a local exposure histogram just like the phone digital cameras where histogram detects the object area and adjusts.

Howeverr LightAwareness is built for more than that, for gameplay reasons, such as :

  • AI : Stealth purposes, AI logic of avoiding light or dark areas, reaction to light etc.
  • Gameplay : logic as entering a cave automatically wielding a torch or flashlight. An actor changing state when exposed to light, revealing a hint or completing a quest. Somebody was doing something related to photosynthesis sim, you gain energy when you are in light etc.
  • Dynamic World : Extracting data of world light conditions, changing behaviours of vegetation, day and night time changes. Shader adjustments depending on the scene , weather and time of day.

Let me know if you can make it work better with the instructions or you need further assistance around it.

1 Like

Wow! I feel like a broken record but again thank you so much for all this help! I made some changes and it’s working ALMOST perfectly! This plugin really is amazing!

The only problem I’m having now is fInterping the meter (needle).

Here I have my LightDetector_BP (top screenshot) and my FirstPersonCharacter (bottom)

Then, this is the function I use to move the meters inside of my WBP_Viewfinder.

I see in the screenshot you uploaded, you use eventTick to fInterp. I could understand doing that, but how would I get the target light value every tick if the detector is only moving based on change in distance? With that in mind, I don’t think the needle needs to move every tick, since the fInterp should make it look smooth regardless. However, this is how it’s moving with the current settings above:

I’ve only used fInterp for moving static meshes, so I don’t fully understand it. If I could just get a bit more of an explanation on how to use it, it should be the last of the issues. Thank you for documenting all of this useful information!


Try to put this on tick and pass tick delta time to Finterp. Make LightLevel in ViewfinderWBP a global variable and update variable directly from GetDetectorLevels event in your character. Don’t run function so on tick interp will run according to your updates of target new light level value. Thus it would appear smoothed.

You don’t need to get light value every tick since it would be unneccesary load however UMG can update on tick.

Also additionally if you want smaller delta distances for updates you can decrease variable on component ``DistanceDeltaForUpdate```

1 Like

That got it working! Thank you so much for all the help this past week! Cheers!

1 Like

Oops! One more thing @RedGrimnir ! Am I able to hide the LightDetector in scene capture? You can see the light detector showing in the scene capture I have inside the polaroid frame in this clip:

No worries, couple of ways you can approach it to solve your design problem.

I am not sure how you do photomode, seems you are making another scene capture.

Simply you can do Capture->HiddenComponents.Add(MeshComp);

set you capture to RenderPrimitives this have option to hide components

However as a side note, think about if you really really need a render target every frame, it is a very costly thing to capture scene, you can maybe use a normal camera and upon action “take picture” you render frame once with the hidden actor of detector from scene capture (or you can even destroy light detector one frame before take snapshot)

Happy developing.