9

I just implemented a light system in my engine. In the following screenshot you can see a light (the yellow square) in action:

1 Take into account that on top of the light illuminating the scenario, its also implemented a FOV which will occlude anything outside your field of view. Thats why the left part of the shadow seems so off.

As you can see the light's shadows are pretty "hard", as they won't even illuminate one bit of the area outside its direct reach. In order to make the lights look better, I applied a filter to them, which pretty much limits the range to be illuminated, and also iluminate the area slightly within this limit:

2

In the big yellow circle you can see how the area is illuminated even if no direct light reaches it.

This solution however comes with some undesirable side effects. As you can see in the following screenshot, even if no light at all reaches an area, it will be illuminated if its too close to the light source:

10

I was wondering if there is any way to achieve what im trying to do by using shaders properly. The main problem that I encounter comes from how I draw these shadows.

1) First I take the structures within the light's range.

At this point, I'm working with vertex, as they define the area of the shadow casting items: 3

2) Then, for each of these objects, I calculate the shadow they cast individually: 4

5

6 The shadow they cast is done by the CPU, by calpulating projections for each vertex of the body.

3) Then the GPU draws these shapes into a texture to compose the final shadow:

7

The problem I find is that making this difuse shadow effect, I need the final shadow. If I were to calculate the diffused shadows in step 2), a gap of light would appear between solids B and C.

But if I difuse the shadows in step 3, I no longer have the vertex information, as all the info I have are the 3 local textures added up together in one final texture.

So, is there anyway to achieve this? My first idea would be to pass a varying to the fragmentshader to calculate how much light comes into the dark area, but since I'll be processing this info on the final shadow, which has no vertex information, I'm completely lost about what approach I should use to make this.

I might be completely wrong on this approach, since I have very very limited experience with shaders.

Here is an example of what I have right now, and what I desire: What I have: Plain illumination withing the light radius (which causes the light to clip through walls. 7

What I want: Shadow is more intense the farther away it is from where the light ends. 7

logain
  • 1,437
  • 1
  • 12
  • 18
Leo
  • 1,034
  • 9
  • 23
  • Thanks for pointing out the typo. Fix'd. Edit: I can't type! :( – Leo Mar 19 '14 at 15:38
  • I think we need a little bit more information about what parts of the algorithm you're doing where. Are you computing the shadow volumes on the CPU? – Nathan Monteleone Mar 19 '14 at 16:03
  • Yes, the shadow volumes are computed on the CPU. – Leo Mar 19 '14 at 16:06
  • is performance an issue? At the cost of an extra pass, you could draw the walled off objects on top in a different color, and then have your final not add any color to the shadows on that part. – user26347 Mar 19 '14 at 16:47
  • 4
    +1 nice use of illustrations! – japreiss Mar 19 '14 at 16:53
  • Added a couple of screenshots to be more precise. – Leo Mar 19 '14 at 17:32
  • Sorry to keep asking a bunch of questions, but how are you actually applying the shadow volume in the shader? There are so many ways to do it I find myself having to think of a million caveats in order to answer.... – Nathan Monteleone Mar 19 '14 at 21:17
  • Do you refer to the step where the individual shadows of each body are drawn, or the part where the resulting big shadow (and the one I want to apply the diffuse effect on) is displayed on screen? Also, I am pleased to answer as may questions as you may have :) – Leo Mar 19 '14 at 21:21
  • @user2215331 Yeah I meant the part where the resulting big shadow is displayed on the screen. – Nathan Monteleone Mar 19 '14 at 21:22
  • I'm just using a fragment shader and pass it a texture that hold the filter to be applied to the shadow (a simple circular gradient). For rach fragment to be draw, it checks the following: -Is this fragment outside the casted shadow? If it is, apply the transparency of the gradient -If the fragment is a piece of the shadow, then check if it is whitin the visible range of the gradient: If it is, apply a fixed value for its trasnparency (currently 0.5). If its outside the range, keep it dark. This might sound pretty confusing, but once I'm home i'll make a image which will clarify the process! – Leo Mar 19 '14 at 21:47

1 Answers1

1

I think that no matter what you do, you're going to have to calculate the light falloff differently for the areas of the scene that don't have direct visibility to the original light source. I'm not sure how you're actually applying the shadow volume to the scene, but you might be able to do something like classify the edges as you're generating the shadow volume (i.e. did they come from a wall or from the line from the light to a corner?), and treat them accordingly.

In short I don't think there's any clever shader-specific trick you can pull off to fix this problem. It's a limitation of the algorithm you're using, so you need to improve the algorithm to take into account the different nature of the edges in your shadow volume.

--- Edit ---

Ok I think your best bet is going to be to create two shadow volumes (or rather shadow areas since we're working in 2D). One will be exactly as you have now, the other will be smaller -- you'll want to exclude the areas that are in "soft" shadow. Then you'll have three categories in your fragment shader: total shadow, soft shadow, and unshadowed.

To create the second shadow map, I think you'll want to do something like add a fixed angle to the edges that are created by the light shining around a corner.

--- Edit #2 ---

I think you can solve the problem of the gap between objects B and C by taking the silhouette of the shadow areas and the outer box of the scene. So for each of your shadow areas, you'd find the two outermost points that intersect the outer box, then throw out all the line segments in between and replace them with that portion of the box. I feel like I should be able to name that algorithm but it escapes me at the moment...

Original Scene: Original scene

Individual "hard" shadows: Individual "hard" shadows

Now union the shadows together: Union

Finally, trace around the shadows, keeping to the edges of the box. The corners you want to identify are the ones in yellow. As you are tracing around the perimeter of the shadows, you want to cut across the edge of the box until you reach the opposite corner. Not the easiest thing to code but if you've gotten this far I think you can figure it out :)

Silhouette

Alternatively, it might be easier to simply consider the lit areas. For example, you could do something like take the difference of the scene box and the unioned shadowed area This will usually give you multiple polygons; discard everything except the one that contains the light because the rest are the false gaps.

Nathan Monteleone
  • 5,110
  • 26
  • 42
  • Yes, I think I'll need to improve the algorithm, but that's exactly what I'm asking for. My question regarding shaders is just a double check for some missing concept or principle from shaders that I might be overlooking or just ignoring, since, as I said, my experience with them is very limited. – Leo Mar 19 '14 at 21:53
  • I have implemented something similar to this. If you look at the first screenshot, the edge of a shadow in the right diffuses in an angle, and the diffused area grows bigger as it gets away from the corner. I tried to use this approach, but the problem remains the same as stated in the question: If I contruct the soft shadow while processing the small shadows (last step of the process where im still working with vertexes), the addition of soft shadows won't be equal the big soft shadow I'm looking for. The real question is how to construct this soft shadow from the resulting total shadow. – Leo Mar 19 '14 at 23:21
  • 1
    @user2215331 Ok now I think I'm starting to get the message. Does that last edit clear things up? – Nathan Monteleone Mar 20 '14 at 01:05
  • I think I'm following you: http://i.imgur.com/Fh2kY9E.png The image shows what I understood from your explanation. The black marks at the edge of the image is where the shadow projection cuts the outerbox. If I understand correctly, only edges that are not between 2 of this projections should be diffused, to avoid the problem on my first example. But wouldn't this generate a new problem? In this image I circled 2 areas, where there would no soft shadow generated because it falls in said criteria... but there SHOULD be soft shadows. This is becoming a really tricky question! – Leo Mar 20 '14 at 09:58
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/50141/discussion-between-user2215331-and-nathan-monteleone) – Leo Mar 20 '14 at 14:37
  • Ok, I might be being obtuse here but... how does tracing the siluette of the final shadow help me in anyway, to achieve something like the last image I posted in my question? – Leo Mar 20 '14 at 17:51
  • It's telling you which areas of the scene are TOTALLY dark and shouldn't even have filtered light. Pass that final silhouette into your shader. If the fragment is inside it, it's completely black. Otherwise test against your original shadow area and use the filter. – Nathan Monteleone Mar 20 '14 at 18:36
  • I see how this will solve the error displayed in the third screenshot of my original post, but it doesn't really address the effect that im looking for which can be seen in the last screenshot, since what im looking for is making part of the area you just described partially visible. – Leo Mar 20 '14 at 22:52