Hi, sorry to bother you guys. Until recently, I had been using in multipass VR a certain free outline effect I found in the forums, but recently we upgraded our project to Unity 2017.1 and we switched to Single pass stereo. Problem is, the shader seem to be incompatible with Single pass Stereo (since it’s basically a screen Space effect). I already talked to the author ,but he isn’t very good with shaders either and was asking for help in his thread (and well, he doesn’t seem to work with VR, so I can’t foresee him fixing it very soon anyways…)
Anyway, the object was becoming fully covered by the effect and the right eye had an offset. And since, I’ve managed to fix one or two post processing effects before, I tried to follow the reference page for SPS, wich appears in the Unity manual, but, I could’t get it to work (outline seem to appear, but it’s the wrong color, and it’s also squashed and offset to the right).
Sadly, I’m pretty much a noob when it comes to shader programming… So, I would greatly appreciate it if someone could point me in the right direction (since I can’t really tell what’s wrong with it…).
The git repository: GitHub - cakeslice/Outline-Effect: Outline Image Effect for Unity
If you don’t want to download it, here’s the shader code only (with some of the stuff I tried):
Shader "Hidden/OutlineEffect"
{
Properties
{
_MainTex ("Base (RGB)", 2D) = "white" {}
}
SubShader
{
Pass
{
Tags{ "RenderType" = "Opaque" }
LOD 200
ZTest Always
ZWrite Off
Cull Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 3.0
#include "UnityCG.cginc"
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _OutlineSource;
struct v2f
{
float4 position : SV_POSITION;
float2 uv : TEXCOORD0;
};
v2f vert(appdata_img v)
{
v2f o;
o.position = UnityObjectToClipPos(v.vertex);
o.uv = v.texcoord;
return o;
}
float _LineThicknessX;
float _LineThicknessY;
int _FlipY;
uniform float4 _MainTex_TexelSize;
half4 frag(v2f input) : COLOR
{
float2 uv = input.uv;
if (_FlipY == 1)
uv.y = uv.y;
#if UNITY_UV_STARTS_AT_TOP
if (_MainTex_TexelSize.y < 0)
uv.y = 1 - uv.y;
#endif
//half4 originalPixel = tex2D(_MainTex,input.uv, UnityStereoScreenSpaceUVAdjust(input.uv, _MainTex_ST));
half4 outlineSource = tex2D(_OutlineSource, UnityStereoScreenSpaceUVAdjust(uv, _MainTex_ST));
const float h = .95f;
/*
half4 sample1 = tex2D(_OutlineSource, uv + float2(_LineThicknessX,0.0));
half4 sample2 = tex2D(_OutlineSource, uv + float2(-_LineThicknessX,0.0));
half4 sample3 = tex2D(_OutlineSource, uv + float2(.0,_LineThicknessY));
half4 sample4 = tex2D(_OutlineSource, uv + float2(.0,-_LineThicknessY));*/
half4 sample1 = tex2D(_OutlineSource, UnityStereoScreenSpaceUVAdjust(uv + float2(_LineThicknessX,0.0), _MainTex_ST));
half4 sample2 = tex2D(_OutlineSource, UnityStereoScreenSpaceUVAdjust(uv + float2(-_LineThicknessX,0.0), _MainTex_ST));
half4 sample3 = tex2D(_OutlineSource, UnityStereoScreenSpaceUVAdjust(uv + float2(.0,_LineThicknessY), _MainTex_ST));
half4 sample4 = tex2D(_OutlineSource, UnityStereoScreenSpaceUVAdjust(uv + float2(.0,-_LineThicknessY), _MainTex_ST));
bool red = sample1.r > h || sample2.r > h || sample3.r > h || sample4.r > h;
bool green = sample1.g > h || sample2.g > h || sample3.g > h || sample4.g > h;
bool blue = sample1.b > h || sample2.b > h || sample3.b > h || sample4.b > h;
if ((red && blue) || (green && blue) || (red && green))
return float4(0,0,0,0);
else
return outlineSource;
}
ENDCG
}
Pass
{
Tags { "RenderType"="Opaque" }
LOD 200
ZTest Always
ZWrite Off
Cull Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 3.0
#include "UnityCG.cginc"
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _OutlineSource;
struct v2f {
float4 position : SV_POSITION;
float2 uv : TEXCOORD0;
};
v2f vert(appdata_img v)
{
v2f o;
o.position = UnityObjectToClipPos(v.vertex);
o.uv = v.texcoord;
return o;
}
float _LineThicknessX;
float _LineThicknessY;
float _LineIntensity;
half4 _LineColor1;
half4 _LineColor2;
half4 _LineColor3;
int _FlipY;
int _Dark;
float _FillAmount;
int _CornerOutlines;
uniform float4 _MainTex_TexelSize;
half4 frag (v2f input) : COLOR
{
float2 uv = input.uv;
if (_FlipY == 1)
uv.y = 1 - uv.y;
#if UNITY_UV_STARTS_AT_TOP
if (_MainTex_TexelSize.y < 0)
uv.y = 1 - uv.y;
#endif
half4 originalPixel = tex2D(_MainTex, UnityStereoScreenSpaceUVAdjust(input.uv, _MainTex_ST));
half4 outlineSource = tex2D(_OutlineSource, UnityStereoScreenSpaceUVAdjust(uv, _MainTex_ST));
const float h = .95f;
half4 outline = 0;
bool hasOutline = false;
/*
half4 sample1 = tex2D(_OutlineSource, uv + float2(_LineThicknessX,0.0));
half4 sample2 = tex2D(_OutlineSource, uv + float2(-_LineThicknessX,0.0));
half4 sample3 = tex2D(_OutlineSource, uv + float2(.0,_LineThicknessY));
half4 sample4 = tex2D(_OutlineSource, uv + float2(.0,-_LineThicknessY));*/
half4 sample1 = tex2D(_OutlineSource, UnityStereoScreenSpaceUVAdjust(uv + float2(_LineThicknessX,0.0), _MainTex_ST));
half4 sample2 = tex2D(_OutlineSource, UnityStereoScreenSpaceUVAdjust(uv + float2(-_LineThicknessX,0.0), _MainTex_ST));
half4 sample3 = tex2D(_OutlineSource, UnityStereoScreenSpaceUVAdjust(uv + float2(.0,_LineThicknessY), _MainTex_ST));
half4 sample4 = tex2D(_OutlineSource, UnityStereoScreenSpaceUVAdjust(uv + float2(.0,-_LineThicknessY), _MainTex_ST));
bool outside = outlineSource.a < h;
bool outsideDark = outside && _Dark;
if (_CornerOutlines)
{
// TODO: Conditional compile
/*half4 sample5 = tex2D(_OutlineSource, uv + float2(_LineThicknessX, _LineThicknessY));
half4 sample6 = tex2D(_OutlineSource, uv + float2(-_LineThicknessX, -_LineThicknessY));
half4 sample7 = tex2D(_OutlineSource, uv + float2(_LineThicknessX, -_LineThicknessY));
half4 sample8 = tex2D(_OutlineSource, uv + float2(-_LineThicknessX, _LineThicknessY));*/
half4 sample5 = tex2D(_OutlineSource, UnityStereoScreenSpaceUVAdjust(uv + float2(_LineThicknessX, _LineThicknessY), _MainTex_ST));
half4 sample6 = tex2D(_OutlineSource, UnityStereoScreenSpaceUVAdjust(uv + float2(-_LineThicknessX, -_LineThicknessY), _MainTex_ST));
half4 sample7 = tex2D(_OutlineSource, UnityStereoScreenSpaceUVAdjust(uv + float2(_LineThicknessX, -_LineThicknessY), _MainTex_ST));
half4 sample8 = tex2D(_OutlineSource, UnityStereoScreenSpaceUVAdjust(uv + float2(-_LineThicknessX, _LineThicknessY), _MainTex_ST));
if (sample1.r > h || sample2.r > h || sample3.r > h || sample4.r > h ||
sample5.r > h || sample6.r > h || sample7.r > h || sample8.r > h)
{
outline = _LineColor1 * _LineIntensity * _LineColor1.a;
if (outsideDark)
originalPixel *= 1 - _LineColor1.a;
hasOutline = true;
}
else if (sample1.g > h || sample2.g > h || sample3.g > h || sample4.g > h ||
sample5.g > h || sample6.g > h || sample7.g > h || sample8.g > h)
{
outline = _LineColor2 * _LineIntensity * _LineColor2.a;
if (outsideDark)
originalPixel *= 1 - _LineColor2.a;
hasOutline = true;
}
else if (sample1.b > h || sample2.b > h || sample3.b > h || sample4.b > h ||
sample5.b > h || sample6.b > h || sample7.b > h || sample8.b > h)
{
outline = _LineColor3 * _LineIntensity * _LineColor3.a;
if (outsideDark)
originalPixel *= 1 - _LineColor3.a;
hasOutline = true;
}
if (!outside)
outline *= _FillAmount;
}
else
{
if (sample1.r > h || sample2.r > h || sample3.r > h || sample4.r > h)
{
outline = _LineColor1 * _LineIntensity * _LineColor1.a;
if (outsideDark)
originalPixel *= 1 - _LineColor1.a;
hasOutline = true;
}
else if (sample1.g > h || sample2.g > h || sample3.g > h || sample4.g > h)
{
outline = _LineColor2 * _LineIntensity * _LineColor2.a;
if (outsideDark)
originalPixel *= 1 - _LineColor2.a;
hasOutline = true;
}
else if (sample1.b > h || sample2.b > h || sample3.b > h || sample4.b > h)
{
outline = _LineColor3 * _LineIntensity * _LineColor3.a;
if (outsideDark)
originalPixel *= 1 - _LineColor3.a;
hasOutline = true;
}
if (!outside)
outline *= _FillAmount;
}
//return outlineSource;
if (hasOutline)
return lerp(originalPixel + outline, outline, _FillAmount);
else
return originalPixel;
}
ENDCG
}
}
FallBack "Diffuse"
}
Shader "Hidden/OutlineBufferEffect" {
Properties
{
[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
_Color ("Tint", Color) = (1,1,1,1)
[MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
}
SubShader
{
Tags
{
"Queue" = "Transparent"
"IgnoreProjector" = "True"
"RenderType" = "Transparent"
"PreviewType" = "Plane"
"CanUseSpriteAtlas" = "True"
}
// Change this stuff in OutlineEffect.cs instead!
//ZWrite Off
//Blend One OneMinusSrcAlpha
Cull [_Culling]
Lighting Off
CGPROGRAM
#pragma surface surf Lambert vertex:vert nofog noshadow noambient nolightmap novertexlights noshadowmask nometa //keepalpha
#pragma multi_compile _ PIXELSNAP_ON
sampler2D _MainTex;
fixed4 _Color;
float _OutlineAlphaCutoff;
struct Input
{
float2 uv_MainTex;
//fixed4 color;
};
void vert(inout appdata_full v, out Input o)
{
#if defined(PIXELSNAP_ON)
v.vertex = UnityPixelSnap(v.vertex);
#endif
UNITY_INITIALIZE_OUTPUT(Input, o);
//o.color = v.color;
}
void surf(Input IN, inout SurfaceOutput o)
{
fixed4 c = tex2D(_MainTex, IN.uv_MainTex);// * IN.color;
if (c.a < _OutlineAlphaCutoff) discard;
float alpha = c.a * 99999999;
o.Albedo = _Color * alpha;
o.Alpha = alpha;
o.Emission = o.Albedo;
}
ENDCG
}
Fallback "Transparent/VertexLit"
}