Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Drawing a trail via shaders

Discussion in 'Shaders' started by SharpeDesigns, Oct 31, 2015.

  1. SharpeDesigns

    SharpeDesigns

    Joined:
    Mar 4, 2015
    Posts:
    4
    Hey everyone!

    Currently working on a project where the player uncovers the map as they move across the world. Almost like a fog of war kind of setup. Tried a million other option involving multiple cameras, dynamic textures, image effects, etc. but it seems like shaders are the way to go for this scenario. Total beginner in this area so I figured I'd ask if anyone could point me in the right direction?

    After doing tons of research, here is a solution I found that's *so close* to what I need. From what I can tell, it works by calculating the distance from the target and swapping the texture of all the UV's inside the radius. I simplified this by just working with one texture and lerping the RBG values based on the distance from the player. Problem is, I can't for the life of me figure out how to prevent the values from re-darkening after the player leaves.

    So basically, I'm wondering if there's any way I could preserve the RBG values once the UV coordinates are outside the player's radius so they don't re-darken after the player moves on.

    Here's a really poor illustration of what I have now based on the shader above vs. the effect I'm looking for:
    ProblemMockup.gif

    And if it helps, here's the current shader code I'm working with:
    Code (CSharp):
    1. Shader "Custom/LightTrail"
    2. {
    3.     Properties
    4.     {
    5.         // Default properties
    6.         _Color("Color", Color) = (1,1,1,1)
    7.         _MainTex("Albedo", 2D) = "white" {}
    8.         _BumpScale("Scale", Float) = 1.0
    9.         _BumpMap("Normal Map", 2D) = "bump" {}
    10.         _EmissionColor("Color", Color) = (0,0,0)
    11.         _EmissionMap("Emission", 2D) = "white" {}
    12.  
    13.         // Paint Properties
    14.         _LightPos("Light Position", Vector) = (0,0,0,0)
    15.         _LightRad("Light Radius", Range(0.0, 300.0)) = 100
    16.         _BorderWidth("Border Width", Range(0.0, 150.0)) = 50
    17.         _BorderColor("Border Color", Color) = (1,1,1,1)
    18.         [MaterialToggle] _Cylindrical("Cylindrical (Ignore Y axis)", Float) = 0
    19.     }
    20.  
    21.     SubShader
    22.     {
    23.         Tags{ "RenderType" = "Opaque" "PerformanceChecks" = "False" }
    24.         LOD 300
    25.         CGPROGRAM
    26.         #pragma surface surf Lambert
    27.  
    28.         struct Input {
    29.             float2 uv_DiffuseFar;   // Far-texture UV
    30.             float2 uv_DiffuseNear;  // Near-texture UV
    31.             float3 worldPos;        // World-space position of the player
    32.         };
    33.  
    34.         sampler2D _MainTex;
    35.         float _LightRad;
    36.         float _BorderWidth;
    37.         float _Cylindrical;
    38.         float4 _LightPos;
    39.         fixed4 _BorderColor;
    40.  
    41.         void surf(Input IN, inout SurfaceOutput o)
    42.         {
    43.             float3 d = (float3)_LightPos - IN.worldPos;
    44.             // Using Distance Squared eliminates the need for a costly square root calculation
    45.             float distSq = d.x*d.x + d.z*d.z + (1.0f - _Cylindrical)*d.y*d.y;
    46.             float farDistSq = _LightRad + _BorderWidth / 2;
    47.             farDistSq *= farDistSq;
    48.             float nearDistSq = _LightRad - _BorderWidth / 2;
    49.             nearDistSq *= nearDistSq;
    50.  
    51.             // Alpha (gradient between inner and outer texture) is calculated using the distance
    52.             // saturate() is used to limit the alpha to the range 0 - 1
    53.             float al = saturate((_LightRad * _LightRad) / distSq);
    54.             float alpha = saturate((distSq - nearDistSq) / (farDistSq - nearDistSq));
    55.             // Border alpha is the alpha of the border (0-1) at a point.
    56.             float border_alpha = abs(alpha * 2 - 1);
    57.             //Below are the 4
    58.             half4 c_f = tex2D(_MainTex, IN.uv_DiffuseFar);
    59.             half4 c_n = tex2D(_MainTex, IN.uv_DiffuseNear);
    60.             float3 finalColor;
    61.             float multiplier = min(1, (nearDistSq / distSq) / 5);
    62.  
    63.             // Set the color for uv's within the light radius
    64.             if (distSq <= nearDistSq) {
    65.                 finalColor = c_n.rgb * multiplier;
    66.             }
    67.             // Set the color for uv's outside the light radius
    68.             else {
    69.                 if (c_f.rgb.r == c_n.rgb.r) {
    70.                     finalColor = c_n.rgb * multiplier;
    71.                 }
    72.                 else {
    73.                     finalColor = fixed3(0, 0, 0);
    74.                 }
    75.             }
    76.             // Outputs the new albedo values
    77.             o.Albedo = lerp(c_n.rgb, lerp(c_n.rgb, finalColor.rgb, alpha), 1);
    78.         }
    79.         ENDCG
    80.     }
    81.         FallBack "VertexLit"
    82. }
    Any help or suggestions would be greatly appreciated!
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,238
    Shaders don't preserve state. By themselves they can't do something based on what happened in a previous frame, they can only do stuff with the information given to them. If you want to know something about a previous frame you have to store it yourself and pass it to the next update.

    Render to texture with an extra camera is the most common way to do this.
     
  3. bricevdm

    bricevdm

    Joined:
    Nov 4, 2009
    Posts:
    34
    as bgolus said :) set the "don't clear" flag on the isometric camera that renders to texture, and voila. you can use the texture for a projector, or into a custom shader that computes UVs for the top down projection