-
-
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 | |
} | |
} | |
} |
@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.
@Skybladev2
Ok, that's what you meant. Thanks for checking. :)
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!
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!
"(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.
Thanks for sharing, a must have for any pixel-perfect project!
Good
Bruh
Bruh
Is there a URP version of this? I'd love to be able to use this with the 2D lights
@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;