Friday, February 17, 2012

SKYRIM CK - Scripting Tutorial - Dynamic Lighting (With Video)


Example Lighting Layout (1 - 8 are shadow casting lights, and A - C are scripting triggers to control the lighting)

Skyrim looks good, but it can always look better.  One thing we can do is add some more dynamic lighting to scenes to increase realism.  However, by doing this, you will quickly learn about one the engine's biggest limitations:

You can't have more than 4 shadow casting lights visible at a time (usually).  Otherwise, the engine will choose which lights to kill based on viewing angle, distance to player, etc.

"Ok", you might say, "I can live with that."  Actually, you can't.  Or, not if you want to add significantly more dynamic lights.  You'll just end up with flickering lights everywhere -- which introduces the engine's next biggest flaw:

The engine is particularly unclever about when and which lights to drop, when left to its own devices.

Thankfully, the CK is powerful enough to allow us to create our own tools to help us out.  Items labeled A, B, and C examples of these tools which I created.  LightingBallControllers (in yellow), and their accompanying LightingBalls (in blue) allow me (and you) to directly control the lighting in the area.

How they work:  Simply put, the LightingBallControllers talk to their LightingBalls (again, these are in blue), and the LightingBalls talk to the lights.  Each LightingBall  has a set of references for lights in the area (set in the object's script properties window).  As a player passes through one of the LightingBallControllers, they interact with their attached LightingBalls (up to 4) to find which set of lights to enable and disable.  It does this by answering the question: "Which ball is the player closest to?"  When it gets its answer, it tells that lightingball to enable the lights it controls.  Also, it tells each of its other lightingballs to disable their lights.

A controller can have anywhere from 2 - 4 balls, and each ball can control from 0 - 4 lights.

Advanced:  Also, each ball can be separately configured to ignore disable and/or enable commands from its controller.  To have 0 lights on a ball, both specialCases flags have to be set on the ball.  Also, two or more controllers can talk to the same lightingball.

It's powerful because it's so simple, and because they work with any object.  So, there's no need for custom scripts on the lights!  You just set up your lights normally, then drop down your controllers and balls.  Once you show the controller where their balls are and show the balls where the lights are, they'll do their magic.  I call this process rigging.

Advanced:  Nothing's stopping you from rigging a ball to any ObjectReference, so it doesn't actually have to be a light.

An example how the LightingBalls could be rigged to five
dynamic shadow casting lights
To create a LightingBallController or LightingBall, click on the "Create Trigger" button in the CK, and add the respective script to them.  Set name, size, shape, and color to taste.

To rig a controller to their balls: 

a) Use the properties button on controller's Script tabs, then click on ball_1
b) Set the reference to a ball
c) Repeat for ball_2, etc.

The same process is used to rig balls to their lights.

Once you create a set, you can just copy and paste them around.

This example assumes that I've already rigged the balls to their controllers.  As you can see, I've rigged the lights to the balls in such a way that they break line of sight.  Obviously, this is a simplistic example because you have to consider their light radius... but, you get the point!  Assuming everything is properly placed, lights will turn on just in time, and the player will never notice.

I'll run through two scenarios detailing what will happen when:

1) Player is at light #1, and is running towards light #5.  Lights 1 - 4 are already on.  Light 5 is off:

As player exits the top side of Controller A, light 3 turns off and light 5 turns on.
As the player exits the right side of Controller B, light 2 turns off.
As the player exits the right side of Controller C, lights 1 and 4 turn off.

2) Player is at light #5, and is running towards light #1.  Light 5 is on, and 1 - 4 are off.:

As the player exits the left side of Controller C, lights 1 and 4 turn on.
As the player exits the left side of Controller B, light 2 turns on.
As player exits the bottom side of Controller A, light 3 turns on and light 5 turns off.  

Why aren't there any lights rigged to the other ball on both Controllers B & C?  To show that you don't have to.  Or, maybe you're just freeing them up to let the engine handle the rest.  Or, maybe you didn't get to it yet.

Or, maybe I didn't want to clutter up the example with stuff on the other side of the map. ;)

From the CK, showing actual controllers with their balls, along with lights 4 & 5 (pink X's)

Advanced:  If you actually want the CK to show lines connecting your balls to lights, you can.  You just have to set up a linked reference between the balls and lights.  It won't actually do anything besides drawing a line, however.

Here's a video demonstration of my scripts in action for the above example (the one showing 5 lights in close proximity).  The character is shown starting from light 5, and going back around again.

There's actually 7 dynamic lights visible in this video (2 are way down the hall).  I run up to 5 of them (those shown in the above example), so you can see their shadows.

Without my scripts running, that area would look broken, as shown in this video:

My scripts are still running, but I disabled the my balls' ability to disable lights via the specialCaseNoDisables flag.  So, they still enable them... just nothing ever gets disabled.  I did it this way, because all my lights are disabled by default.  But I assure you, this is how the game engine normally handles lighting (as anyone who has tried to do this can attest to).

If you compare it to the example diagram above, you'll see that the engine is "flickering" between lights 3 and 5.  Even though light #5 is obviously not visible through the wall, and there are 4 other lights that are closer, the game engine doesn't seem to care.  According to its own internal alien logic, light #5 is the best choice at that distance and viewing angle.  I didn't show it in the video, but if I had then run up to light #3, it would've also "flickered".

The source code is available below, and on the Nexus.  The newest version is currently v1.12.

Scripts ( v1.12 source and compiled, along with an example .esp):

Scripts (just the source for 1.12):


  1. Excellent will be using this thanks

  2. There was a weird problem on the nexus.

    The 1.1 listing was actually still 1.0. That's resolved now.

  3. Anthony,

    Thanks so much for creating this - I can see this making my mod SO much more engaging and impressive than it was before, and I will have you to thank for that. Unfortunately, I seem to be having some difficulties with getting your mod to work. I've followed all of your tutorials, and ran into a few problems I was able to solve myself, however this latest issue doesn't seem to be an easy hurdle for me to get over.

    Essentially I've created the controllers and balls and rigged them to each other and their lights. However, in-game they seem to have no effect whatsoever. I'm not sure if I'm missing something in the rigging of the lights to the balls, but I have them linked up through the script tab as your tutorial implies with the controller to the balls. Also, interestingly, after reloading my mod after saving, it seems your lighting controllers are all absent from the scene (even though other changes I made are still there). It's as if your script controllers aren't being saved with the mod - which might explain why they don't seem to do anything in-game. Any suggestions or ideas?


  4. Sorry for not replying sooner... I'd lost interest in Skyrim rather suddenly.

    Hmm... well, if objects aren't saving, then that explains why they're not working. ;)

    As to why they're not saving, nothing comes to mind.

  5. Hello i have the same light problem.Can you make a new script for latest version pls?