Hello. Right now I have an 2D outline shader working pretty fine. This is done in the common way to sample the same texture multiple times giving an offset on different directions.
The problem is, as the texture has been cut out inside unity, the technique is applied to the neighbors frames as well, going inside the current frame when the outline is too big or the free space not too much, or both.
I have searched for solution and read that probably texel size (with some calculations) could help me here. I also read in the post here that I could detect when a texture is going outside of the normal [0,1] uv values and just discard it.
So, here are my questions:
- First of all, how sprite renderer works in unity? it seems to be handling all its properties automatically. For example, I haven’t set anything related to flip and the flip works. But most important, the shader looks to hold the entire texture but the sprite is just showing the assigned frame. Yes this is because it is cut out, but, when is this done during the render process?
- Second, directly related to the above question. If the “frame selection” stuff is done automatically, is there actually a way to say: “Hey, discard all the “frames” (this through the normal pixel work of course) that are outside of the current uv sample”?. I ask this because maybe that part of the flow is done AFTER the entire custom shader, so the “extra frames” are never outside of the uv.
Image with the problem is exaggerated because I can’t show the real sprite, but mine is failing with a pretty small outline. That’s why I need the solution
To show the problem I am using the outline from 1 side so it is easier to see the problem
Thanks a lot for anyone who can, at least, let me know if I this is possible or I would need to go and search for another feature or change all the spritesheets.
Good day!
Shader "Unlit/outlineShaderTest"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_outlineThickness("Outline Thickness", Range(0, 1)) = 0
_outlineColor ("Outline Color", Color) = (1,1,1,1)
}
SubShader
{
Tags { "Queue"="Transparent" }
Blend SrcAlpha OneMinusSrcAlpha
Cull Off
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 pos : SV_POSITION;
};
sampler2D _MainTex;
float _outlineThickness;
float4 _outlineColor;
v2f vert (appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos (v.vertex);
o.uv = v.uv;
return o;
}
fixed4 CreateABorder(float2 uv, float4 mainTextureSampler, sampler2D mainTextureWithoutSampling, float xOfsset, float yoffset){
uv.x += xOfsset;
uv.y += yoffset;
float4 border = saturate(tex2D(mainTextureWithoutSampling, uv).aaaa - mainTextureSampler.aaaa);
return border;
}
fixed4 frag (v2f i) : SV_Target
{
float2 uv = i.uv ;
sampler2D mainTex = _MainTex;
fixed4 mainTexture = tex2D(mainTex, uv);
// CREATE OUTLINE BORDERS --------------------------------------------------------
fixed4 bottomOutlineTexture = CreateABorder(uv, mainTexture, mainTex, 0, _outlineThickness);
fixed4 topOutlineTexture = CreateABorder(uv, mainTexture, mainTex, 0, -_outlineThickness);
fixed4 leftOutlineTexture = CreateABorder(uv, mainTexture, mainTex, -_outlineThickness, 0);
fixed4 rightOutlineTexture = CreateABorder(uv, mainTexture, mainTex, _outlineThickness, 0);
////-----------------------------------------------------------------------------
float4 outlineBaseColor = _outlineColor;
// ADDING BORDERS ALL TOGETHER ---------------------------------------------------
float4 finalOutlineColor = saturate(
bottomOutlineTexture +
topOutlineTexture +
leftOutlineTexture +
rightOutlineTexture);
// ------------------------------------------------------------------------------
finalOutlineColor *= outlineBaseColor;
float4 finalTextureColor = mainTexture + finalOutlineColor;
return finalTextureColor;
}
ENDCG
}
}
}