Skip to content

Instantly share code, notes, and snippets.

@antonkudin
Last active September 22, 2023 07:44
Show Gist options
  • Star 71 You must be signed in to star a gist
  • Fork 14 You must be signed in to fork a gist
  • Save antonkudin/9ff45ec9a2c6755b3e7f4221faef81a1 to your computer and use it in GitHub Desktop.
Save antonkudin/9ff45ec9a2c6755b3e7f4221faef81a1 to your computer and use it in GitHub Desktop.
//
// shader starts here, c# companion script below
//
// PS. Make sure to use square texture (sides must be equal)
//
Shader "Unlit/spritePixelated"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
[Header(Scaling)]
_Res ("Resolution", Float) = 1024
_PixelSize ("Pixel Size", Float) = .0625
[Header(Sprite MetaData)]
_SpriteUV ("Sprite Rect", Vector) = (1,1,0,0)
_SpritePivot ("Sprite Pivot", Vector) = (1,1,0,0)
_UVCenter ("_UVCenter", Vector) = (0,0,0,0)
}
SubShader
{
Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"
"DisableBatching"="True"
}
LOD 100
Blend SrcAlpha OneMinusSrcAlpha
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
uniform half _Res, _PixelSize;
uniform half4 _SpriteUV, _SpritePivot, _UVCenter;
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float2 quant(float2 q, float2 v){
return floor(q/v)*v;
}
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
float2 quantToWorld(float2 value, float q){
float2 wp = mul(unity_ObjectToWorld, float4(value,0,0) );
wp = quant(wp, q) ;
return mul(unity_WorldToObject, float4(wp,0,0));
}
fixed4 frag (v2f i) : SV_Target
{
float2 uv = i.uv;
// next line is the pixelation
uv = quantToWorld(uv-_UVCenter.xy, 1/_Res)+_UVCenter.xy;
fixed4 col = tex2D(_MainTex, uv);
clip(col.a-.001);
return col;
}
ENDCG
}
}
}
// c# companion script
// SpriteUVToShader.cs -------------------------------------------------------------------------------------------------------------------------------- //
// Save you your project, add to your SpriteRenderer gameObject
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
[ExecuteInEditMode]
[RequireComponent(typeof(SpriteRenderer))]
public class SpriteUVToShader : MonoBehaviour {
public string UV_property="_SpriteUV";
public string Pivot_property="_SpritePivot";
public string uvCenter_property="_UVCenter";
public string textureSize_property="_Res";
public string pixelSize_property="_PixelSize";
SpriteRenderer sr;
Sprite sprite;
MaterialPropertyBlock mpb;
void OnValidate()
{
update();
}
void OnWillRenderObject(){
update();
}
void Start(){
update();
}
void update(){
if(sr==null)
sr = GetComponent<SpriteRenderer>();
if(sprite != sr.sprite){
sprite = sr.sprite;
applySpriteUV(sr, sprite, ref mpb, UV_property, Pivot_property, uvCenter_property);
applySpriteTX(sr, sprite, ref mpb, textureSize_property, pixelSize_property);
}
}
public static void applySpriteUV(Renderer renderer, Sprite toSprite, ref MaterialPropertyBlock mpb,
string uvProp=null, string pivotProp=null, string uvCenterProp=null){
if(toSprite==null) return;
var scale = new Vector2(
toSprite.textureRect.width/ toSprite.texture.width,
toSprite.textureRect.height/toSprite.texture.height);
var offset = new Vector2(
toSprite.rect.x/toSprite.texture.width,
toSprite.rect.y/toSprite.texture.height);
Vector4 uvVector = new Vector4(scale.x,scale.y,offset.x,offset.y);
Vector4 pivotVector = new Vector4(toSprite.pivot.x/toSprite.rect.width,toSprite.pivot.y/toSprite.rect.height);
if(string.IsNullOrEmpty(uvProp))
uvProp = "_MainTex_ST";
if(mpb==null)
mpb = new MaterialPropertyBlock();
renderer.GetPropertyBlock(mpb);
mpb.SetVector(uvProp, uvVector);
if(!string.IsNullOrEmpty(pivotProp))
mpb.SetVector(pivotProp, pivotVector);
if(!string.IsNullOrEmpty(uvCenterProp))
mpb.SetVector(uvCenterProp, new Vector2(
Mathf.Lerp(uvVector.z, uvVector.z+uvVector.x, pivotVector.x),
Mathf.Lerp(uvVector.w, uvVector.w+uvVector.y, pivotVector.y)
));
renderer.SetPropertyBlock(mpb);
}
public static void applySpriteTX(Renderer renderer, Sprite toSprite, ref MaterialPropertyBlock mpb,
string texSizeProp=null, string pixSizeProp=null){
if(toSprite==null || string.IsNullOrEmpty(texSizeProp)) return;
if(mpb==null)
mpb = new MaterialPropertyBlock();
renderer.GetPropertyBlock(mpb);
mpb.SetFloat(texSizeProp, toSprite.texture.width);
if(!string.IsNullOrEmpty(pixSizeProp))
mpb.SetFloat(pixSizeProp, 1f/toSprite.pixelsPerUnit);
renderer.SetPropertyBlock(mpb);
}
}
@Hammster
Copy link

The texture used needs to be a square, otherwise it will look like this ;)

disortion

@Babarzor
Copy link

Babarzor commented Oct 23, 2018

facinating, I don't understand anything but it works .. now I wonder how we do to modify the pixel/unit :-p (to have bigger pixels than screen
resolution...)

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