Search Unity

Retroreflector (bike reflector) in Unity

Discussion in 'Shaders' started by Arlert, Jul 21, 2016.

  1. Arlert

    Arlert

    Joined:
    Jul 14, 2013
    Posts:
    3
    Need help in making retroreflector in unity. is there any ideas or code of such shader? smth like bike reflectors or hi-vis road signs.
     
  2. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    You can try standard shader, the trick will be in how you arrange the normals texture, you probably don't need a specific shader for this.
     
  3. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,342
    Getting a normal texture that handles this properly will be difficult, but is plausible close enough cameras & high enough resolutions. The problem will be any situation where the texture gets small enough that you loose the small details it'll start acting like a normal flat surface which isn't what you want.

    I can't think of seeing any examples of this kind of shader either, though a basic one wouldn't be hard. Getting a physically plausible one is a little harder.

    If you start with the "simple specular" example on the surface shader light example page here:
    https://docs.unity3d.com/Manual/SL-SurfaceShaderLightingExamples.html

    Change this line:
    float nh = max (0, dot (s.Normal, h));

    To:
    float nh = max (0, dot (viewDir, h));
     
    hippocoder likes this.
  4. Lost-in-the-Garden

    Lost-in-the-Garden

    Joined:
    Nov 18, 2015
    Posts:
    176
    (bike) reflectors are retroreflective (see https://en.wikipedia.org/wiki/Retroreflector). They reflect most of the incoming light back at the direction it came from, mostly independent of the incident angle of the light. That means, that the object appears brightest when the light source and the camera are coming from the same direction.

    For example, when in a car, you (the camera) and the headlights (light source) are pretty much in the same spot and thus the reflector lights up nicely.

    fun fact: grass is also retro reflective (a bit at least) :D edit: here's the link: https://en.wikipedia.org/wiki/Heiligenschein
     
    Last edited: Jul 27, 2016
    hippocoder likes this.
  5. Waffleslug

    Waffleslug

    Joined:
    Jan 3, 2013
    Posts:
    12
    The simplest way to achieve a retroreflective material is to have the normals of the surface pointing towards the light in the lighting step. This is simple to achieve with Unity's Surface Shaders.

    Using the second example on https://docs.unity3d.com/Manual/SL-SurfaceShaderLightingExamples.html we can just modify the lighting function.

    Code (csharp):
    1. Shader "Example/Retroreflective Example"
    2. {
    3.     Properties
    4.     {
    5.         _MainTex ("Texture", 2D) = "white" {}
    6.     }
    7.  
    8.     SubShader
    9.     {
    10.         Tags { "RenderType" = "Opaque" }
    11.         CGPROGRAM
    12.         #pragma surface surf SimpleLambert
    13.  
    14.         half4 LightingSimpleLambert (SurfaceOutput s, half3 lightDir, half atten)
    15.         {
    16.             half NdotL = dot (s.Normal, lightDir);
    17.          
    18.             // It should only be reflecting light that could actually enter it
    19.             // if NdotL is negative that means the surface normal is pointing away from the light
    20.             if(NdotL > 0)
    21.             {
    22.                 // Retroreflective materials return most of their light in the opposite direction that it came in
    23.                 half3 retroNormal = 1 - lightDir;
    24.                 // allow some of the surface normal to influence this so it's not perfectly retroreflective.
    25.                 retroNormal = lerp(s.Normal, retroNormal, 0.8);
    26.                 NdotL = dot(retroNormal, lightDir);
    27.             }
    28.          
    29.             half4 c;
    30.             c.rgb = s.Albedo * _LightColor0.rgb * (NdotL * atten);
    31.             c.a = s.Alpha;
    32.             return c;
    33.         }
    34.  
    35.         struct Input
    36.         {
    37.             float2 uv_MainTex;
    38.         };
    39.  
    40.         sampler2D _MainTex;
    41.  
    42.         void surf (Input IN, inout SurfaceOutput o)
    43.         {
    44.             o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
    45.         }
    46.         ENDCG
    47.     }
    48.     Fallback "Diffuse"
    49. }
     
  6. ryancampfire

    ryancampfire

    Joined:
    Jan 4, 2017
    Posts:
    31
    I've been trying this and it just makes things dark.

    I'm not great with shaders but I'm trying out a version based on this and the simple specular shader. Basically treating the reflection like a specular highlight, but I need to reflect a different direction.
     
  7. ryancampfire

    ryancampfire

    Joined:
    Jan 4, 2017
    Posts:
    31
    So I hit on something that works pretty well and is fairly simple.

    Code (csharp):
    1.  
    2. CGPROGRAM
    3.         #pragma surface surf RetroReflection
    4.  
    5.         half4 LightingRetroReflection (SurfaceOutput s, half3 lightDir, half3 viewDir, half atten) {
    6.             half diff = max (0, dot (s.Normal, lightDir));
    7.             half retro = max (0, 1 - length(lightDir - viewDir))*2.5+0.5;
    8.  
    9.             half4 c;
    10.             c.rgb = (s.Albedo * _LightColor0.rgb * diff + s.Albedo * retro * atten ) * atten;
    11.             c.a = s.Alpha;
    12.             return c;
    13.         }
    14.  
    15.         struct Input {
    16.             float2 uv_MainTex;
    17.             float2 uv_BumpMap;
    18.         };
    19.  
    20.         sampler2D _MainTex;
    21.         sampler2D _BumpMap;
    22.      
    23.         fixed4 _Color;
    24.  
    25.         void surf (Input IN, inout SurfaceOutput o) {
    26.             fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
    27.             o.Albedo = c.rgb;
    28.             o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));
    29.             o.Alpha = c.a;
    30.         }
    31.         ENDCG
    32.  
    It's modified from the specular shader.

    Important bit is right here:

    half retro = max (0, 1 - length(lightDir - viewDir))*2.5+0.5;

    Simple once you see it. The closer the lightDir and viewDir are to being the same, the brighter it is. I spent a lot of time trying to account for the normal in there, but it's not worth it, really. Maybe throw in pow() function and adjust the other values until you get something that looks right for you.

    Also down here:

    c.rgb = (s.Albedo * _LightColor0.rgb * diff + s.Albedo * retro * atten ) * atten;

    For my purposes, I'm basing the retro reflection colour on Albedo but I expect in a lot of cases you'll want to use the LightColor instead. I also have atten in there twice, I felt like it looks better when I make absolutely sure it doesn't reflect when it's in a shadow.
     
  8. Viker

    Viker

    Joined:
    May 10, 2016
    Posts:
    1
    Hey. I am trying a retroreflective shader too. Have you made any progress since?
     
  9. ryancampfire

    ryancampfire

    Joined:
    Jan 4, 2017
    Posts:
    31
    I didn't do much beyond what I posted here. Is that working for you?