Jump to content
The Dark Mod Forums

How Does the Light Awareness System (LAS) Work?


Alkalide
 Share

Recommended Posts

I'm not sure if this should go here or in the Tech Support section, so If this is the wrong place, please let me know.

 

As a hobbyist game developer, I'm curious about how the Light Awareness System works in The Dark Mod. I've been poking through the source code, but haven't found any definitive math explaining it, or code comments mentioning on how it's calculated. If anyone could point me to exactly where to look, or could explain what steps and/or math it's using to calculate how visible the player is, I'd greatly appreciate the insight.

 

For reference, I'm trying to implement a similar system in my own stealth game I'm working on in Unreal Engine 4.

Hobbyist game developer, 3D artist, and electronic music producer. Fan of action-adventure and stealth games.

Link to comment
Share on other sites

Start with idAI::PerformVisualScan().

 

AI perform this every time they think, to determine if they can see the player.

 

Inside the method, look for

 

// Check the candidate's visibility.
float vis = GetVisibility(player);
That determines how much light is on the player, and whether the AI can see the player in that amount of light.
Our AI go through stages of alertness, so it takes quite a few 'sightings' before the AI registers that it's the player he's looking at. This prevents instantaneous sightings, and allows the player to do something like "step out of hiding for a brief moment, then scoot back into the darkness", which raises the observing AI's suspicion that someone might be there, but doesn't let him leap all the way to the conclusion that it's an enemy.
  • Like 3
Link to comment
Share on other sites

Start here:

 

http://wiki.thedarkmod.com/index.php?title=Visual_scan

 

The general process is:

 

1) Check whether it's the correct "turn" to capture a lightgem image (lightgem interleave)

2) Hide the player model and weapons and replace with the lightgem model (octahedron)

3) Hide non-essential surfaces and particles

4) Move the camera inside the lightgem model and aim it upward

5) Capture a screenshot to a buffer image

6) Find the brightest pixel in the buffer image and map it's brightness to one of the brightness range numbers

7) Apply biases for weapon drawn, crouch, player speed, etc to the lightgem value

8) (AI Thinking) Draw a visibility cone for each eye

9) Trace from the lightgem model to the origin of the visibility cone

10) If any opaque objects block the trace, player is invisible

11) If the trace completes, check the lightgem value from step 6

12) If the value is x then set alert level y. Fully visible == Fully alert

13) Repeat steps but aim the camera downward for step 3

  • Like 1

Please visit TDM's IndieDB site and help promote the mod:

 

http://www.indiedb.com/mods/the-dark-mod

 

(Yeah, shameless promotion... but traffic is traffic folks...)

Link to comment
Share on other sites

Good info, but I think I have the wrong term for what I'm trying to understand. I'm interested in how the the game calculates the level of light hitting the player.

 

As I understand it, the old Thief games used checks on the lightmap value immediately around the player. I've seen more modern examples get an array of lights from within a certain distance of the player, subtract the occluded ones, get the parameter values of the unoccluded ones, compare the player's position to the attenuation radius of each one, and calculate the player's light level based on some formula I don't know (probably some arbitrary values set by the developer.)

 

Does TDM do something similar to that?

Hobbyist game developer, 3D artist, and electronic music producer. Fan of action-adventure and stealth games.

Link to comment
Share on other sites

Hey Alkalide,

 

The process that nbohr just went through *is* that process :-). Basically there is an invsible octahedron where the player is. Every time the player litness needs to be calculated a camera looks at that octahedron (from the top and bottom), checks the pixel brightness of that octahedron and uses that to determine how well lit the player is. I actually cobbled together a similar system in Unity (which I ended up not using), so it is definitely possible to do something like this in Unreal, but keep in mind it is a little bit clunky because natively neither Unity or Unreal has the ability to get lighting data from shaders so you end up having to do something like what TDM does (having a separate camera look only at a player object and read the screen pixels to determine brightness).

 

Edit: when thinking about litness detection, it's important that you delineate baked lighting from dynamic lighting. With baked lighting you can (at least in Unity) do the exact same thing that the original Thief games did - raytrace to the lightmap and grab the color of the pixel. With dynamic lighting (and all TDM lighting is dynamic) there is no light map to pull data from so you have to resort to these sort of hacky tricks (like a separate camera looking at a model such as TDM does, or using triggers to create "light volumes" to detect when the player enters a light,etc).

 

If you're using a mix of both baked and dynamic lighting, you might have to have two systems working side by side to get the most consistent results.

 

An added wrinkle: both Unity and Unreal have different tricks that they use (such as manually placed light probes in the case of Unity) to illuminate dynamic objects with baked lighting - this can create a bit of annoyance because it means that how well lit the player model is won't necessarily match up to the baked lighting at their feet.

Edited by Moonbo
  • Like 2

But you should walk having internal dignity. Be a wonderful person who can dance pleasantly to the rhythm of the universe.

-Sun Myung Moon

 

My work blog: gfleisher.blogspot.com

Link to comment
Share on other sites

I guess if you want to do this without rendering first, there are a few things you can glean from tdm_lg_weak.

 

void idPlayer::CalculateWeakLightgem() in Player.cpp.

 

It's not quite as accurate as the main lightgem we use which is rendering screenshot images.

 

In Thief DS, I recall they would sample a render of a bone and then combine

the different bone samples for a final light value. So, a little bit like us. Render then sample.

 

In a modern engine, I guess you would use a compute shader to generate a sample from all the scene render inputs.

  • Like 1

Please visit TDM's IndieDB site and help promote the mod:

 

http://www.indiedb.com/mods/the-dark-mod

 

(Yeah, shameless promotion... but traffic is traffic folks...)

Link to comment
Share on other sites

Ah, thanks for clarifying; I get what's going on now. And I think I should be able to come up with a similar system in Unreal based on what's here. I might post a thread about the stealth game progress in the Off-Topic section here eventually if anyone's interested in seeing that.

  • Like 2

Hobbyist game developer, 3D artist, and electronic music producer. Fan of action-adventure and stealth games.

Link to comment
Share on other sites

  • 4 years later...
On 5/25/2017 at 10:50 PM, Moonbo said:

Hey Alkalide,

 

The process that nbohr just went through *is* that process :-). Basically there is an invsible octahedron where the player is. Every time the player litness needs to be calculated a camera looks at that octahedron (from the top and bottom), checks the pixel brightness of that octahedron and uses that to determine how well lit the player is. I actually cobbled together a similar system in Unity (which I ended up not using), so it is definitely possible to do something like this in Unreal, but keep in mind it is a little bit clunky because natively neither Unity or Unreal has the ability to get lighting data from shaders so you end up having to do something like what TDM does (having a separate camera look only at a player object and read the screen pixels to determine brightness).

 

Edit: when thinking about litness detection, it's important that you delineate baked lighting from dynamic lighting. With baked lighting you can (at least in Unity) do the exact same thing that the original Thief games did - raytrace to the lightmap and grab the color of the pixel. With dynamic lighting (and all TDM lighting is dynamic) there is no light map to pull data from so you have to resort to these sort of hacky tricks (like a separate camera looking at a model such as TDM does, or using triggers to create "light volumes" to detect when the player enters a light,etc).

 

If you're using a mix of both baked and dynamic lighting, you might have to have two systems working side by side to get the most consistent results.

 

An added wrinkle: both Unity and Unreal have different tricks that they use (such as manually placed light probes in the case of Unity) to illuminate dynamic objects with baked lighting - this can create a bit of annoyance because it means that how well lit the player model is won't necessarily match up to the baked lighting at their feet.

Hi, sorry for being a little late to the party :D

I found this thread very interesting. You mentioned "I actually cobbled together a similar system in Unity (which I ended up not using)".
What did you end up using if I may ask? And why did you abandon the octahedron capture method in Unity?

Regards,
Stepan

Edited by Gooren
Link to comment
Share on other sites

Hey Stephan,

So, as to why I abandoned the octahedron method, it was mainly because Unity's dynamic lights are really expensive from a performance perspective. If you have more than one or two on-screen at any given time performance starts to tank. Most Unity games get around this by mixing up dynamic lighting with baked lightmaps + light probes to light up dynamic objects. But that would mean having to create two separate lighting detection models: a octahedron-esque system for dynamic lights, and a "raycast down to get lighting info from lightmaps" for baked lights (which is what the original Thief games did). And then what about light probes? I would probably include their impact in my dynamic lighting stream, but then I would need to be REAAALY sure that I had placed all my light probes the right way in every instance to make sure that they were properly lighting up my octahedron. So it was a choice of sticking with either just dynamic lights (poor performance) or just baked lighting and not have any light probes, which didn't match with my vision for the game.

Thankfully, my game is 2D which meant that rolling a custom solution that I could tailor for ease of getting lighting data wasn't overwhelming. What I ended up doing was making all the lights in my game actual meshes (something like this: 

but I generate them using an optimized clipping algorithm instead of blasting out raycasts. It's then just a matter of checking the uv coordinates of all light meshes at the player's location. This turned out to be a really fast calculation, so worked out well in the end :-).

Here's some footage of the system in action - the little circle indicator above the player's head shows their visibility, a mix of their movement speed and lights hitting them:

 

 

Hope this helps and let me know if you have any other questions!

-Gelo

Edited by Moonbo
explain where light gem was
  • Like 3

But you should walk having internal dignity. Be a wonderful person who can dance pleasantly to the rhythm of the universe.

-Sun Myung Moon

 

My work blog: gfleisher.blogspot.com

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

  • Recent Status Updates

    • Nort

      I want to be a fish, but I'm not a fish. My mom wants to be a fish too, and so she's killing herself eating plankton and sh***ng blood, and tells me to stop nagging her about taking her medication. I spent several hours today, just lying in bed, having anxiety over just existing, and not being a fish. You fish, you don't know how lucky you are. You can eat all the plankton you want. I tried eating plankton again yesterday, and I just got sick. I hate being a shark.
      · 0 replies
    • Nort

      I just gave myself vertigo. A pleasant kind of vertigo, like the world has been lifted off my shoulders. I'll explain:
      Yesterday I saw to my dismay, that I had made my entire map two - two - units too short on every level - that every set01 piece was sticking 2 units into the ceiling. That's basically 402 brushes that needs to be realigned (minus the ground floor brushes).
      I knew enough about selections to do all of that in a very tense five minutes, and it compiled without leaks. (Thank you so much, Dark Radiant devs, for making an editor with such care for precision that you can align hundreds of brushes perfectly at once (which is not something I can say for Valve's Hammer editor, which has some serious issues on that front, which actually made me just quit it in disgust).) However, the result is that the entire level has now been stretched a barely noticable 2 units, and it will take some getting used to psychologically.
      · 0 replies
    • Nort

      My workflow is basically running from a chain of disasters, eventually trying to seek shelter in former disasters. It's not ideal - it's just my life.
      When I abandoned my first map, it was out of a typical mental breakdown, and so I returned to find a skybox void where the kitchen door should have been (due to a misplaced visportal) and two overlapping brushes Z-fighting on the kitchen floor.
      I've now cleaned up the last bit of mess, by cleanly separating every floor into its own layer. Now I can finally work on each floor in peace.
      ...not that I really needed to. Once you get skilled enough, the orthographic messes, well, I'll let this video speak for itself:
       
      · 1 reply
    • Nort

      Beams, beams, beams...
      Support beams, and cross beams, and then beams to fixate the support beams to the cross beams. The more beams you have in a map, the better. There's walls, floors and ceilings, but the rest of the map is pretty much just beams. Beams makes a thief happy.
      · 0 replies
    • jaxa

      Embracer Group is Buying Square Enix Montréal, Eidos, and Crystal Dynamics for “Only” 300 Million USD: https://wccftech.com/embracer-group-square-enix-montreal-eidos-crystal-dynamics/
      · 1 reply
×
×
  • Create New...