The shift registers will allow all the leds ON at the same instant instead of multiplex flickering which is okay up to perhaps 5 at once. You will still need to connect transistors if you want all lights full bright but for demo that might not matter.
They also simplify making light patterns to bytes you send them, 22 lights needs 3 bytes, 3 8-bit registers, only when a change is needed.
With the intersection you have different car and people traffic patterns. Determine those, all of the ones you want to allow. You have cars going north and south and able to turn while cars east and west are stopped and then the switch to stop north and south and allow east and west but you also have pedestrians.. when they cross it is a pattern or part of one.
Make some drawings with arrows on each showing who can move where for each desired traffic condition. From those, which lights should be ON can be figured out and matched to each condition and time for that also noted. Make sure that yellow (caution) light conditions are separate.
Figure out the flow going from one condition to the next, here is simplified no pedestrians;
N/S cars open, E/W cars blocked, 30s ----> N/S cars caution, E/W cars blocked, 10s ----> N/S cars blocked, E/W cars open, 30s ----> N/S cars blocked, E/W cars caution, 10s ----> back to start.
When you add pedestrians, it gets more. If the sequence is interrupted, always go to a condition desired and continue as usual from there.
Be glad you don't have turn arrows too.
You do this and your logic only has to choose a condition. The lights will be set by what condition, each has 3 bytes to send through SPI always the same per condition. The lights figured out ahead of time, stored as bytes, no per-led code except sending the bytes is needed. ---- most of the work is done ahead and saved as data, the sketch doesn't have to at run time.
These are very old techniques, by the way.