SOLVED! Link to solution
Godot Version
v4.5.1.stable.steam [f62fdbde1]
Question
I want my shader (a modified version of retr0_dev’s Earthbound battle background shader) to split my texture into clean, pixel-perfect rows. While the shader DOES split my texture into rows, the rows themselves aren’t pixel-perfect; the cuts don’t line up on a pixel grid.
Here’s an example image for clarification. The right image (with the tan lines) is the texture with the shader applied; notice how its rows don’t align with the left texture’s pixel perfect rows (the left texture has no shaders applied).
Ideally, the right texture’s rows should align with the left texture’s rows (i.e. the right texture’s rows would be pixel-perfect).
Here’s the relevant code snippet:
// In this example, transparent_lines is set to true.
// This code should split the texture into pixel-perfect rows. While the code does split the texture into rows, the rows aren't pixel-perfect.
if (transparent_lines) {
COLOR = mix(vec4(0.0), COLOR, float(int(UV.y * screen_height) % 2)); //float(int(UV.y * screen_height) % 2)
}
And, if needed, here’s the entire shader code:
/*
Earthbound battle backgrounds shader with scrolling effect and palette cycling like in the original game.
Original by @retr0_dev - https://godotshaders.com/shader/earthbound-like-battle-background-shader-w-scroll-effect-and-palette-cycling/
Apply the shader to a TextureRect or a Sprite. Use a texture with some shapes in a transparent background for best results.
You can then use a ColorRect or another method to paint the background.
You can use the shader on multiple TextureRects and obtain a double-buffer effect tweaking the values for each one, remember to Make Unique the shader material.
*/
shader_type canvas_item;
/**
Determines whether the background has transparent lines or not.
*/
uniform bool transparent_lines = false;
/**
The screen height of the viewport. Must be a whole number.
You can set this manually or dynamically using a .gd file with something similar to this: “material.set_shader_param(“screen_height”, get_viewport().size.y)”.
*/
uniform float screen_height = 960.0;
/**
How many lines you want the image to be split into. Must be a whole number.
Only used for interleaved oscillation.
*/
uniform float number_of_lines = 960;
/**
The direction of the infinite scrolling effect. Set this to (0, 0) to disable the effect.
*/
uniform vec2 scroll_direction = vec2(0.0, 0.0);
/**
The speed of the infinite scrolling effect.
*/
uniform float scrolling_speed = 0.08;
/**
Enables interleaved oscillation on the x-axis.
*/
uniform bool interleaved_oscillation = false;
/**
The amplitude of the oscillation effect.
*/
uniform vec2 amplitude = vec2(0.075, 0.0);
/**
The frequency of the oscillation effect.
*/
uniform vec2 frequency = vec2(10.0, 0.0);
/**
The speed of the oscillation effect.
*/
uniform vec2 speed = vec2(2.0, 0.0);
/**
Enables the palette cycling effect using a palette to change the color of a grayscale background based on a palette of colors, like in the original game with some backgrounds.
*/
uniform bool enable_palette_cycling = false;
/**
The gradient texture used for the palette cycling effect. The number of the palette colors must correspond with the grayscale of the base texture for best results.
*/
uniform sampler2D palette;
/**
The speed of the palette cycling.
*/
uniform float palette_speed = 0.1;
void fragment()
{
float diff_x = amplitude.x * sin((frequency.x * UV.y) + (speed.x * TIME));
float diff_y = amplitude.y * sin((frequency.y * UV.y) + (speed.y * TIME));
vec2 scroll = scroll_direction * TIME * scrolling_speed;
vec4 tex = texture(TEXTURE, vec2(UV.x + ((int(UV.y * screen_height) % 2) == 1 && interleaved_oscillation ? -diff_x : diff_x), UV.y + diff_y) + scroll);
/*if (interleaved_oscillation) { // float(int(UV.y) % 2) <- ts doesn't work...
tex = texture(TEXTURE, vec2(UV.x + (diff_x * float(int(UV.y * screen_height) % 2)), UV.y + diff_y) + scroll);
} else {
tex = texture(TEXTURE, vec2(UV.x + diff_x, UV.y + diff_y) + scroll);
}*/
float palette_swap = mod(tex.r - TIME * palette_speed, 1.0);
if (enable_palette_cycling)
{
COLOR = vec4(texture(palette, vec2(palette_swap, 0)).rgb, tex.a);
} else {
COLOR = tex;
}
if (transparent_lines) {
COLOR = mix(vec4(0.0), COLOR, float(int(UV.y * screen_height) % 2)); //float(int(UV.y * screen_height) % 2)
}
}
How do I modify my shader to split my texture into pixel-perfect rows?
