Search Unity

Long exposure shader?

Discussion in 'Shaders' started by Democide, May 20, 2015.

  1. Democide

    Democide

    Joined:
    Jan 29, 2013
    Posts:
    315
    I'm meaning to create a sort of long-exposure shader, something like this:



    It will make the bright things cause trails based on their real world position, with these trails slowly fading over time. I know trail renderers might do the trick but they are not an option at the moment.

    Anyone have some pointers on how to go about this?
     
  2. Chman

    Chman

    Unity Technologies

    Joined:
    Feb 6, 2010
    Posts:
    721
    Why aren't trails an option ?
     
  3. Torigas

    Torigas

    Joined:
    Jan 1, 2014
    Posts:
    63
    You might want to look at the build in motion blur shaders. (Effects/ImageEffects/MotionBlur.cs + the shader).
    They actually have a comment in there about clamping the blur amount to avoid trails.
    Looks like a good starting point.
    Perhaps using HDR + Blur beforehand would result in the expected behaviour.
     
  4. imaginaryhuman

    imaginaryhuman

    Joined:
    Mar 21, 2010
    Posts:
    5,834
    Depending on the length of the trail that you want this could require a massive amount of rendering. If you rendered into an HDR buffer for example, you probably would need hundreds of passes in order to create a smooth looking streak like that. It would be extremely slow. Even for 50 passes it would be very slow. You going to render your scene at all those moments in time? It's basically the same thing as motion blur which is expensive.
     
  5. Torigas

    Torigas

    Joined:
    Jan 1, 2014
    Posts:
    63
    It shouldn't be too expensive if you use the last frame's image as a source and write to the current image. I might try to rig something up later.
     
    Mehrdad995 likes this.
  6. Democide

    Democide

    Joined:
    Jan 29, 2013
    Posts:
    315
    Using the last frame's image doesn't really work if the camera is locked to the moving object...
     
  7. Torigas

    Torigas

    Joined:
    Jan 1, 2014
    Posts:
    63
    Maybe I seem to understand something wrong here but doesn't a long exposure thing do just that?
    Light gets to fall onto the chip for a long timespan.
    If you don't move the camera and the objects move you get fancy trails (if they are bright).
    If you move the camera you get a very blurry image.

    To me, that's just what long exposure time does. And that seems to be quite easily approximated by a motion blur-ish shader.
     
    Mehrdad995 likes this.
  8. Zicandar

    Zicandar

    Joined:
    Feb 10, 2014
    Posts:
    388
    A long exposure "shader" is simply by NOT Clearning the screen!
    Just add to it every frame.
    Really!
    It can be that simple :D.
    However note that the rest of what's visible has to be VERY dark in comparison to the "streaks". And that you need to use Addative shaders instead of the overwriting opaque ones.
    (Or I'd suggest that you have a post process gather the final image, letting unity clear as usual and use unmodified shaders)
     
    Mehrdad995 and Torigas like this.
  9. Torigas

    Torigas

    Joined:
    Jan 1, 2014
    Posts:
    63
    One problem with simply not clearing the screen, however, is that the OP wanted the effects to slowly fade.

    So the Image would have to be like "max(oldImageColor *0.99 (ish),newImageColor)"
     
    Mehrdad995 likes this.
  10. Zicandar

    Zicandar

    Joined:
    Feb 10, 2014
    Posts:
    388
    A couple of things there, the 0.99 must be multiplied by delta time, or else the fade is framerate dependant.
    And why the max? I'm guessing to prevent the non-streaking parts to go to bright over time? (A "real" long exposure also add's up the non-bright stuff, but then again, we might not wan't the "real" effect.)
    If we don't use the max a blend mode of:
    Code (CSharp):
    1.  
    2. Blend One SrcAlpha
    3.  
    And output deltaTime multiplied by ( 1 / NumFramesToAddTogether).
    Should give the result asked for?
    Ofc, if the camera MOVES, there will be issues, alot of issues :D
    The way to handle a moving camera is to reconstruct the previous frames pixel positions, (crytek developed a nice way of doing this, and alot of engines now use that!). If ONLY the camera moves it's quite simple, but if objects also move it's harder and needs a velocity buffer.
     
  11. Torigas

    Torigas

    Joined:
    Jan 1, 2014
    Posts:
    63
    You're right! If you don't use max the image turns white awfully white.
    As promised, i rigged a silly little thing up.

    If you want to move the Camera AND the trails to stay where they are in world space it gets quite complicated as the post before this one describes =)
    Code (CSharp):
    1.  
    2. using System;
    3. using UnityEngine;
    4.  
    5. /// <summary>
    6. /// Light trails. Based on the Unity Motion Blur
    7. /// </summary>
    8. namespace UnityStandardAssets.ImageEffects
    9. {
    10.     [ExecuteInEditMode]
    11.     [AddComponentMenu("Image Effects/Blur/LightTrails2")]
    12.     [RequireComponent(typeof(Camera))]
    13.     public class LightTrails : ImageEffectBase
    14.     {
    15.         public float blurAmount = 0.8f;
    16.  
    17.         public RenderTexture accumTexture;
    18.  
    19.         override protected void Start()
    20.         {
    21.             if (!SystemInfo.supportsRenderTextures)
    22.             {
    23.                 enabled = false;
    24.                 return;
    25.             }
    26.             base.Start();
    27.             accumTexture = new RenderTexture(1, 1, 0);
    28.         }
    29.  
    30.         override protected void OnDisable()
    31.         {
    32.             base.OnDisable();
    33.             DestroyImmediate(accumTexture);
    34.         }
    35.  
    36.         // Called by camera to apply image effect
    37.         void OnRenderImage (RenderTexture source, RenderTexture destination)
    38.         {
    39.             // Create the accumulation texture
    40.             if (accumTexture == null || accumTexture.width != source.width || accumTexture.height != source.height)
    41.             {
    42.                 DestroyImmediate(accumTexture);
    43.                 accumTexture = new RenderTexture(source.width, source.height, 0);
    44.                 accumTexture.hideFlags = HideFlags.HideAndDontSave;
    45.                 accumTexture.isPowerOfTwo = false;
    46.                 accumTexture.Create();
    47.                 Graphics.Blit( source, accumTexture );
    48.                 accumTexture.MarkRestoreExpected();
    49.             }
    50.             blurAmount = Mathf.Clamp( blurAmount, 0.0f, 10.0f );
    51.             // We are accumulating motion over frames without clear/discard
    52.             // by design, so silence any performance warnings from Unity
    53.             accumTexture.MarkRestoreExpected();
    54.  
    55.             material.SetTexture("_AccumTex",accumTexture);
    56.             material.SetFloat("_AccumOrig", 1.0F-blurAmount*Time.deltaTime);
    57.          
    58.          
    59.             Graphics.Blit (source, destination,material);
    60.             Graphics.Blit (destination, accumTexture);      
    61.          
    62.         }
    63.     }
    64. }
    65.  
    66.  
    Code (CSharp):
    1. Shader "Image Effects/Blur/LightTrails2" {
    2. Properties {
    3.     _MainTex ("Base (RGB)", 2D) = "white" {}
    4.     _AccumTex ("Base (RGB)", 2D) = "black" {}
    5. }
    6.  
    7. SubShader {
    8.     Pass {
    9.         ZTest Always Cull Off ZWrite Off
    10.              
    11. CGPROGRAM
    12. #pragma vertex vert_img
    13. #pragma fragment frag
    14. #include "UnityCG.cginc"
    15.  
    16. uniform sampler2D _MainTex;
    17. uniform sampler2D _AccumTex;
    18. uniform float _AccumOrig;
    19.  
    20. float4 frag (v2f_img i) : SV_Target
    21. {
    22.     float4 original = tex2D(_MainTex, i.uv);
    23.     float4 accum = tex2D(_AccumTex, i.uv);
    24.     return max(accum*_AccumOrig, original);
    25. }
    26. ENDCG
    27.  
    28.     }
    29. }
    30.  
    31. Fallback off
    32.  
    33. }
    34.  
     

    Attached Files:

    Mehrdad995 likes this.
  12. McDev02

    McDev02

    Joined:
    Nov 22, 2010
    Posts:
    664
    That sounds like the most efficient method if you want the camera to move because in the real world the camera is static as well. I don't believe a shader will do that because you need any kind of 3D representation of the data, such as volumes, meshes or splines and render those somehow.

    When you move the camera you could prevent the blurring effect but the trails would remain local on the screen and this might not be the effect that you want to achieve.
     
    Last edited: May 22, 2015