A resposta simples é que você as altera entre cada chamada de empate. Defina um shader, desenhe um bule, coloque outro shader, desenhe outro bule.
Para coisas mais complexas, nas quais você precisa aplicar vários shaders a apenas um objeto, como desfoque, brilho e assim por diante. Você basicamente tem tudo renderizado para textura (s). Em seguida, você renderiza um quad em toda a tela com a textura aplicada ao usar outro sombreador.
Por exemplo, se você deseja renderizar um efeito de brilho, primeiro precisa renderizar sua cena regular e não brilhante, depois renderize apenas a silhueta colorida do material que deseja brilhar em uma textura, depois mude para um sombreamento de desfoque e renderize seu quad com essa textura anexada à sua cena não brilhante.
Há outra técnica chamada sombreamento adiado onde você renderiza a cena sem iluminação e a aplica posteriormente no espaço da tela. O objetivo principal é reduzir as despesas de iluminação por pixel.
Normalmente você renderiza um buffer de cores que é colocado na tela. Com o sombreamento diferido, você processa um buffer de cores e um buffer normal e de profundidade em uma passagem do shader (você pode armazenar os vetores normais e a profundidade em uma textura como no mapeamento normal e de altura).
Isso significa que, para cada pixel, você sabe a posição da peça mais próxima da geometria não transparente (profundidade ou distância do olho), a cor e o normal. Por esse motivo, você pode aplicar iluminação a cada pixel da tela em vez de a cada pixel visível de cada objeto que renderizar. Lembre-se de que algum objeto será desenhado por cima de outros objetos se a cena não for perfeitamente renderizada na ordem inversa ou inversa.
Para as sombras, você realmente renderiza apenas o buffer de profundidade do ponto de vista da sua luz e, em seguida, usa essas informações de profundidade para descobrir onde a luz atinge. Isso é chamado de mapeamento de sombra (também existe outra abordagem chamada volumes de sombra que elabora uma silhueta da geometria e a expulsa, mas você ainda usará sombreadores).
Com o OpenGL mais moderno (3.0+), você usa um Objeto Framebuffer com Objetos Renderbuffers anexados. Como os renderbuffers podem ser tratados como uma textura. Você pode fazer coisas como renderizar 1 shader para vários buffers de renderização diferentes (para que você não precise renderizar sua textura, suas normais e componentes de brilho), mas a prática subjacente ainda é a mesma.
Também é desejável minimizar o número de comutadores de sombreador, tanto quanto possível, para economizar em sobrecarga. Assim, alguns motores agrupam tudo com o mesmo material para que tudo possa ser desenhado de uma só vez.