Skip to content

Instantly share code, notes, and snippets.

@partybusiness
Last active January 8, 2023 19:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save partybusiness/9997db4b20ed88697b73fe9abf520220 to your computer and use it in GitHub Desktop.
Save partybusiness/9997db4b20ed88697b73fe9abf520220 to your computer and use it in GitHub Desktop.
VHS style camera
Shader "Unlit/CircleBlur"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Radius ("Radius", float) = 0.8
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float4 _MainTex_TexelSize;
float _Radius;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 def = tex2D(_MainTex, i.uv);
fixed4 col = 0;
float tau = 6.28318530718;
float quality = 2.0;
fixed directions = 14; //if I have these two hard-coded then it can unroll the loop better
float scale = _Radius *_MainTex_TexelSize.x;
for (float d = 0.0; d<tau; d += tau / directions) {
for (float c = 1.0 / quality; c <= 1.0; c += 1.0 / quality)
{
col += tex2D(_MainTex, i.uv + float2(cos(d), sin(d))*scale*c);
}
}
col /= directions * quality;
return col;
}
ENDCG
}
}
}
Shader "Unlit/DrawVHSFrame"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Even ("Even / Odd", int) = 0
}
SubShader
{
Tags { "RenderType"="Transparent" }
LOD 100
Blend SrcAlpha OneMinusSrcAlpha
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float4 _MainTex_TexelSize;
fixed _Even;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
//based on https://www.shadertoy.com/view/3lycWz
fixed3 rgb2yuv(fixed3 rgb) {
float y = 0.299*rgb.r + 0.587*rgb.g + 0.114*rgb.b;
return fixed3(y, 0.493*(rgb.b - y), 0.877*(rgb.r - y));
}
fixed3 yuv2rgb(fixed3 yuv) {
float y = yuv.x;
float u = yuv.y;
float v = yuv.z;
return fixed3(
y + 1.0 / 0.877*v,
y - 0.39393*u - 0.58081*v,
y + 1.0 / 0.493*u
);
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
//convert to YUV
fixed3 yuv = rgb2yuv(col.rgb);
//horizontal blur on chroma channels
fixed ts = _MainTex_TexelSize.x;
fixed3 blurred = col.rgb * 2.0;
for (int c = 1; c < 10; c++) {
float weight = 2.0 - c *0.1; //make further pixels have lower weight
blurred += ((tex2D(_MainTex, i.uv + fixed2(ts * c, 0)).rgb + tex2D(_MainTex, i.uv + fixed2(-ts * c, 0)).rgb)) * weight;
}
blurred = blurred / 20; // 9 * 2 (loop) + 2 (col) = 20
fixed3 blurredYUV = rgb2yuv(blurred);
//convert back to RGB
fixed3 rgb = yuv2rgb(fixed3(yuv.r, blurredYUV.gb));
//interlace
fixed opaque = round( ((i.uv.y * _MainTex_TexelSize.w + _Even) / 2.0) %1 );
return fixed4(rgb*lerp(0.7, 1, opaque), lerp(0.1, 1, opaque));
}
ENDCG
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ForceAspectRatio : MonoBehaviour {
void Start () {
GetComponent<Camera>().aspect = 4f / 3f; //you can force 4:3 aspect ratio on a camera rendering to a render texture
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Interlacing : MonoBehaviour {
[SerializeField]
private Material evenMaterial; //material that renders all even lines: DrawVHSFrame with _Even set to 1
[SerializeField]
private Material oddMaterial; //material that renders all odd lines: DrawVHSFrame with _Even set to 0
[SerializeField]
private RenderTexture source; //texture the in-game camera is rendering to
[SerializeField]
private RenderTexture dest; //texture you display on-screen
private bool evenField = false;
void Start () {
Application.targetFrameRate = 60;
}
void Update () {
//alternates between updating even and odd fields every frame
Graphics.Blit(source, dest, evenField?evenMaterial:oddMaterial, -1);
evenField = !evenField;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment