Pixel Quantization
I’ve gotten a few questions about quantization the past few weeks, so this is the pixel quantization effect pulled from my dither shader, in case only this effect is needed. Works with both textures and screen reading. Unfortunately, GodotShaders doesn’t allow you to paste multiple files, so please pay attention to the comments.
To use:
- Add the .gdshaderinc portions to new shader include files.
- Add the .gdshader portion to a new shader file.
- Update the #include sections to match your filepaths.
- Use the ColorRect shader for ColorRects, and the Sprite2D shader for Sprite2Ds.
The uniform parameters are:
- Quantization
- Quantize Size: Pixel resolution scale (0 is bypass)
- Handle Scale: Determines how scaled images should display.
- Handle Subpixels: Auto-scales the quantize size when zoom is < 1, preventing artifacts.
Shader code
/*
* This should be your main shader file if using with a ColorRect.
*/
shader_type canvas_item;
// This file relies on a quantize shader include file, listed further down.
// The paths must match your file's location.
#include "res://shaders/quantize.gdshaderinc"
uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, repeat_disable, filter_nearest;
void vertex() {
g_q_size = getQuantizeSize(CANVAS_MATRIX);
g_model_matrix = MODEL_MATRIX;
g_world_to_clip = SCREEN_MATRIX * CANVAS_MATRIX;
g_vertex = VERTEX;
}
void fragment() {
COLOR = quantizeScreen(SCREEN_TEXTURE, SCREEN_UV, g_vertex);
}
/*
* This should be your main shader file if using with a Sprite2D.
*/
shader_type canvas_item;
// This file relies on a quantize shader include file, listed further down.
// The paths must match your file's location.
#include "res://shaders/quantize.gdshaderinc"
void vertex() {
g_q_size = getQuantizeSize(CANVAS_MATRIX);
g_model_matrix = MODEL_MATRIX;
g_texture_size = 1. / TEXTURE_PIXEL_SIZE;
g_vertex = VERTEX;
g_flat_vertex = VERTEX;
}
void fragment() {
COLOR = quantizeTexture(TEXTURE, UV);
}
/*
* This is the quantize shader-include file. Please make a copy in a
* separate file, and update the #include in the file you plan to reference it in.
*/
group_uniforms Quantization;
uniform float quantize_size : hint_range(0,100, 1.0) = 1;
uniform bool handle_scale;
uniform bool handle_subpixels = true;
group_uniforms;
varying mat4 g_model_matrix;
varying mat4 g_world_to_clip;
varying vec2 g_texture_size;
varying vec2 g_vertex;
varying flat vec2 g_flat_vertex;
varying float g_q_size;
float getQuantizeSize(mat4 canvas_matrix) {
vec2 g_zoom = vec2(length(canvas_matrix[0].xyz), length(canvas_matrix[1].xyz));
float q_size = quantize_size;
if (handle_subpixels && g_zoom.x < 1.) {
q_size = round(quantize_size * (1. / g_zoom.x));
}
return q_size;
}
vec4 quantizeTexture(sampler2D in_texture,vec2 in_uv) {
if (g_q_size == 0.) {
return texture(in_texture, in_uv);
}
float q_size = g_q_size;
// gets -1 if not flipped, 1 if flipped
vec2 flipped = sign(g_flat_vertex - g_vertex);
// gets the offset of the texture
// adds 1 when flipped
vec2 offset = g_flat_vertex / g_texture_size;
vec2 uv = in_uv;
// add offset so positioned back at 0,0 locally
// so grid lines up
uv *= flipped;
uv = offset - uv;
// scale to texture size
uv *= g_texture_size;
if (handle_scale) { // convert to world space
uv = (g_model_matrix * vec4(uv, 0, 1)).xy;
}
// quantize to specified pixel size
uv /= q_size;
uv = floor(uv) + 0.5;
uv *= q_size;
if (handle_scale) { // convert back to local space
uv = (inverse(g_model_matrix) * vec4(uv, 0, 1)).xy;
}
// normalize
uv /= g_texture_size;
// remove offset so pixel taken at correct location
uv = offset - uv;
uv *= flipped;
return texture(in_texture, uv);
}
vec4 quantizeScreen(sampler2D in_screen_texture, vec2 in_screen_uv, vec2 in_vertex) {
if (g_q_size == 0.) {
return texture(in_screen_texture, in_screen_uv);
}
vec2 uv = (g_model_matrix * vec4(in_vertex, 0, 1)).xy;
uv /= g_q_size;
uv = floor(uv) + 0.5;
uv *= g_q_size;
uv = (g_world_to_clip * vec4(uv, 0, 1)).xy;
uv = uv * 0.5 + 0.5;
return texture(in_screen_texture, uv);
}
it would be amazing to have this shader working on godot 3.x but for my it does’nt 🙁
Migrate