I have a glassy object and when light passes through it I want it to cast colored light behind it, instead of the shadow.
I could just use another light object to cast that colored light, but is it possible to do this using shaders?
Treating them like shadows should work fine.
-Render the world from the light(s) perspective(s) and record the distance from the light.
-Render the world from the camera's point of view, then sample and compare the new distance.
-For each pixel, if the world-space pixel-to-light distance is greater than the light-space pixel-to-light distance, the pixel is in "shadow".
-You can mix the glass color in, any way you'd like. Glass usually perturbs light that passes through it.
A perturbation texture, color texture, and/or stencil can also be used to enhance the effect. For example, sampling a "stained glass" texture when coloring the final pixel, will project the stained glass effect onto anything it hits. "Frosted" glass, "privacy glass", glass-block walls, panes with beveled edges, etc., etc.; all from textures.
For the lightmap render, the length is just:
length(lightPos - worldPos)
Write the value to the lightmap. For the camera render, you'll need to calculate the camera-space length using length(), sample the light-space length out of the lightmap, and compare.
To retrieve the light-space length during the camera render, project worldPos using the light's (View * Projection) matrix. The resulting coordinates range from -1 to +1 and need to be scaled into the 0 to 1 (UV) range. UV's place (0,0) at the top left which corresponds to screen-space (-1,+1) so you'll need to invert the Y. With the UV coordinate, sample the lightmap for the length, then subtract the two lengths.
lightUV = mul(float4(worldPos, 1), lightVP);
lightUV += 1;
lightUV /= 2;
lightUV.y = 1 - UV.y;
For simple colored glass, sample the object textures as usual. If the pixel is in shadow, multiply the sampled color by the light's color.
lightVP, lightColor, lightPos will probably all be in a constant buffer
worldPos will need to be saved by the vertex shader and passed to the pixel shader