Sign in to follow this  
cakefrost

Simple 2D lighting effects

Recommended Posts

Hi, I am trying to do simple lighting effects (no dynamic shadows, almost like a fog of war). Below is a screenshot of something that looks similar to what I am going for (this is not my game, just something I found from google)

 

4.png

 

 

I am using LPD3DXSPRITE to render things, and am currently running a single pixel shader that isn't doing anything right now. I have found a variety of strategies, from rendering a light map to a different surface (using SetRenderTarget), then converting that to a texture, and then passing that to the pixel shader, and then using that to determine what should be darkened (and potentially by how much).

 

This sounds pretty straightforward, but I need to learn how to do each of those steps.  The problem is, I am having difficulty using the right terms to search. So my questions are: 

 

1. Is this the right approach for something like the above screenshot?

2. If this isn't the right approach, can you please point me in the right direction?

3. If this is the right approach, what things should I be looking up to better understand how to do this?

Thanks in advanced!

Share this post


Link to post
Share on other sites

I don't know about DirectX, but I know one method I see recommended a lot is to make a screen sized bitmap that has alpha transparency with the circle in the middle and a custom made gradient filling from the edge of the circle to the edge of the bitmap. Then it is a simple matter of drawing it over the top of the sprites being drawn. That is if I'm understanding what you are wanting. There are probably better ways to go about it, but like I said, that is the normal method I see recommended, but I've never done this for a game myself so I can't say from experience.

 

I should point out this method also assumes you have the camera locked so that the character is always dead center of the screen.

Edited by BHXSpecter

Share this post


Link to post
Share on other sites

You could draw all your sprites with a non-white color to ID3DXSprite::Draw() which will darken them, then draw the lightmap as another sprite over top of the player sprite and blended with the background.  The lightmap doesn't need to be generated with render targets, it could just be a texture you have loaded from a file.

Share this post


Link to post
Share on other sites

Thank you for the reply, I wasnt clear, but I also meant that these light sources would be in the environment - think a light post or something.  I was thinking about doing it the way you described, and determine where in the screen each light is, render the mask as you described, then figure out which areas are not touched by the light, and render a simple mask over it. I suppose that idea doesnt actually sound so bad.

 

edit: Ah, I know why it would be tough - when multiple lights are on the screen at once, if they overlap, it will be rendered weirdly.

Edited by jarrett.baugh

Share this post


Link to post
Share on other sites

You could draw all your sprites with a non-white color to ID3DXSprite::Draw() which will darken them, then draw the lightmap as another sprite over top of the player sprite and blended with the background.  The lightmap doesn't need to be generated with render targets, it could just be a texture you have loaded from a file.

 

The lights are not constant relative to the player/camera, so I am not sure that would work.

 

I do exactly that currently, but I if I render something on top of it, the colors look dull/muffled, because I am adding something on top of it.

Share this post


Link to post
Share on other sites

Thank you for the reply, I wasnt clear, but I also meant that these light sources would be in the environment - think a light post or something.  I was thinking about doing it the way you described, and determine where in the screen each light is, render the mask as you described, then figure out which areas are not touched by the light, and render a simple mask over it. I suppose that idea doesnt actually sound so bad.

 

edit: Ah, I know why it would be tough - when multiple lights are on the screen at once, if they overlap, it will be rendered weirdly.

I have never done lighting based on sprites, but I suspect the correct approach is

  1. Render your scene/screen as if you are not doing lighting
  2. Set an RGB texture the same size as your screen as the render target
  3. Clear the texture/render target to 0/black
  4. Set the blending mode to additive (dest = dest + source, rather than say your "dest = dest * (1-alpha) + source* alpha" for alpha blending)
  5. Render your light gradients (they can be coloured, because "a + b == b + a" order does not matter, overlapping areas just get brighter till you saturate the channel at full brightness)
  6. Put your backbuffer back as the render target
  7. Multiply your backbuffer/scene with the lighting texture (dest = dest * source) which makes unlit areas black (dest = dest * 0) and leaves fully lit areas alone (dest = dest * 1) and everything inbetween, for red, green and blue independently.
Edited by SyncViews

Share this post


Link to post
Share on other sites

Glass_Knife: thank you for the link, I will check it out. The lights will not necessarily stay in the same spot (the player might be able to place torches on the ground, or start a fire, I am not entirely sure but I dont want to limit myself). I also am looking to do much simpler lighting, mostly just rendering certain pixels with less color if it is supposed to be darker. 

 

SyncViews: Awesome, this is something I can look into, thanks. From my original research, I remember reading that there is no multiplication blend (step 7), so this sounds like something I'll use the shader for. However, this is basically back to my original problem of not knowing what I need to search. I tried searching for passing textures/buffers to pixel shaders but I am getting a variety of responses, none of which have proven helpful to me. Is there a particular term that this process is called that I can look into?

Share this post


Link to post
Share on other sites

I've been working on a method for real time lighting on pixel art. I've put some videos up on YouTube. Latest one here

 

https://www.youtube.com/watch?v=Amv1Akm-3io

 

I haven't written up my method yet as I'm still finishing up some details, but you can see the idea. I do it by offline rendering various normal, material and occlusion maps into my sprite sheet alongside the diffuse colour, then doing similar to a 3D deferred renderer but using the 2D sprites to populate the geometry buffer. It supports dynamic point lights and directional lights so far.

 

It's a bit similar to the Gamasutra article I guess (though that article hadn't come out when I started working on it.)

Share this post


Link to post
Share on other sites

Glass_Knife: thank you for the link, I will check it out. The lights will not necessarily stay in the same spot (the player might be able to place torches on the ground, or start a fire, I am not entirely sure but I dont want to limit myself). I also am looking to do much simpler lighting, mostly just rendering certain pixels with less color if it is supposed to be darker. 

 

SyncViews: Awesome, this is something I can look into, thanks. From my original research, I remember reading that there is no multiplication blend (step 7), so this sounds like something I'll use the shader for. However, this is basically back to my original problem of not knowing what I need to search. I tried searching for passing textures/buffers to pixel shaders but I am getting a variety of responses, none of which have proven helpful to me. Is there a particular term that this process is called that I can look into?

What do you mean by passing textures/buffers to the pixel shader? I'm sure your already doing that with your normal rendering, and if I recall correctly even pretty old hardware can support somthing like 8 input textures. For D3D9 I believe you can just declare 2 (or more) samplers in your HLSL pixels hader file, and all the relevant functions take the sampler index like IDirect3DDevice9::SetTexture(DWORD sampler, IDirect3DBaseTexture9*).

 

Then working on my previous suggestion, I think you can do it pretty much like a simple non-cached lightmap:

  1. Set an RGB texture the same size as your screen as the render target
  2. Clear the texture/render target to 0/black
  3. Set the blending mode to additive (dest = dest + source, rather than say your "dest = dest * (1-alpha) + source* alpha" for alpha blending)
  4. Render your light gradients (they can be coloured, because "a + b == b + a" order does not matter, overlapping areas just get brighter till you saturate the channel at full brightness)
  5. Put your backbuffer back as the render target
  6. Set that RGB lighting texture as the second texture
  7. Render your scene as without lighting, but in the pixel shader, sample that second texture using the screen space coordinate, then multiply it by your unlit colour to get the lit colour
    //HLSL pixel shader like pseudo code as not on development system
    sampler texture;//The texture for the sprite your rendering
    sampler lighting;//The lighting texture from 2-4
    
    struct Input
    {
        float2 texcoord : TEXCOORD;
        //anything else you have
        float2 screenPos : VPOS;//provided by D3D9, is the location on the screen/render target. I am assuming its in 0-1 space, correctly orientated etc. You will need to check this.
    };
    
    float4 main(Input input) : COLOR
    {
        //do what you normally would
        float4 col = texture.sample(input.texcoord);
    
        //lighting
        float4 light = texture.sample(screenPos);
        return col * light;
    }
    
    

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this