Mapping/Multiple skies with point light support

From Sven Co-op
Jump to navigation Jump to search

SC 5.21 added a new entity called trigger_changesky, which allows you to change the skybox texture on the fly. Changing the light of the sky is possible but you'll run into a few limitations. This tutorial will show you how to work around these problems with a nifty trick. It'll also go into detail about the nature of environment lights.

1 Environment light

A light_environment entity will cast light from the SKY brush to illuminate brushes, just like any other light entity does. The light information on a brush will be stored in the lightmap. Nearly all models in the game will look below their origin for this light information and take on the colour and intensity of that light. In the screenshot below the player is standing on a red light spot and thus becomes the same shade of red.

ZzD7tM4.jpg

A light_environment does something extra: it creates a global light and a vector point. The sky vector point is a point in 3D space where the sky light is coming from. As soon as a model can trace a line to this point, it'll take on the colour and intensity of the global light. This global light will always override the light info in the lightmap below the model. See the illustration below:

You can experiment with the sky vector and colour by using the sv_skycolor and sv_skyvector commands in your server. However, these cannot be dynamicly changed by map entities.

2 Light_spot and -noskyfix

Having a global light override all your lightmap info can be quite annoying. Imagine a dark map where you're model is always a dark shade of blue even when you are walking under a spot light. Luckely, there is a way to get rid of it. You can either use the -noskyfix parameter for RAD or use a light_spot instead of a light_environment. Both methods have the same result: they nullify the global light. For this tutorial I'm using the light_spot route, since it's easier to work with.

Remove the light_enviroment from your map and put in a light_spot. Then set the keyvalue Is Sky? to Yes. (_sky 1). You can give this light the desired colour and intensity and you can also add Ambient light by click on SmartEdit and add the '_diffuse_light' keyvalue with RGB values. It only needs a targetname. I'm calling mine 'light1'. You can add a button to the map to target our light and turn it on and off.

3 Lighting problems

There are some issues with this setup, though. For starters, the SKY brush doesn't hold any lighting information. So if your map has an Osprey flying above a SKY brush, it will be rendered completely black. Or if you have a Xen map, where players jump from island to island: in between the islands their models will become black. Note that models only take lighting info from world geometry. Even though brush entities such as func_walls have lightmaps, the engine will ignore them and look further down below until it hits a world brush and take the light info from that face. If that face happens to be a SKY brush, your model will be black again.

The second problem is that the light_spot is a point light entity and the engine limits the casting range of those to 2048 units. If your model is flying above a world brush higher than 2048 units it will not recieve any more lightmap info.

4 The work-around

To make sure our models are lit correctly in the skybox, we'll have to find an invisible brush that can hold the lightmap data. The ZHLT tools provide us with just such a thing: BLACK_HIDDEN. Make sure you have zhlt.wad loaded.

Create a brush over the area of the SKY brush and put the SKIP texture on all sides. Then put the BLACK_HIDDEN on top of this brush. You can cover the entire bottom of the SKY but I'll advise you to only use it where it's necessary. These brushes can be very large and it might take a while to calculate lighting on during compilation. Therefore, also scale the texture to 4.00 or 8.00, so the lightmap becomes larger. This will improve compile times a lot and you will not be able to notice the difference, since there is only one gradient of light cast on them anyhow.


Now compile it and our Apache will have correct lighting above the skybox!


You might notice that if your Apache flies over areas with other lightmap info, it'll start shifting colour and intensity because it takes on different lightmap info. This can be very undisirable, but there is a fix for it. Create another brush at the top of the skybox and this time put the BLACK_HIDDEN texture on the bottom.

Now go into the properties of the Apache, click SmartEdit and add the keyvalue 'effects' with a value of 16. This invokes EF_INVLIGHT, which will cause this entity to search for lightmap info ABOVE the origin (in this case: our new brush). Now our Apache will always use this sky light for its light info.

5 Setting up multiple togglable skies

Now that we've found a solution to the lighting issues, we can begin to set up our multiple sky system. NOTE: There is a hard limit of three sky lights. This is because the engine can handle one static light (unnamed light entities) and three dynamic lights (named lights or light with appearance settings). If you add a fourth dynamic light, you'll get the "too many lightstyles on a face" error. Keep this in mind if you plan to use other dynamic lights in your outside areas. In this case you are better off with just two different skies, so you have one free channel for your other dynamic lights.

-Create three light_spot entities and call them "light1", "light2" and "light3". Give each of them a unique colour. Flag "light2" and "light3" to Initially Dark. -Create three trigger_changesky entities and call them "light1_sky", "light2_sky" and "light3_sky". Give each of them a unique sky name. You can find these in the ../gfx/env folder. Flag "All Players" and "Update server" on all three. -Create a multimanager and name it "set_light1". -Click on SmartEdit and add "light1_sky" with a value of "0". This will set the sky for light system 1. -Add "light1" with a value of "0#1". In this case "0" means the delay and "#1" will force it to go ON. -Add "light2" with a value of "0#0". "#0" will force it to go OFF. -Add "light3" with a value of "0#0". -Duplicate the multimanger and call it "set_light2". -Change "light1_sky" to "light2_sky". -Change "light1" value to "0#0" and "light2" to 0#1". Now this will force light2 to be ON. -Duplicate the multimanager again and make similar changes for "light3". -Create a trigger (or button) to target "set_light1", "set_light2" and "set_light3".

Now compile and watch your lights change!

6 Setting up the multiple simultaneous skies

It's also possible to set up a map where you have two seperate skyboxes at the same time. Imagine a scenario where you travel forward or back in time through a teleporter.

We'll start by making two rooms with a SKY brush. You can shape them however you like, as long as they are seperate areas that do not connect to one another. Place a light_environment in each of them and create a trigger_teleporter and info_teleport_destination, so you travel from one to the other.

Add two trigger_changesky's and add the skies of your choice. I'm going with 'morning' for one and 'night' for the other. I'm giving them the targetnames 'morning_sky' and 'night_sky'. Now I'm going to adjust the light properties of each light_enviroment to match a morning and a night light. Do not tag any flags. By default the sky will only change for the player who activates it. Finally, go into your Map Properties and set the sky you want to player to begin with.

Go into the info_teleport_destination and in FLAGS, tag 'trigger on arrival'. Then in the target field add the sky that should be enabled once you arrive here. The teleport_destination in my night area will target 'night_sky' and the teleport_destination in my morning area will target 'morning_sky'. You might now have something that resembles this:


Now here comes trouble: as established earlier in this tutorial, using a light_environment will cause the global light to enable. The engine will take the light information from the light_environment which was placed LAST to use for the global light. In my case that would be night, so even in the morning area, all models will have night lighting. Luckily, there is a work-around: Create a small room with SKY textures and place a light_enviroment in there. Now change the 'brightness' to 0 0 0 0. This will set the global light to nothing and will fix our lighting problems.

To enable the simultaneous skies, you must add the -noskyfix parameter to your RAD compiler. Now you can hop from one time zone into another!

7 global_light_control

There is a special entity you might be able to use in specific cases when it comes to controling your lights: global_light_control. This entity can change the appearance of all unnamed lights in the entire map. With appearance I mean the custom appearance field (pattern), which can give light an effect like fluorescent flicker, gentle pulse, etc. With custom appearance you can also control the intensity of the lights: 'a' is completely dark and 'z' is full bright. The default value is 'm'.

So imagine your map is mostly set in an outdoor environment and you use lights (like street lamps) to light your night environment. Then if you want to use a day environment, you can trigger the global_light_control entity with the appearance "a" to toggle all lights off. Note that this will toggle ALL unnamed lights, so if you have any indoor lights you wish to remain lit, make sure they have a targetname.

Turning lights on and off can of course also be done simply by giving the outside lights a targetname. However, by giving them a name, they become part of an additional lightstyle. As determined in this tutorial, there is a limit to the amount of lightstyles you can have per face. So if you happen to run into this problem, you can instead use global_light_control to toggle them.