Skip to content

Instantly share code, notes, and snippets.

@talecrafter
Last active February 27, 2024 12:33
Show Gist options
  • Star 59 You must be signed in to star a gist
  • Fork 11 You must be signed in to fork a gist
  • Save talecrafter/81e2f3bb7fb4b4fc367e7b851772b646 to your computer and use it in GitHub Desktop.
Save talecrafter/81e2f3bb7fb4b4fc367e7b851772b646 to your computer and use it in GitHub Desktop.
/*
Basic Sprite Shader for aligning pixel art to the same grid, based on the Unity Sprite Shader.
Create one Material where you assign the same Pixels Per Unit value you use on your imported Sprites,
then reuse this Material on all appropriate Sprite Renderers.
(You can use Shader.SetGlobalFloat to set that Pixels Per Unit value for all your shaders:
https://docs.unity3d.com/ScriptReference/Shader.SetGlobalFloat.html)
This is not for scaled or rotated artwork. If you need those features, look at low res render textures.
Use this however you want.
@talecrafter
*/
Shader "Sprites/PixelArt"
{
Properties
{
[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
_Color ("Tint", Color) = (1,1,1,1)
_pixelsPerUnit("Pixels Per Unit", Float) = 16
}
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 _ UNITY_ETC1_EXTERNAL_ALPHA
#include "UnityCG.cginc"
struct appdata_t
{
float4 vertex : POSITION;
float4 color : COLOR;
float2 texcoord : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
float2 texcoord : TEXCOORD0;
};
fixed4 _Color;
float _pixelsPerUnit;
float4 AlignToPixelGrid(float4 vertex)
{
float4 worldPos = mul(unity_ObjectToWorld, vertex);
worldPos.x = floor(worldPos.x * _pixelsPerUnit + 0.5) / _pixelsPerUnit;
worldPos.y = floor(worldPos.y * _pixelsPerUnit + 0.5) / _pixelsPerUnit;
return mul(unity_WorldToObject, worldPos);
}
v2f vert(appdata_t IN)
{
float4 alignedPos = AlignToPixelGrid(IN.vertex);
v2f OUT;
OUT.vertex = mul(UNITY_MATRIX_MVP, alignedPos);
OUT.texcoord = IN.texcoord;
OUT.color = IN.color * _Color;
return OUT;
}
sampler2D _MainTex;
sampler2D _AlphaTex;
fixed4 SampleSpriteTexture(float2 uv)
{
fixed4 color = tex2D(_MainTex, uv);
#if ETC1_EXTERNAL_ALPHA
color.a = tex2D(_AlphaTex, uv).r;
#endif
return color;
}
fixed4 frag(v2f IN) : SV_Target
{
fixed4 c = SampleSpriteTexture (IN.texcoord) * IN.color;
c.rgb *= c.a;
return c;
}
ENDCG
}
}
}
@Skybladev2
Copy link

Don't you think it's better to add 0.625 instead of 0.5 to avoid rounding issues?
Or maybe there are no issues and this is an overkill? :)

@talecrafter
Copy link
Author

@Skybladev2
The 0.5 is for offsetting the result so the source position is inside a virtual square by all four possible new positions. It's half a pixel in world space which would be 0.03125 and not 0.0625 for a _pixelsPerUnit of 16. (I guess you meant 0.0625 and the missing 0 was a typo.)

Here's it written in another way:
float offset = 0.5 / _pixelsPerUnit;
worldPos.x = floor(worldPos.x * _pixelsPerUnit) / _pixelsPerUnit + offset;

@Skybladev2
Copy link

Skybladev2 commented Oct 4, 2016

@talecrafter
No, I meant 0.625 which is 3/4 - 1/8.
Ok, I checked - there is no difference between 0.5 and 0.625, so forget it.

@talecrafter
Copy link
Author

@Skybladev2
Ok, that's what you meant. Thanks for checking. :)

@edwardrowe
Copy link

Note it looks like before Unity 5.4, the functions in the UnityCG.cginc library "unity_WorldToObject" and "unity_ObjectToWorld" were named "_World2Object" and "_Object2World" respectively. https://forum.unity3d.com/threads/_object2world-undeclared.385227/

So if using this on older versions of unity, you'll want to change those lines or it won't compile.

Thanks for sharing the code @talecrafter!

@leegrey
Copy link

leegrey commented Jun 15, 2017

Hi @talecrafter. I've been using this shader and it's really useful! In a recent version of Unity it seems to be broken though. Would you happen to have patched this in the meantime? Any chance of updating the gist? Thanks for sharing! :)

EDIT: Oh, I just realised you have already updated it. It works now. Thank you!

@timsoret
Copy link

timsoret commented Aug 4, 2017

"(As far as I know there's no possiblity to get this value automatically.)"

You can use Unity - Scripting API: Shader.SetGlobalFloat
https://docs.unity3d.com/ScriptReference/Shader.SetGlobalFloat.html

It sets a float shared by all shaders at the same time.

@ezonecom
Copy link

Thanks for sharing, a must have for any pixel-perfect project!

@denartelny
Copy link

Good

@denartelny
Copy link

Bruh

Bruh

@TheStigC
Copy link

Is there a URP version of this? I'd love to be able to use this with the 2D lights

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment