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.

enter image description here

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

| improve this answer | |
  • \$\begingroup\$ I get the logic, but I'm not really sure how to implement it. How would I get those distances and how would I know what color is the glass? \$\endgroup\$ – zoran404 Apr 10 '15 at 14:29
  • \$\begingroup\$ I filled out the rest of my method, but realized I didn't pay attention to the question's tags, yet again. I am unfamiliar with Unity and I halfway suspect that it already does this "natively". \$\endgroup\$ – Jon Apr 10 '15 at 21:19
  • \$\begingroup\$ If this WAS actually on the way to helpful, I will revise it again, to add support for textured glass. \$\endgroup\$ – Jon Apr 10 '15 at 21:21
  • \$\begingroup\$ I tried to implement this, but since I never worked with shadows I couldn't do it. I asked on unity forum for help with implementing. Thanks. forum.unity3d.com/threads/how-to-cast-colored-shadows.317987 \$\endgroup\$ – zoran404 Apr 11 '15 at 2:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.