1
\$\begingroup\$

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?

\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

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

\$\endgroup\$
4
  • \$\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
    Commented Apr 10, 2015 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
    Commented Apr 10, 2015 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
    Commented Apr 10, 2015 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
    Commented Apr 11, 2015 at 2:17

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .