PS1 Shader

This is a shader trying to emulate the look of a PS1 game. The PS1 graphics pipeline took a lot of shortcuts, for example it used exclusively integers.

Simply apply it to any mesh. Best used with a texture with disabled filtering.


Jitter – The amount of polygon “jitter”, higher value means more intensive jittering.
Jitter Z Coordinate – If disabled, the Z axis (depth) of a vertex isn’t affected. Can avoid some clipping.
Jitter Depth Independent – If disabled, makes further objects jitter less, basically “scaling” the jitter with distance.
Affine Texture Mapping – If disabled, gets rid of the “weird floaty textures” effect at oblique angles. PS1 developers counteracted this by subdividing geometry, so you should too.

Shader code
shader_type spatial;
render_mode vertex_lighting, skip_vertex_transform, 
			specular_phong, diffuse_lambert_wrap;

uniform sampler2D albedo: hint_black_albedo;
uniform sampler2D specular: hint_black;
uniform sampler2D emission: hint_black;

uniform float jitter: hint_range(0.0, 1.0) = 0.5;
uniform bool jitter_z_coordinate = true;
uniform bool jitter_depth_independent = true;
uniform bool affine_texture_mapping = true;
uniform float alpha_scissor: hint_range(0.0, 1.0) = 1.0;

void vertex() {
	float z_orig = VERTEX.z;
	float i = (1.0 - jitter) * min(VIEWPORT_SIZE.x, VIEWPORT_SIZE.y) / 2.0;
	if (jitter_depth_independent) {
		float w = (PROJECTION_MATRIX * vec4(VERTEX, 1.0)).w;
		VERTEX = round(VERTEX / w * i) / i * w;
	} else {
		VERTEX = round(VERTEX * i) / i;
	if (!jitter_z_coordinate) {
		VERTEX.z = z_orig;

	if (affine_texture_mapping) {
		UV *= VERTEX.z;

void fragment() {
	vec2 uv = UV;
	if (affine_texture_mapping) {
		uv /= VERTEX.z;
	ALBEDO = texture(albedo, uv).rgb;
	ALPHA = texture(albedo, uv).a;
	ALPHA_SCISSOR = alpha_scissor;
	EMISSION = texture(emission, uv).rgb;
	SPECULAR = texture(specular, uv).r;
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

Mandelbrot Set

PS1 Post-processing

Related shaders

PS1 Post-processing

Procedural Marble Shader

3D simple animated flag shader


Newest Most Voted
Inline Feedbacks
View all comments
1 year ago

Do you plan to add UV scaling? Such as tiling a floor with a texture on repeat? (I just finished implementing this myself but was wondering if you had plans to make your own updates to further long this shader!)

Last edited 1 year ago by Nekuromu
10 months ago

A quick heads up, though the vertex effect is great it does NOT transform normals, they will remain in local space.


NORMAL = normalize((MODELVIEW_MATRIX * vec4(NORMAL, 0.0)).xyz);

into the vertex function to fix this

6 months ago

hey ive been trying to use this shader but its not tiling my textures so im not able to use this!