1
\$\begingroup\$

A central mechanic in my game involves shining a flash light on a glass sphere, which then focuses the light like a magnifying glass in order to burn enemies. The flash light was easy to implement - it's just a spot light - but the focused beam is turning out to be a little harder, since Unity doesn't seem to have any built-in light type that converges to a single point.

Currently, I'm using a flipped spot light. With that the illusion falls apart pretty quickly, since it casts shadows in the wrong direction and doesn't illuminate things the way you would expect it to.

Am I missing a light type that does what I need, or is there a trick to achieve such an effect?

\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

enter image description here

Here's a simple fix: multiply the material's normal by -1 and light it with a spot light in the opposite direction. Let's start with a Lambert surface shader with a main texture and a normal texture.

Shader "Example/Diffuse Bump" {
    Properties {
        _MainTex ("Texture", 2D) = "white" {}
        _BumpMap ("Bumpmap", 2D) = "bump" {}
    }
    SubShader {
        Tags { "RenderType" = "Opaque" }
        CGPROGRAM
        #pragma surface surf Lambert
        struct Input {
            float2 uv_MainTex;
            float2 uv_BumpMap;
        };
        sampler2D _MainTex;
        sampler2D _BumpMap;
        void surf (Input IN, inout SurfaceOutput o) {
            o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
            o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap))*-1;//<- multiply by -1
        }
        ENDCG
    } 
    Fallback "Diffuse"
}

But this affects all types of lighting, including directional lights. So if you only need to deal with spot light, you need to implement a multi-light lighting model yourself, like this and this.

In the lighting model, it will be judged whether the angle between the reflected light direction and the observe direction is > 90°(dot < 0), like:

max(0.0, dot(reflect(-lightDirection, normalDirection),viewDirection))

If the light is a point light or a spot light, change its normal direction to:

max(0.0, dot(reflect(-lightDirection, -normalDirection),viewDirection))
\$\endgroup\$
2
  • 2
    \$\begingroup\$ A limitation with this is that you can have only converging spotlights, no mix of diverging and converging, and you need to modify every material shader. A possible alternative I don't have time to test, but you'd be welcome to run with: set up a camera with the same FoV as the spotlight, and render the scene to a render texture with shader replacement. In that shader, use the view space position of the shaded point to get its position in the converging cone shape, and shade it white if inside/black outside. Now use that render texture as the cookie for the spotlight. \$\endgroup\$
    – DMGregory
    May 31, 2022 at 11:36
  • \$\begingroup\$ Not a bad idea, but I do need anything that can be illuminated by the converging spotlight to also be illuminated by diverging spotlights. I'm going to give @DMGregory's solution a spin when I have time, and if that works out, post it as an answer \$\endgroup\$ May 31, 2022 at 21:53

You must log in to answer this question.

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