Sooo after keeping myself busy finding all my mistakes about the tutorial ive made in this:
https://willweissman.wordpress.com/tutorials/shaders/unity-shaderlab-object-outlines/)
I would like to provide a very simple solution- where you dont even have to understand shaders at all.
Create a new Camera Gameobject which only Renders things you want in a RenderTexture. That Rendertexture will later have the Outline.
(Set the Culling Mask to a new "Outline" layer.
Set the Layer of the Objects you want the outline for to the same layer.)
Also create a new RenderTexture and put it inside "TargetTexture" of your camera.
Put this script inside that camera gameobject
public class OutlineEffect : MonoBehaviour
{
public bool Gauss;
public Material WhiteMaker;
public Material PostOutline;
public Material GaussianBlur;
private Camera cam;
void Start()
{
cam = GetComponent<Camera>();
}
void OnRenderImage(RenderTexture source, RenderTexture destination)
{
RenderTexture TempRT = new RenderTexture(cam.pixelWidth, cam.pixelHeight, 24);
RenderTexture whiteRT = new RenderTexture(TempRT.width, TempRT.height, TempRT.depth);
Graphics.Blit(source, whiteRT, WhiteMaker);
if (Gauss)
{
Graphics.Blit(whiteRT, TempRT, PostOutline);
Graphics.Blit(TempRT, destination, GaussianBlur);
}
else
{
Graphics.Blit(whiteRT, destination, PostOutline);
}
}
}
put these shaders inside a material with the same name and put those materials inside that script in step 2.
WHITEMAKER SHADER
Shader "WhiteMaker" {
Properties
{
_MainTex("Main Texture 1", 2D) = "white" {}
}
SubShader
{
Tags{ "Queue" = "Transparent" }
Pass
{
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
half _SampleTime;
v2f_img vert(appdata_base v)
{
v2f_img o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.texcoord.xy;
return o;
}
float4 frag(v2f_img i) : COLOR
{
// Surface
float4 main = tex2D(_MainTex, i.uv);
if (main.a == 0)
{
return float4(0, 0, 0, 0);
}
else
{
return float4(1, 1, 1, 1);
}
return main;
}
ENDCG
}
}
}
POST OUTLINE SHADER
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with
'UnityObjectToClipPos(*)'
Shader "Custom/Post Outline"
{
Properties
{
_MainTex("Main Texture",2D) = "black"{}
_SceneTex("Scene Texture",2D) = "black"{}
}
SubShader
{
Pass
{
CGPROGRAM
sampler2D _MainTex;
float4 _MainTex_ST;
//<SamplerName>_TexelSize is a float2 that says how much screen space a texel occupies.
float2 _MainTex_TexelSize;
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 pos : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
};
v2f vert(appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.pos);
o.uv = o.pos.xy / 2 + 0.5;
return o;
}
half frag(v2f i) : COLOR
{
//arbitrary number of iterations for now
int NumberOfIterations = 20;
//split texel size into smaller words
float TX_x = _MainTex_TexelSize.x;
//and a final intensity that increments based on surrounding intensities.
float ColorIntensityInRadius;
//for every iteration we need to do horizontally
for (int k = 0; k<NumberOfIterations; k += 1)
{
//increase our output color by the pixels in the area
ColorIntensityInRadius += tex2D(
_MainTex,
i.uv.xy + float2
(
(k - NumberOfIterations / 2)*TX_x,
0
)
).r / NumberOfIterations;
}
//output some intensity of teal
return ColorIntensityInRadius;
}
ENDCG
}
//end pass
GrabPass{}
Pass
{
CGPROGRAM
sampler2D _MainTex;
sampler2D _SceneTex;
float4 _MainTex_ST;
//we need to declare a sampler2D by the name of "_GrabTexture" that Unity can write to during GrabPass{}
sampler2D _GrabTexture;
//<SamplerName>_TexelSize is a float2 that says how much screen space a texel occupies.
float2 _GrabTexture_TexelSize;
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 pos : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
};
v2f vert(appdata v)
{
v2f o;
//Despite the fact that we are only drawing a quad to the screen, Unity requires us to multiply vertices by our MVP matrix, presumably to keep things working when inexperienced people try copying code from other shaders.
o.pos = UnityObjectToClipPos(v.pos);
//Also, we need to fix the UVs to match our screen space coordinates. There is a Unity define for this that should normally be used.
o.uv = o.pos.xy / 2 + 0.5;
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
half4 frag(v2f i) : COLOR
{
//arbitrary number of iterations for now
int NumberOfIterations = 20;
//split texel size into smaller words
float TX_y = _GrabTexture_TexelSize.y;
//and a final intensity that increments based on surrounding intensities.
half ColorIntensityInRadius = 0;
//if something already exists underneath the fragment (in the original texture), discard the fragment.
if (tex2D(_MainTex,i.uv.xy).r>0)
{
discard;
return tex2D(_SceneTex,float2(i.uv.x,1 - i.uv.y));
}
//for every iteration we need to do vertically
for (int j = 0; j<NumberOfIterations; j += 1)
{
//increase our output color by the pixels in the area
ColorIntensityInRadius += tex2D(
_GrabTexture,
float2(i.uv.x,1 - i.uv.y) + float2
(
0,
(j - NumberOfIterations / 2)*TX_y
)
).r / NumberOfIterations;
}
//this is alpha blending, but we can't use HW blending unless we make a third pass, so this is probably cheaper.
half4 outcolor = ColorIntensityInRadius*half4(0,1,1,1) * 2 + (1 - ColorIntensityInRadius)*tex2D(_SceneTex,float2(i.uv.x,1 - i.uv.y));
return outcolor;
}
ENDCG
}
//end pass
}
//end subshader
}
//end shader
^
[POST OUTLINE SHADER ENDS HERE]
GAUSSIAN BLUR SHADER
Shader "Blur"
{
Properties
{
_MainTex("Base (RGB)", 2D) = "white" { }
}
SubShader
{
ZTest Always Cull Off ZWrite Off Fog{ Mode Off }
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
float4 _MainTex_TexelSize;
float step_w;
float step_h;
struct v2f
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
};
float4 _MainTex_ST;
float4 _MainTex_ST_TexelSize;
v2f vert(appdata_base v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
}
fixed4 frag(v2f i) : COLOR
{
step_w = _MainTex_TexelSize.x;
step_h = _MainTex_TexelSize.y;
float2 offset[25] =
{
float2(-step_w*2.0, -step_h*2.0), float2(-step_w, -step_h*2.0), float2(0.0, -step_h*2.0), float2(step_w, -step_h*2.0), float2(step_w*2.0, -step_h*2.0),
float2(-step_w*2.0, -step_h), float2(-step_w, -step_h), float2(0.0, -step_h), float2(step_w, -step_h), float2(step_w*2.0, -step_h),
float2(-step_w*2.0, 0.0), float2(-step_w, 0.0), float2(0.0, 0.0), float2(step_w, 0.0), float2(step_w*2.0, 0.0),
float2(-step_w*2.0, step_h), float2(-step_w, step_h), float2(0.0, step_h), float2(step_w, step_h), float2(step_w*2.0, step_h),
float2(-step_w*2.0, step_h*2.0), float2(-step_w, step_h*2.0), float2(0.0, step_h*2.0), float2(step_w, step_h * 20), float2(step_w*2.0, step_h*2.0)
};
float kernel[25] =
{
0.003765, 0.015019, 0.023792, 0.015019, 0.003765,
0.015019, 0.059912, 0.094907, 0.059912, 0.015019,
0.023792, 0.094907, 0.150342, 0.094907, 0.023792,
0.015019, 0.059912, 0.094907, 0.059912, 0.015019,
0.003765, 0.015019, 0.023792, 0.015019, 0.003765
};
float4 sum = float4(0.0, 0.0, 0.0, 0.0);
for (int j = 0; j < 25; j++)
{
float4 tmp = tex2D(_MainTex, i.uv + offset[j]);
sum += tmp * kernel[j];
}
return sum;
}
ENDCG //Shader End
}
}
}
create a new "raw image" inside a UI canvas.
Put the Rendertexture inside that Rawimage. And set the Camera Height and Width as the image Height and Width.
Its done! You can check the "Gauss" bool true or false- depends on which you prefer. Also you can change the color of the raw image