ThreeJS Light and shadow

Exploring the best ways to create light and shadows in ThreeJS

We often take lights for granted. It's extremely easy to add and remove lights or shadows to our scene, but they are pretty expensive. The more you add the worse it gets.

Try your best to use real-time lights when you are doing real-time things with them. When they are moving around, or being updated while rendering. When you are not, bake them or use static HDRis.

In Unity or Unreal the experience is smoother because they are editors. With the click of a button, you can choose to bake your light. On the web, we often rely on Blender for that.

No one reading (or writing) this newsletter wants to open Blender. So here are my go-to rules when working with real-time lights and go-to tutorials when I do have to do baking.

Let me know your thoughts by responding to this email!

In next week's issue, we'll learn how I used a low-resolution render to get the intersection of the hand model into a texture. See you then!

Getting started


Dont dispose of Lights

Don't dispose (or add new ones) of them unless absolutely needed.

in ThreeJS, all materials depend on the lights, if they are disposed/removed/added they all the materials have to be recompiled and updated. When a light is not needed, set its intensity to 0.

This tiny mouse interaction by ToyFight is a neat example of what you can do with very little light. It's just two models with a light acting as a rim light that moves with your cursor.


Try to not use point lights for shadows

Point lights are often my go-to when I add a new light. However, if you turn on shadows, it has to render shadows for every single direction. This means 6 shadow renders. So, you can use point lights for lighting, but it you want shadows, try your best to use directional-type lights when possible.

In this demo by Kevin Levron, he uses point lights which create this beautiful effect when you move the mouse around and the shapes are slowly moving towards the light.


Shadows are expensive. Limit your shadows.

Each shadow source is one more render of your scene, this means rendering all the materials that have "material.castShadow= true". The quality of this shadow image depends on its resolution. However, a higher resolution also means more expensive to render.

This project by MerciMichele is an amazing example because the only real-time shadow is the character's shadow. It probably has the shadow camera always following the player very closely. All other shadows are baked/static.

How do you know this is the case? First, you can notice this because the trees' leaves have slight movements to them, however, their shadow is static. Second, the shadow of other characters disappears once you are far from them


Baking Lightmaps. Avoid real-time shadows and lights.

Often we stay with real-time lights and materials because of the convenience. But baking is the number one thing you can do to help the look/performance of your project like in this demo by @arturitu. You completely avoid all lights by pre-rendering them to a light map.

This demo also takes advantage of two sets of UVs. One UV for the light map, and the other for a tiled texture with lazy unwrapping. This allows the main color map to be very small while keeping the light map very high quality.


Further reading / Inspiration