Good evening) I make a 2d outline shader. Found answer to the post: https://forum.unity.com/threads/help-to-find-an-asset-solution.755273/#post-5246960 there, script came up to me, but the outline resizes with the removal of the camera (I'm trying to make the size static (the size of the contour changes with the removal of the camera, but I do NOT need it ) Will you help me please?( script: Code (CSharp): Shader "Unlit/Spine Outline" { Properties { _MainTex ("Texture", 2D) = "white" {} _OutlineColor ("Outline Color", Color) = (1,1,1,1) _OutlineWidth ("Outline Width", Range(0, 4)) = 1 } SubShader { Tags { "Queue"="Transparent" "RenderType"="Transparent" } LOD 100 ZWrite Off Blend SrcAlpha OneMinusSrcAlpha CGINCLUDE #include "UnityCG.cginc" sampler2D _MainTex; float4 _MainTex_ST; fixed4 _OutlineColor; float _OutlineWidth; struct v2fOutline { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; }; v2fOutline vertOutline (appdata_base v, float2 offset) { v2fOutline o; o.pos = UnityObjectToClipPos(v.vertex); o.pos.xy += offset * 2 * o.pos.w * _OutlineWidth / _ScreenParams.xy; o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); return o; } fixed4 fragOutline (v2fOutline i) : SV_Target { fixed alpha = tex2D(_MainTex, i.uv).a; fixed4 col = _OutlineColor; col.a *= alpha; return col; } ENDCG Pass { CGPROGRAM #pragma vertex vert #pragma fragment fragOutline v2fOutline vert (appdata_base v) { return vertOutline(v, float2( 1, 1)); } ENDCG } Pass { CGPROGRAM #pragma vertex vert #pragma fragment fragOutline v2fOutline vert (appdata_base v) { return vertOutline(v, float2(-1, 1)); } ENDCG } Pass { CGPROGRAM #pragma vertex vert #pragma fragment fragOutline v2fOutline vert (appdata_base v) { return vertOutline(v, float2( 1,-1)); } ENDCG } Pass { CGPROGRAM #pragma vertex vert #pragma fragment fragOutline v2fOutline vert (appdata_base v) { return vertOutline(v, float2(-1,-1)); } ENDCG } Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct v2f { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; float4 color : TEXCOORD1; }; v2f vert (appdata_full v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); o.color = v.color; return o; } fixed4 frag (v2f i) : SV_Target { return tex2D(_MainTex, i.uv) * i.color; } ENDCG } } }
The shader was designed such that _OutlineWidth was defined in screen pixels width. The _ScreenParams in the above shader holds the current render resolution. You can remove that / _ScreenParams.xy, but then the _OutlineWidth will be in "screen space" width. I'm not entirely sure what you mean by "removal of the camera" though. Are you using this on something you're manually rendering to a render texture?
Let me explain again what I want to do: this shader adjusts the outline size depending on the distant camera, but I don't need that. I need a outline size of 3 (for example), that is, when the camera is farther away, it will be almost invisible (or it will be visible but quite a bit) will you help me please? if remove _ScreenParams.xy from the code, then the outline will appear only if the camera is very, very close. Gif:
3 what. Three sprite texels? The shader has no idea how big a texel is in the vertex shader (where this code is running), so that's not actually possible to do programatically. You'd have to fudge the size to be whatever you needed. And it'll break if the sprite's scale changes because, again, the vertex shader has no idea how big a texel is. Because the _OutlineWidth is now in screen widths. If you originally had the value at "3" or something, you'll want to set it to something like 0.002 after you remove that value to get something similar. But it's technically still being done in screen space. For what you're looking to do you probably want something like this: Code (csharp): // add this line v.vertex.xy += offset * _OutlineWidth; o.pos = UnityObjectToClipPos(v.vertex); // comment this line out or delete it // o.pos.xy += offset * 2 * o.pos.w * _OutlineWidth / _ScreenParams.xy; If you're working on your sprites on a pixel sized canvas, _OutlineWidth will be fairly easy to understand as it'll just be canvas pixels. But again, if you scale the sprite to anything not 1:1 you'll have to figure out what the "correct" _OutlineWidth value is.
Thank you very much! You wrote in two minutes what I could not do in two days) And yes, shaders are an interesting topic, though little is clear)
Once again I have to contact you ... I'm trying to improve this shader, as I found out that I could use the Flip function in SpriteRenderer, I had to write "Cull Off". Then I decided to get rid of the weird, narrow outline. It appears even when "_OutlineWidth" = 0, no matter how the script is written So: Code (CSharp): v2fOutline vertOutline (appdata_base v, float2 offset) { v2fOutline o; o.pos = UnityObjectToClipPos(v.vertex); o.pos.xy += offset * 2 * o.pos.w * _OutlineWidth / _ScreenParams.xy; o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); return o; } Or like this: Code (CSharp): v2fOutline vertOutline (appdata_base v, float2 offset) { v2fOutline o; v.vertex.xy += offset * _OutlineWidth; o.pos = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); return o; } I solved the given problem with a small outline (even with _OutlineWidth = 0) like this: Code (CSharp): fixed4 fragOutline (v2fOutline i) : SV_Target { fixed alpha = tex2D(_MainTex, i.uv).a; fixed4 col = _OutlineColor; col.a *= alpha; // solution if (_OutlineWidth == 0) { col.rgba = fixed4(0, 0, 0, 0); } // return col; } This is a good decision? And the last thing. I needed to make the outline adjust to the screen size (as it was at the very beginning), but with some kind of border (that is, the outline size adjusts to the distance of the camera if it is not too far (some number)) ... That is, with a very strong distance from the camera, this would not happen: (the picture is not that far away but this is just an example. I will be glad for any help (especially with the last question, it worries me very much) For earlier thanks)
Its "fine", but not necessarily great. A better option would probably be to swap the sprite's material to one that doesn't use the outline shader instead. Otherwise I'd probably fix it in the vertex shader. Setting the alpha to zero does mean you don't see it, but you're still paying the full cost of it rendering at those pixels. Code (csharp): v.vertex.xy += offset * _OutlineWidth; o.pos = UnityObjectToClipPos(v.vertex); if (_OutlineWidth == 0.0) o.pos = float4(0,0,0,0); Doing it that way will mean the meshes get shrunk down infinitely small and all fragment shader costs for the additional passes will disappear.
The last lines in the post above refer to the shader in its original state (where the outline size adjusts to fit the screen). I will try to ask again How about putting a limit on the maximum size of the outline? (that is, if the camera is too far, for example, then the increase in the outline width stops) This worries me, and the last thing I want to improve. And yes, thank you so much for the answer.
This specific technique can't handle sharp corners, unless the edges align perfectly with the world space axis. It's an unsolvable limitation of a multi-pass setup like this. If you want outlines on arbitrarily rotated objects, you will need to do the outline using a different technique.