Isso pode ser feito com mascaramento. Existem várias maneiras de fazer isso.
Uma maneira seria ter uma maneira de renderizar uma versão sombria dos elementos de primeiro plano. Desenhe o plano de fundo. Em seguida, desenhe os elementos do primeiro plano, desloque um pouco, dependendo de como você deseja que a iluminação se mova, de forma que você produz apenas cores pretas. Em seguida, desenhe o primeiro plano normalmente.
Outra maneira seria renderizar o primeiro plano em um buffer, um pouco mais do que você realmente veria. Em seguida, faça um passe "preto" e talvez um desfoque. Agora renderize a saída desse conjunto de passes e a seção visível do buffer em primeiro plano.
Para suportar várias luzes em diferentes ângulos, você pode executar a etapa anterior várias vezes ou acumular todas elas em um único buffer. A matemática varia de acordo com o que você está tentando alcançar, mas um primeiro palpite sobre o que está acontecendo naquele primeiro vídeo é que eles apenas posicionam a luz contra a posição da câmera (centro da área visível) e em seguida, use esse vetor (em escala) para determinar como compensar as sombras. Algo como:
draw background
for each light intersecting viewing bounds:
offset = light.position - camera.position
offset *= SCALE FACTOR (0.25 maybe)
draw shadow foreground at offset
draw foreground
As luzes que estão "mais próximas" da cena terão um fator de escala menor. Se você deseja várias profundidades, há algumas contas a serem trabalhadas por aí, coisas geométricas simples.