The Problem:
Unfortunately blender doesn’t have integrated support for point light shadows. Sometimes, it would be nice to have them, and so we look for ways to fake them.
Previous Solutions:
- The most obvious and most used way is to have a very wide angle spotlight in the roof of the room that should have the point light.
- A slight improvement on this is to use the spotlight as ‘shadows only’ and have a point light up there to do the actual lighting.
Both of these methods fall flat on their faces when you need to move around the point light in all three dimensions.
- A couple of weeks ago, @Viper-MIJP thread, which faked point-light shadows by having a wide angle spotlight always pointing at the camera.
This works pretty well, except that when you’re facing across the direction of the light, there aren’t any shadows. Also, wide angle spotlights sometimes have issues with shadows at the extremes of their angles.
All of these methods also fail at large distances, where the pixels of the shadow-map become large on-screen.
So I thought about this, got out a pen and paper, and came up with a better way.
How it works:
- When you’re facing away from a light, the shadows you see are your shadows and anything between you and the light.
- When you’re across a light (ie the light is perpendicular to you), you only see shadows being cast in that direction, or objects between you and the light.
- When you face towards a light, you can see shadows in all directions from the light.
The method by Viper-MIJP solves the first of these cases, by having the light pointing at you.
To solve the second case, we can point the light in the direction you’re facing (incidentally, this also solves the first case)
To sold the third case, well, you need an actual point light, but the shadows you’re most likely to notice are those facing you. (ie objects between you and the light)
So we want the light to:
Face the direction you’re looking when you’re not facing it
Face towards you when you are facing it.
And of course, sudden jumps are not desirable as they are noticeable.
And of course, the view angle of the camera affects how much of the scene needs to be shadowed.
So we can end up with the code:
import bgeimport math
def face_the_right_way(cont):
l = cont.owner
c = bge.logic.getCurrentScene().active_camera
dist, vect_to_cam, _ = l.getVectTo(c)
vect_of_cam = c.getAxisVect([0,0,-1])
view_angle = c.fov
cur_angle = vect_to_cam.angle(vect_of_cam) * 180 / math.pi
l.spotsize = view_angle * (1.1+l.spotblend)
if cur_angle < view_angle/2:
l.alignAxisToVect(-vect_of_cam)
else:
ratio = (cur_angle-view_angle/2) / (180 - view_angle/2)
final_vec = - vect_to_cam.lerp(vect_of_cam, 1 - ratio)
l.alignAxisToVect(final_vec, 2)
Attach this to a spot-light light running every frame, set it to ‘shadows only,’ put it in the same location as a point light, and you have a point light that will cast shadows
Difference between code here and in the blend
The code here uses the active camera.
The code in the blend uses the first camera, to allow you view it from top-view.
I forgot to remove a print statement from the code in the blend!
Attached is a sample blend, and here are some shots of the effect from overhead:
Summary:
Pros:
- Theoretically indistinguishable from a point light for 180 degrees of camera rotation.
- Works in 3D situations, you can move above and below the light, and it looks just as good
- Shadows never ‘pop’ in. They always transition in smoothly.
Cons:
- Shadow map flickers as the light rotates. Probably would work better with variance shadowtype, but it doesn’t work on my graphics card.
- another 180 degrees camera rotation where it doesn’t look like a point light
- method for deciding spot-size based on camera view-angle works when facing away and across, but it should scale up to ~160 when facing the camera.
More Things To Do:
If I get around to it, here are a few things I’d like to try implementing:
- As the player gets further away, scale the cone of the spot-lamp so the shadow has more pixels where the player is. Adapt angle based on direction facing.
- Write a system like Viper’s where any point lights in the scene are auto-shadowed like this one, if they are close to the player.
Attachments
Light Test.blend (612 KB)