Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by Tomer-Barkan · Aug 26, 2015 at 09:21 PM · shadertextureshaderssprites

Shaders - offset texture coordinates by a single pixel

I'm trying to make an outline shader for sprites, so I need to check adjacent pixels in the texture. However, the tex2d() shader function expects 0..1 for x/y coordinates, so if I want to offset by a single pixel, I would have to know the texture's size. Since I use unity's sprite packer, these are usually fairly large sprites.

Is there a way to check a neighboring pixel in the texture? Is there a way to get the texture size in pixels, so I can calculate this myself?

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

2 Replies

· Add your reply
  • Sort: 
avatar image
3
Best Answer

Answer by _Gkxd · Aug 27, 2015 at 12:55 AM

I adapted the default sprite shader to do roughly what you want:

 Shader "Custom/OutlinedSprite"
 {
     Properties
     {
         [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
         _Color ("Tint", Color) = (1,1,1,1)
         _OutlineColor ("Outline", Color) = (1,1,1,1)
         [MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
     }
 
     SubShader
     {
         Tags
         { 
             "Queue"="Transparent" 
             "IgnoreProjector"="True" 
             "RenderType"="Transparent" 
             "PreviewType"="Plane"
             "CanUseSpriteAtlas"="True"
         }
 
         Cull Off
         Lighting Off
         ZWrite Off
         Blend One OneMinusSrcAlpha
 
         Pass
         {
         CGPROGRAM
             #pragma vertex vert
             #pragma fragment frag
             #pragma multi_compile _ PIXELSNAP_ON
             #include "UnityCG.cginc"
             
             struct appdata_t
             {
                 float4 vertex   : POSITION;
                 float4 color    : COLOR;
                 float2 texcoord : TEXCOORD0;
             };
 
             struct v2f
             {
                 float4 vertex   : SV_POSITION;
                 fixed4 color    : COLOR;
                 half2 texcoord  : TEXCOORD0;
             };
             
             fixed4 _Color;
             fixed4 _OutlineColor;
             float _TexWidth;
             float _TexHeight;
 
             v2f vert(appdata_t IN)
             {
                 v2f OUT;
                 OUT.vertex = mul(UNITY_MATRIX_MVP, IN.vertex);
                 OUT.texcoord = IN.texcoord;
                 OUT.color = IN.color * _Color;
                 #ifdef PIXELSNAP_ON
                 OUT.vertex = UnityPixelSnap (OUT.vertex);
                 #endif
 
                 return OUT;
             }
 
             sampler2D _MainTex;
             float4 _MainTex_TexelSize;
 
 
             fixed4 frag(v2f IN) : SV_Target
             {
                 fixed4 c = tex2D(_MainTex, IN.texcoord) * IN.color;
 
                 if (c.a == 0) {
                     return fixed4(0, 0, 0, 0); // Skip outline for transparent pixels
                 }
 
                 // Get the colors of the surrounding pixels
                 fixed4 up = tex2D(_MainTex, IN.texcoord + fixed2(0, _MainTex_TexelSize.y));
                 fixed4 down = tex2D(_MainTex, IN.texcoord - fixed2(0, _MainTex_TexelSize.y));
                 fixed4 left = tex2D(_MainTex, IN.texcoord - fixed2(_MainTex_TexelSize.x, 0));
                 fixed4 right = tex2D(_MainTex, IN.texcoord + fixed2(_MainTex_TexelSize.x, 0));
 
                 // This method uses an if statement
                 if (up.a * down.a * left.a * right.a == 0) {
                     c.rgb = _OutlineColor.rgb;
                 }
 
                 /* This method doesn't use an if statement, but it won't work for sprites with semi-transparency. 
 
                 I prefer the previous method because I don't notice any performace difference between the two.
 
                 float isNotOutline = up.a * down.a * left.a * right.a;
                 c.rgb = isNotOutline * c.rgb + (1-isNotOutline) * _OutlineColor;
                 
                 */
 
                 c.rgb *= c.a;
                 return c;
             }
         ENDCG
         }
     }
 }

The outline here will appear inside the sprite. It's pretty easy to change so that the outline is on the outside of the sprite, but there are some edge cases that you have to handle when you're at the edge of a sprite.

Here is the original sprite, rendered using a normal sprite renderer: alt text

Here is the sprite with the sprite renderer's material set to one that uses the outline shader: alt text

Edit:
To answer your question, float4 _MainTex_TexelSize; gets a few numbers that are relevant to the texture called _MainTex.

It gives you a 4-vector where the first two elements are the size of one pixel in uv coordinates, and the last 2 elements is the resolution of the texture.


sprite.png (3.3 kB)
outlinedsprite.png (3.8 kB)
Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Tomer-Barkan · Aug 27, 2015 at 04:46 AM 0
Share

Perfect!

I guess _$$anonymous$$aintex_TexelSize is something that Unity sets per texture? Is this documented somewhere? I found this link http://docs.unity3d.com/$$anonymous$$anual/SL-UnityShaderVariables.html but there's nothing there about _TexelSize...

avatar image _Gkxd · Aug 27, 2015 at 06:57 AM 0
Share

There's this Twitter post from someone at Unity, which I saw in some other answer before: https://twitter.com/aras_p/status/258567507487637504

Other than that, I couldn't find any "official" documentation either.

avatar image
1

Answer by IgorAherne · Aug 26, 2015 at 09:25 PM

-how to offset by 1 pixel http://vvvv.org/documentation/tutorial-effects-neighbouring-pixels

  • how to set up the offset http://answers.unity3d.com/questions/256638/acessing-a-global-variable-in-shader.html

I am not familiar with sprites, but I understand that you would like to have different uniform variables per different meshes. Ideally you would want to use 1 material to avoid any additional draw calls.

Whatever the case is, you are applying a texture on triangles of a mesh (quad etc).

A mesh is made of vertices which carry position, uv coordinates and a color.

You can color code the meshes' vertices with color. In shader, have several uniforms (20, 40, doesn't matter, uniforms are cheap). Test the for the color of vertex and use the appropriate offset uniform. Say if you see that the vertex is yellow - apply the offset with offset = 0.2, else if pinkish = 0.3 etc

.

That way you can tweak the values once, setting up all the uniforms via the c# script or directly in the editor via properties of material, ensuring that they look good on all the quads and save on the drawcalls, having just 1 material.

You will have to look into optimizing dynamic branching. Shaders don't like loops and if/else statements. See how you can implement step / mix() functions

Comment
Add comment · Show 5 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image IgorAherne · Aug 26, 2015 at 09:27 PM 0
Share

should be the same for sprites

avatar image Tomer-Barkan · Aug 26, 2015 at 09:35 PM 0
Share

Thanks, I actually read that one, but I find it problematic to have to create a new material for every sprite to set it's size... Isn't there a way to do this from within the shader given the texture?

I found this reference: http://http.developer.nvidia.com/Cg/tex2Dsize.html but it doesn't seem to work within unity.

avatar image IgorAherne · Aug 26, 2015 at 10:06 PM 0
Share

ok, check out the answer now, edited it

avatar image IgorAherne · Aug 26, 2015 at 10:14 PM 0
Share

vertex paint in 3ds max

avatar image Tomer-Barkan · Aug 27, 2015 at 05:02 AM 0
Share

Thanks for your explanation. I'm familiar with the basics of meshes and shaders, the main issue was looking at a neighboring pixel of the texture given the uv coordinates of the current fragment only. See _Gkxd's answer.

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

26 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Are shaders more efficient than manual pixel replacement? 0 Answers

How to use a shader to write to a mipmap (partial mipmap update) 2 Answers

Mobile Shader with Albedo Color and Normal Map 0 Answers

Shader on 3D model not seen over 2D sprites 0 Answers

There is an issue with texture wrapping around sphere's in unity 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges