PS1 Post-processing

This shader is meant to be used with the PS1 Shader. It gives your game that PS1 dithered look. Works in editor, too!

Make a MeshInstance, give it a QuadMesh, make the size 2 by 2, set the Extra Cull Margin to the highest possible value, apply a material with this shader to it.

Known issues:
Doesn’t support transparent objects.

Color Depth – Reduce color depth to X bits per color. The PS1 supported many modes, some of them being 24 bit (8 bits per color) and 15 bit (5 bits per color), the latter (5 bits per color) used in majority of 3D games and being the default.
Dithering – Apply the “dotted” look that gives an illusion of more colors.
Resolution Scale – Reduce screen resolution.

Shader code
shader_type spatial;
render_mode unshaded, shadows_disabled, depth_test_disable, depth_draw_never;

uniform int color_depth : hint_range(1, 8) = 5;
uniform bool dithering = true;
uniform int resolution_scale = 4;

int dithering_pattern(ivec2 fragcoord) {
	const int pattern[] = {
		-4, +0, -3, +1, 
		+2, -2, +3, -1, 
		-3, +1, -4, +0, 
		+3, -1, +2, -2
	int x = fragcoord.x % 4;
	int y = fragcoord.y % 4;
	return pattern[y * 4 + x];

void vertex() {
	POSITION = vec4(VERTEX, 1.0);

void fragment() {
	ivec2 uv = ivec2(FRAGCOORD.xy / float(resolution_scale));
	vec3 color = texelFetch(SCREEN_TEXTURE, uv * resolution_scale, 0).rgb;
	// Convert from [0.0, 1.0] range to [0, 255] range
	ivec3 c = ivec3(round(color * 255.0));
	// Apply the dithering pattern
	if (dithering) {
		c += ivec3(dithering_pattern(uv));
	// Truncate from 8 bits to color_depth bits
	c >>= (8 - color_depth);

	// Convert back to [0.0, 1.0] range
	ALBEDO = vec3(c) / float(1 << color_depth);
ps1, retro
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.

More from Mighty Duke

PS1 Shader

Mandelbrot Set

Related shaders

PS1 Shader

Post Effect Outline Shader for GLES2

Post Effect Outline Shader


Newest Most Voted
Inline Feedbacks
View all comments
1 year ago

Awesome shader! One problem though, it doesn’t support transparency at all. Transparent objects disappear at certain angles and are not affected by the reduced resolution and dithering.

Last edited 1 year ago by Zorochase
1 year ago

It works, but I’m not convinced 8 bit color is the mode used by most PS1 games, least of all Metal Gear Solid.

  • Mode 4: 4-bit CLUT (16 colors)
  • Mode 8: 8-bit CLUT (256 colors)
  • Mode 15: 15-bit direct (32,768 colors)
  • Mode 24: 24-bit (16,777,216 colors)

I suspect Mode 15 was the most common.

Transparency could work with with this if it was suface shader rather than a post process shader.

Here is someone else’s attempt at it – it has many problems of its own, which I’ve been trying to fix, but it does support transparency.

1 year ago

any chance of a GLES2 compatible version? it’s kinda weird to use a higher-quality renderer to make my graphics look worse

1 year ago

Wait, this isn’t a canvasitem shader…

8 months ago
Reply to  Exuin

Changed the category to Spatial. Better late than never 🙂

9 months ago

I managed to get transparent objects (and shadows) working by converting this into a canvas item shader as per here. Conversion’s pretty painless: change the shader_type, comment out the render_mode and vertex function and switch SCREEN_TEXTURE for TEXTURE. Then plonk the material on a ViewportContainer. Tada.

The Viewport will need to have matching Shadow Atlas size for shadows to show up properly, but it does work!

comment image

Only downside is it no longer works in Editor.

Last edited 9 months ago by Guessy
4 months ago
Reply to  Guessy

What did you change the albedo line near the end to? Albedo doesn’t exist on canvasitem shaders and I can’t for the life of me figure out what i’m meant to put there instead.

EDIT: Found it. Change ALBEDO to COLOR.rgb

Last edited 4 months ago by Lemin
3 months ago
Reply to  Lemin

thanks you legend

1 month ago

Not sure if anyone else has made this mistake, but be sure to resize the quad mesh by clicking the mesh preview window and change the size to 2. Don’t change the size in the transform menu, otherwise only a small portion of the center of the viewport will be affected by the post-processing.

1 month ago

can you do a gles 2 version? Please!