Shader to simulate depth changes when object tilts to the sides (pixel art)

Godot Version

v4.6.1.stable.mono.official [14d19694e]

Question

The idea - to avoid some objects looking flat, I want to implement a shader that makes one side brighter, and one side darker, which should create illusion of object tilting (example - plane with view from the top tilting to the left and right).

What makes things a little more complicated for me, is that in Godot one Sprite2D can have one shader. So I have to merge two shaders into one, since I also need hit flash functionality (this one is easy, plenty of premade shaders available on the internet).

This is what I have right now:

shader_type canvas_item;

uniform bool hit_enable = false;
uniform float flash_intensity : hint_range(0.0, 1.0) = 0.0;

uniform float tilt_max : hint_range(0.0, 1.0) = 0.3;
uniform float tilt_current : hint_range(-1.0, 1.0) = 0.0;
uniform int tilt_steps : hint_range(2, 8) = 3;
uniform bool tilt_horizontal = true;

void fragment() {
    vec4 original = COLOR;

    //tilt
    float axis = tilt_horizontal ? UV.x : UV.y;

    float steps = float(tilt_steps);
    float band = floor(axis * steps) / (steps - 1.0);
    float side = band - 0.5;

    float tilt_shift = tilt_current * tilt_max * side * 2.0;
    vec3 tilted = clamp(original.rgb + tilt_shift, 0.0, 1.0);

    //hit flash
    float intensity = flash_intensity * float(hit_enable) * original.a;
    vec3 final_rgb = mix(tilted, vec3(1.0), intensity);

    COLOR = vec4(final_rgb, original.a);
}

Hit flash part works. The tilting works perfectly in engine (one side brighter, one side darker, nice even colors if you set tilt_max properly), but not in actual game - when tilt_current is positive entire sprite gets brighter (right side is the brightest), when it’s negative entire sprite gets darker (left side is the brightest). Colors are also very oversaturated.

I admit I’m very bad at creating shaders. LLMs are probably even worse than me. So I’m in trouble right now, and I hope someone here knows where problem lies.

Try using this as a reference: Tilt-Shift Shader (minimal) - Godot Shaders

1 Like

I have one idea - I think that the shader applies the effect to entire atlas, not just active frame. The issues are:

  1. I have no idea how to fix it.
  2. It doesn’t explain oversaturation.

Use REGION_RECT to determine the UV range of the visible part of the atlas.

1 Like
    //remap UV into the active frame
    float local_u = (UV.x - REGION_RECT.x) / REGION_RECT.z;
    float local_v = (UV.y - REGION_RECT.y) / REGION_RECT.w;

    //tilt
    float axis = tilt_horizontal ? local_u : local_v;

This is what I’ve added, now it only edits active frame, also seems to have fixed oversaturation. I consider the issue solved, but if someone has some optimization ideas, feel free to reply. Thanks everyone for help.