Aug
5
2012

Old Film FX Shader

Converted from webgl shaders (source at devmaster.net). This should be nice as a camera shader?

Adjustable parameters in shader:
– SepiaValue, NoiseValue, ScratchValue, InnerVignetting, OuterVignetting, RandomValue, TimeLapse

Original barn image: http://www.cgtextures.com/texview.php?id=12170

Webplayer:
http://unitycoder.com/upload/demos/OldFilmShader1/

Readme pdf:
README_OldFilmFx_Shader_web

Purchase: (unity package)

0.50 eur [digishop id=”15″]

*unitypackage is saved with unity 3.5.6f4 (comes with example scene, see the ReadMe pdf above for more information)
Or use this,

Free source:


// old film shader, converted to unity from : http://devmaster.net/posts/shader-effects-old-film
// http://unitycoder.com/blog/2012/08/05/old-film-shader/

Shader "UnityCoder/OldFilm1"
{
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}

SepiaValue("SepiaValue", Float) = 0
NoiseValue("NoiseValue", Float) = 0
ScratchValue("ScratchValue", Float) = 0
InnerVignetting("InnerVignetting", Float) = 0
OuterVignetting("OuterVignetting", Float) = 0
RandomValue("RandomValue", Float) = 0
TimeLapse("TimeLapse", Float) = 0

}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200

CGPROGRAM
#pragma target 3.0
#pragma surface surf Lambert

sampler2D _MainTex;

uniform float SepiaValue;
uniform float NoiseValue;
uniform float ScratchValue;
uniform float InnerVignetting;
uniform float OuterVignetting;
uniform float RandomValue;
uniform float TimeLapse;

struct Input {
float2 uv_MainTex;
};

/// <summary>
/// Computes the overlay between the source and destination colours.
/// <summary>
float3 Overlay (float3 src, float3 dst)
{
// if (dst <= O) then: 2 * src * dst
// if (dst > O) then: 1 - 2 * (1 - dst) * (1 - src)
return float3((dst.x <= 0.5) ? (2.0 * src.x * dst.x) : (1.0 - 2.0 * (1.0 - dst.x) * (1.0 - src.x)),
(dst.y <= 0.5) ? (2.0 * src.y * dst.y) : (1.0 - 2.0 * (1.0 - dst.y) * (1.0 - src.y)),
(dst.z <= 0.5) ? (2.0 * src.z * dst.z) : (1.0 - 2.0 * (1.0 - dst.z) * (1.0 - src.z)));
}

float3 mod289(float3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
float2 mod289(float2 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
float3 permute(float3 x) { return mod289(((x*34.0)+1.0)*x); }

float snoise (float2 v)
{
const float4 C = float4(0.211324865405187,  // (3.0-sqrt(3.0))/6.0
0.366025403784439,  // 0.5*(sqrt(3.0)-1.0)
-0.577350269189626, // -1.0 + 2.0 * C.x
0.024390243902439); // 1.0 / 41.0

// First corner
float2 i  = floor(v + dot(v, C.yy) );
float2 x0 = v -   i + dot(i, C.xx);

// Other corners
float2 i1;
i1 = (x0.x > x0.y) ? float2(1.0, 0.0) : float2(0.0, 1.0);
float4 x12 = x0.xyxy + C.xxzz;
x12.xy -= i1;

// Permutations
i = mod289(i); // Avoid truncation effects in permutation
float3 p = permute( permute( i.y + float3(0.0, i1.y, 1.0 ))
+ i.x + float3(0.0, i1.x, 1.0 ));

float3 m = max(0.5 - float3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0);
m = m*m ;
m = m*m ;

// Gradients: 41 points uniformly over a line, mapped onto a diamond.
// The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287)

float3 x = 2.0 * frac(p * C.www) - 1.0;
float3 h = abs(x) - 0.5;
float3 ox = floor(x + 0.5);
float3 a0 = x - ox;

// Normalise gradients implicitly by scaling m
// Approximation of: m *= inversesqrt( a0*a0 + h*h );
m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h );

// Compute final noise value at P
float3 g;
g.x  = a0.x  * x0.x  + h.x  * x0.y;
g.yz = a0.yz * x12.xz + h.yz * x12.yw;
return 130.0 * dot(m, g);
}

void surf (Input IN, inout SurfaceOutput o)
{

// Sepia RGB value
float3 sepia = float3(112.0 / 255.0, 66.0 / 255.0, 20.0 / 255.0);

// Step 1: Convert to grayscale
float3 colour = tex2D(_MainTex,  IN.uv_MainTex.xy).xyz;
float gray = (colour.x + colour.y + colour.z) / 3.0;
float3 grayscale = float3(gray);

// Step 2: Appy sepia overlay
float3 finalColour = Overlay(sepia, grayscale);

// Step 3: Lerp final sepia colour
finalColour = grayscale + SepiaValue * (finalColour - grayscale);

// Step 4: Add noise
float noise = snoise(IN.uv_MainTex.xy * float2(1024.0 + RandomValue * 512.0, 1024.0 + RandomValue * 512.0)) * 0.5;
finalColour += noise * NoiseValue;

// Optionally add noise as an overlay, simulating ISO on the camera
//vec3 noiseOverlay = Overlay(finalColour, vec3(noise));
//finalColour = finalColour + NoiseValue * (finalColour - noiseOverlay);

// Step 5: Apply scratches
if ( RandomValue < ScratchValue )
{
// Pick a random spot to show scratches
float dist = 1.0 / ScratchValue;
//RandomValue *= _Time.y*10;
float d = distance(IN.uv_MainTex.xy, float2(RandomValue * dist, RandomValue * dist));
if ( d < 0.4 )
{
// Generate the scratch
float xPeriod = 8.0;
float yPeriod = 1.0;
float pi = 3.141592;
float phase = TimeLapse;
//                    float phase = _Time.x*TimeLapse;
//                    float phase = _Time.x;
float turbulence = snoise(IN.uv_MainTex.xy * 2.5);
float vScratch = 0.5 + (sin(((IN.uv_MainTex.x * xPeriod + IN.uv_MainTex.y * yPeriod + turbulence)) * pi + phase) * 0.5);
vScratch = clamp((vScratch * 10000.0) + 0.35, 0.0, 1.0);

finalColour.xyz *= vScratch;
}
}

// Step 6: Apply vignetting
// Max distance from centre to corner is ~0.7. Scale that to 1.0.
float d = distance(float2(0.5, 0.5), IN.uv_MainTex) * 1.414213;
float vignetting = clamp((OuterVignetting - d) / (OuterVignetting - InnerVignetting), 0.0, 1.0);
finalColour.xyz *= vignetting;

// Apply colour
//gl_FragColor.xyz = finalColour;
//gl_FragColor.w = 1.0;

//half4 c = tex2D (_MainTex, IN.uv_MainTex);
o.Albedo = finalColour;
o.Alpha = 1;
}
ENDCG
}
FallBack "Diffuse"
}


25 Comments + Add Comment

  • Hi, I saw your old film example and it was amazing, I’m trying to create something like that as well but I kinda new in unity (so I have no idea how to make it), can you help me with this? are you willing to share your code?

    Thanks in advance.

    • Yes, I’ll post it later this week! (forgot to reply this earlier..)

  • Source added

  • Someone sent feedback on this page, had to remove it due to too many f-words..(about the toolbar). Sorry about that, and yes, the annoying toolbar will go away eventually.

  • Hi, really nice shader. Just wondering if there’s a way to adjust the transparency with it?

    • Not in this version.
      But could be easy add, how the alpha would work?
      – Just use the base texture alpha?
      – or no base texture at all, just noise where white or black parts would be transparent?
      – and/or using some blending modes

  • VCR distortion (shader toy)
    https://www.shadertoy.com/view/ldjGzV

  • So it seems this is just to be applied to a particular texture and can’t be used to create the effect over your entire scene?

    • Yes its only for image, camera view would need rendertextures (pro only) and few modifications (use rendertexture instead of the image)

      • Gotcha. I really need to save up for the pro license then! This is a great shader and would love to apply it to my camera view.

        • Or actually it would work with GetPixels (basically constantly taking screenshot, instead of rendertextures), slower of course.. see here for info:
          http://forum.unity3d.com/threads/198568-Epic-Radial-Blur-Effect-for-Unity-Indie

          • How about creating a large transparent texture to apply the shader on, and then placing that texture in front of the camera with the rest of the scene behind it? This may not be practical in most situations, but for my 2D game this should work well.

            I tried doing this, but I couldn’t figure out how to modify the shader to leave the texture transparent; I’m not a shader programmer, so I don’t know if what I’m trying to do will work.

          • That could work, easiest way would be setting a blend mode:
            https://docs.unity3d.com/Documentation/Components/SL-Blend.html

            for example add this line to the shader:
            Blend One One // Additive

  • Hmm I tried that but the texture is showing up as solid black. Here’s the shader code that I modified.

    I can confirm that the completely cleared texture has an alpha channel, and in Unity I’ve selected the “Alpha is transparent” option for it.

    • *emailed you new version with alpha value slider

      • Awesome, thanks!

        I tried it out, and it seems the change made the alpha channel transparent on the texture, but the actual shader effect isn’t applied to the alpha channel (which makes sense, since it’s completely transparent). I can try adjusting the alpha value so it’s not completely transparent?

        • Yes, that one takes the alpha directly from texture, could just remove the texture alpha, and make it 0.5f or so for whole image instead.

          • Ah yes, got it working how I want it. Awesome, thanks for all the help and the awesome shader!

          • So I’ve recently deployed this shader to an Ouya, and it simply couldn’t handle it; the FPS dropped to single digits. Off the top of your head, do you think there’s anything that can be done to optimize the shader for Tegra 3? I want to dive into it myself, but thought I would ask first before heading down a winless crusade!

          • havent really went into shader optimization myself.. but i would probably try making it simpler with noise texture, instead of calculating noise with sin and those other heavy functions..

            vignetting, sepia could be removed (just put them in the image already if needed..)

            some other tips that i’ve seen:
            http://www.humus.name/index.php?page=Articles
            also few here (those float/fixed/half)
            http://docs.unity3d.com/Documentation/Components/SL-ShaderPerformance.html

  • nice noise (shader)
    http://thndl.com/more-noise.html

  • I pay for the shader but I didnt got it???

  • Hi, sorry about that, it looks like the download link end up in my junk folder 🙂

    Thank you very much!

    Regards
    Dusan

  • Hi, I just found your website by total coincidence and I am impressed how much work went in 😀

    Thanks you so much this filter also works with Unity 2018. The only error I got was wrong format on line 107 where it says grayscale = float3(Gray) which is a single float number 0o I just changed it to (colour.x/3.0,colour.y/3.0,colour.z/3.0) and it worked.

    How could you make that effect in front of the camera guys, that’s what I actually way looking for :/

Leave a comment

Connect

Twitter View LinkedIn profile Youtube Youtube Join Discord Twitch

UnityLauncherPro

Get UnityLauncherPRO and work faster with Unity Projects!
*free unity hub alternative

@unitycoder_com

Subscribe to Blog via Email

Enter your email address to subscribe to this blog and receive notifications of new posts by email.