Broken Affine Mapping Shader

I’ve had a recent video during the development of my game where the affine shader for my PSX renderer broke after months of changes and stuff, and people actually said the effect looked neat for a horror/LSD trip thingy, so I separated it from the shader and added some sliders to tweak the values

Shader code
/*
    PSX-Style "Broken Affine" UV Warp

    This intentionally preserves the visually exaggerated old UV * clip_w
    distortion seen in my Twitter clip, while carrying both normal
    and warped UV coordinates so the effect can fade out safely 
    near the camera.

    Free to use, modify, and redistribute without attribution.
	- MR.SOLACE
*/

shader_type spatial;

render_mode
    blend_mix,
    depth_draw_opaque,
    cull_back,
    diffuse_burley,
    specular_schlick_ggx;

uniform sampler2D albedo_texture : source_color, filter_nearest, repeat_enable;
uniform vec4 albedo_color : source_color = vec4(1.0);

uniform vec2 uv_scale = vec2(1.0);
uniform vec2 uv_offset = vec2(0.0);

uniform bool enable_affine_warp = true;
uniform float affine_warp_strength : hint_range(0.0, 1.0, 0.01) = 0.2;

uniform bool enable_near_fade = true;
uniform float near_fade_start : hint_range(0.0, 10.0, 0.01) = 0.25;
uniform float near_fade_end : hint_range(0.0, 10.0, 0.01) = 1.0;

uniform float maximum_w_scale : hint_range(1.0, 1000.0, 0.1) = 1000.0;

varying vec2 perspective_uv;
varying vec2 broken_affine_uv;
varying float view_distance;


void vertex()
{
    vec4 view_position = MODELVIEW_MATRIX * vec4(VERTEX, 1.0);
    vec4 clip_position = PROJECTION_MATRIX * view_position;

    float clip_w = clip_position.w;
    float safe_sign = clip_w < 0.0 ? -1.0 : 1.0;
    float safe_w = abs(clip_w) < 0.0001
        ? 0.0001 * safe_sign
        : clip_w;

    safe_w = clamp(
        safe_w,
        -maximum_w_scale,
        maximum_w_scale
    );

    perspective_uv = UV;
    broken_affine_uv = UV * safe_w;
    view_distance = max(-view_position.z, 0.0);
}


void fragment()
{
    float strength = enable_affine_warp
        ? clamp(affine_warp_strength, 0.0, 1.0)
        : 0.0;

    if (enable_near_fade) {
        float fade_start = min(near_fade_start, near_fade_end);
        float fade_end = max(near_fade_start, near_fade_end);

        float distance_fade = smoothstep(
            fade_start,
            max(fade_end, fade_start + 0.0001),
            view_distance
        );

        strength *= distance_fade;
    }

    // Mixing the two already-interpolated varyings preserves the original
    // exaggerated effect while allowing it to fade cleanly near the camera.
    // You'll thank me later.
    vec2 final_uv = mix(
        perspective_uv,
        broken_affine_uv,
        strength
    );

    final_uv = final_uv * uv_scale + uv_offset;

    vec4 tex = texture(albedo_texture, final_uv);

    ALBEDO = tex.rgb * albedo_color.rgb;
}
Live Preview
Tags
acid, broken, disorienting, distortion, faulty, LSD, optical illusion, psx, retro, trip, trippy
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

0 Comments
Oldest
Newest Most Voted