Triangular Pixelation

This was inspired by the Hex Pixelation shader at https://godotshaders.com/shader/hex-pixelization-shader/.

Pixelates the original texture into right-triangles.

Shader code
shader_type canvas_item;

/**
The number of pixels along the X and Y axes.
Also controls the size and aspect ratio of each pixel. 
For cleaner images, use whole, even numbers.
*/
uniform vec2 pixel_grid_size = vec2(128.0);
group_uniforms Offsets;
/**
If true, then every other column of pixels will be inverted.
For cleaner images, set when texture is vertically symmetrical.
*/
uniform bool offset_x = false;
/**
If true, then every other row of pixels will be inverted.
For cleaner images, set when texture is horizontally symmetrical.
*/
uniform bool offset_y = false;
/**
Reverses the direction of triangles.
*/
uniform bool inverted = false;


//All pixel squares are cut into 2 triangles using a diagonal cut.
//By default this creates a "top-left" and "bottom_right" triangle.
//This function determines if it will instead be cut into a "top-right" and "bottom-left" triangle.
bool get_offset(vec2 uv){
	vec2 grid_index = floor(uv * pixel_grid_size); //The grid index of the current pixel cell. Ex. (2, 3)
	float grid_total = dot(grid_index, vec2(float(offset_x), float(offset_y))); //The total value of the X and Y indexes based on if their respective uniforms are enabled.
	float offset_frequency = 2.0; //Every other row/column will be offset. You could change this for different patterns/effects.
	
	bool is_offset = mod(grid_total, offset_frequency) < 1.0; 
	is_offset = (is_offset != inverted); //Another way to write "if (inverted) {is_offset = !is_offset;}"
	
	return is_offset;
}


//Returns a normalized position within the local pixel cell that points to the center of the closest triangle.
//Top Left = vec2(1.0/3.0, 1.0/3.0)
//Top Right = vec2(2.0/3.0, 1.0/3.0)
//Bottom Left = vec2(1.0/3.0, 2.0/3.0)
//Bottom Right = vec2(2.0/3.0, 2.0/3.0)
vec2 get_triangle_center(vec2 uv, bool is_offset){
	
	vec2 triangle_center; 
	
	//Split square pixel into 2 triangles using a diagonal line and select which triangle to reference.
	if (is_offset){
		bool is_top_left = (uv.x + uv.y) <= 1.0;
		if (is_top_left) {
			//Top Left
			triangle_center = vec2(1.0/3.0, 1.0/3.0);
		}
		else{
			//Bottom Right
			triangle_center = vec2(2.0/3.0, 2.0/3.0);
		}
	}
	else{
		bool is_top_right = (uv.x >= uv.y);
		if (is_top_right) {
			//Top Right
			triangle_center = vec2(2.0/3.0, 1.0/3.0);
		}
		else{
			//Bottom Left
			triangle_center = vec2(1.0/3.0, 2.0/3.0);
		}
	}
	
	return triangle_center;
}


void fragment( )
{
	vec2 pixel_origin = floor(UV * pixel_grid_size) / pixel_grid_size; //Normalized position within the texture that points to the (0,0) position of the local pixel cell.
	vec2 pixel_uv = fract(UV * pixel_grid_size); //Normalized position within the local pixel cell.
	
	bool is_offset = get_offset(UV);
	vec2 triangle_center = get_triangle_center(pixel_uv, is_offset);
	vec2 triangle_uv = pixel_origin + (triangle_center / pixel_grid_size); //Normalized position within the texture that points to the triangle's center.
	
	//Apply triangle color.
	COLOR = texture(TEXTURE, triangle_uv);
}
Live Preview
Tags
diamond, pixel, pixelate, pixelation, pixelization, Pixelizer, triangle, Triangulation
The shader code and all code snippets in this post are under CC0 license and can be used freely without the author's permission. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

Related shaders

guest

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
binbun
11 days ago

Very cool. Love it!