2
\$\begingroup\$

I'm trying to achieve the fog-of-war lighting style that Terraria and Starbound have. Terraria's lighting system seems to be more blocky/tile based, but Starbound's is a lot more smooth.

The Desired Effect:

Here you can see the nice silhouette that the fog-of-war provides.

Starbound is using a shader to render its lighting, but how it's going about that is quite a mystery to me.

The idea I had on how to achieve the desired effect is the following: Create a texture that is black and somehow calculate the area that is white, storing this in a light map render texture, finally doing an Additive Blend of both the main texture and the light map texture to achieve a similar effect to Starbound's. (However this does not take into account lights in the world, which I also have absolutely no clue how to include in my calculation to the light map render texture)

I say somehow in italics because I have no clue as to how I can create this "Mask" effect in the light map render texture. How I can do calculations necessary to create the mask is beyond me; I don't even know how I can begin to translate the game world's data, relative to the what the camera sees, and update the texture accordingly.

TLDR: How can I achieve lighting similar to that of either Terraria or Starbound in Unity 2D?

\$\endgroup\$
  • \$\begingroup\$ Additive blend won't work. You should multiply. \$\endgroup\$ – Ocelot Dec 27 '17 at 3:25
3
\$\begingroup\$

First you draw your color map

color map

Then you draw your light map

light map

And finally you multiply both.

result of multiplication

If you want a some sort of secondary lighting in your game, and if your game world uses grid for terrain and/or object placement, then I have a solution for you. This is something like instant radiosity.

First, you find which cells are lit by the light by tracing them from the light source.

trace

Then you place another light sources on lit cells with attenuation of intensity based on a distance from original light. You may also want to blur them a bit (I did). Here's resulting map.

secondary light

Add original light source there.

full lighting

Then multiply with your color map.

final result

Here's pseudocode for the rendering pipeline (don't mind the syntax highlight)

for each light on scene:
    if light is on screen:
        add light to the drawing queue

draw frame:
    render frame color map:
        draw each visible tile and object

    for each light in queue:
        trace secondary lights on visible cells and add them to the drawing queue                

    render frame light map:
        set blending to additive
        for each light in queue:
            move light object to the light position
            set light object width and height to the light radius
            set light object color to the light color
            draw light object
        //then we render shadows for solid places
        set blending to subtraction
        for each visible cell:
            if cell is surrounded by other cells from every side:
                move light object to the cell
                set light width and height to the radius slightly bigger than cell
                set light color to white//to subtract any kind of light color
                draw light object

    set blending to normal
    draw color map
    set blending to multiplication
    draw light map
\$\endgroup\$
  • \$\begingroup\$ This is exactly what I need and definitely help me move over in the write direction, however I'm still stuck on how to procedurally generate the lightmap with that nice radial gradient. I looked online and found very little on the subject in HLSL, any ideas? \$\endgroup\$ – BlazeXenon Dec 27 '17 at 22:51
  • \$\begingroup\$ @BlazeXenon You can use pregenerated texture for the lights. Simply draw them to the lightmap with additive blending. But however, if you want to generate them procedurally, you should have at least basic understanding of what shader is and how programmable rendering pipeline works. Speaking of HLSL - it is not so different from C language. \$\endgroup\$ – Ocelot Dec 27 '17 at 23:51
  • \$\begingroup\$ Yeah, that seems like a good idea however that would only really work for things like torches. Do you have any idea how I can procedurally generate the nice gradient around the blocks themselves? Currently I only have a it rendering the black directly on the tiles themselves which looks really horrible, however with a nice gradient blur around the edges of the tiles, it would look a lot like the desired effect image above. This is what I current have: puu.sh/yPbi0/4fde0796b2.png; The light map is already multiplied to the main camera's color map. I feel like I'm so close... \$\endgroup\$ – BlazeXenon Dec 28 '17 at 3:05
  • \$\begingroup\$ @BlazeXenon First of all, avoid using completely black color as it will cause the black pixels being unlit completely (AnyLightAmount * 0 = 0). To create a gradient you are talking about, just apply the same light with a range approximately of 1.2 (assuming a cell size is 1) for each cell that is surrounded by blocks from every side, only this time with subtraction blending. I don't think you really need a shader for this. \$\endgroup\$ – Ocelot Dec 28 '17 at 3:35
  • \$\begingroup\$ Wouldn't rendering to a texture from anything else besides the GPU be very bad? The Apply() function is very costly and will generally cause huge lag spikes, from my experience at least. I believe the proper way to do this is in a shader, however I have no clue how in one. The idea you posted is perfect however I have no clue how to render to the texture in the CPU without heavy performance dips. Any ideas? \$\endgroup\$ – BlazeXenon Dec 28 '17 at 8:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.