Fractal noise scene transition

This is a follow-up shader for https://godotshaders.com/shader/pixelated-warped-fractal-noise/.

This shader takes the whole code of the pixelated warped fractal noise and applies it from top left corner to bottom right corner based on “progress” uniform variable.

I’m using this shader for transition animation when switching scenes. I made it so the effect covers the entire screen at value progress=0.5, giving the ability to clear the old scene and load a new one in the background. After the new scene is loaded, the effect can be progressed from 0.5 -> 1.0 to fully dissapate.

Here’s the code snippet for a “PersistentScene” autoload signleton that I use to play the animation. The transition effect is a ColorRect (with ShaderMaterial) attached as a child to persistent_foreground_scene.tscn, stretched to fullscreen and has a unique name %TransitionEffect.

extends Control

@export var _persistent_foreground_scene : PackedScene = preload("res://scenes/persistent_foreground_scene.tscn")

var _foreground_canvas : CanvasLayer
var _foreground_scene : Control

var _transition_effect : ColorRect
var _transition_tween : Tween

func _ready():
	get_tree().scene_changed.connect(_scene_changed_callback)

	_foreground_canvas = CanvasLayer.new()
	_foreground_canvas.layer = 1000
	add_child(_foreground_canvas)
	_foreground_scene = _persistent_foreground_scene.instantiate()
	_foreground_canvas.add_child(_foreground_scene)

	_transition_effect = _foreground_scene.get_node_or_null("%TransitionEffect")
	if _transition_effect:
		_transition_effect.set_visible(false)


var _transition_effect_parameter_call = func(value : float):
	_transition_effect.material.set_shader_parameter(
		"progress",
		value
	)
	_transition_effect.material.set_shader_parameter(
		"background_threshold",
		abs(1.0 - value*2.0) - 0.5
	)
	_transition_effect.material.set_shader_parameter(
		"color_threshold",
		min(1.0,abs(-4.0+value*8.0)) * 0.48
	)


func change_scene(scene_path : String):
	if _transition_effect == null:
		push_warning("Transition effect not found.")
		get_tree().change_scene_to_file(scene_path)
		return
	
	if _transition_tween != null:
		_transition_tween.kill()
		_transition_tween = null
	
	_transition_effect.material.set_shader_parameter("seed",randf())

	_transition_effect.set_visible(true)
	_transition_tween = create_tween()
	_transition_tween.tween_method(_transition_effect_parameter_call, 0.0, 0.5, 0.5)
	_transition_tween.tween_callback(get_tree().change_scene_to_file.bind(scene_path))


func _scene_changed_callback():
	if _transition_tween != null:
		_transition_tween.kill()
		_transition_tween = null
		
	_transition_tween = create_tween()
	_transition_tween.tween_method(_transition_effect_parameter_call, 0.5, 1.0, 0.5)
	_transition_tween.tween_callback(_transition_effect.set_visible.bind(false))
Shader code
// Pixelated noise transition effect based on https://godotshaders.com/shader/warped-fractal-noise/
//
// Copyright Gerardo Montaño 2025
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of 
// this software and associated documentation files (the “Software”), to deal in 
// the Software without restriction, including without limitation the rights to 
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
// of the Software, and to permit persons to whom the Software is furnished to do 
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all 
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
// SOFTWARE.

shader_type canvas_item;

uniform float progress = 0.0;
uniform float speed = 0.1; 

uniform vec2 pixelation = vec2(2.0, 2.0);
uniform float zoom = 2.0;

uniform float background_threshold : hint_range(-2.0, 1.0) = 0.0;
uniform float color_threshold : hint_range(0.0, 1.0)  = 0.24;

uniform vec4 color : source_color = vec4(0.0, 0.0, 0.0, 1.0); 

uniform float seed = 0.0;

#define iTime (TIME * speed - seed)

const mat2 mtx = mat2( vec2(0.80, -0.60), vec2(0.60, 0.80) );

float rand(vec2 n) { 
    return fract(sin(dot(n, vec2(12.9898 + seed, 4.1414 - seed))) * (43758.5453 + seed * 1000.0));
}

float noise(vec2 p){
    vec2 ip = floor(p);
    vec2 u = fract(p);
    u = u * u * (3.0 - 2.0 * u);

    float res = mix(
        mix(rand(ip), rand(ip + vec2(1.0, 0.0)), u.x),
        mix(rand(ip + vec2(0.0, 1.0)), rand(ip + vec2(1.0, 1.0)), u.x), u.y);
        
    return res * res;
}

float fbm( vec2 p )
{
    float f = 0.0;
    
    f += 0.500000 * noise( p + iTime ); p = mtx * p * 2.02;
    f += 0.031250 * noise( p ); p = mtx * p * 2.01;
    f += 0.250000 * noise( p ); p = mtx * p * 2.03;
    f += 0.125000 * noise( p ); p = mtx * p * 2.01;
    f += 0.062500 * noise( p ); p = mtx * p * 2.04;
    f += 0.015625 * noise( p + sin(iTime) );

    return f / 0.96875;
}

float pattern( in vec2 p )
{
	return fbm( p + fbm( p + fbm( p ) ) );
}

vec4 colormap(float x, vec2 uv) {
	
	x *= max(0.0, min(-abs(progress * 4.0 - uv.x - uv.y - 1.0) + 1.0, 1.0) * 2.0);
    
    if (x < background_threshold) { 
        return vec4(0.0, 0.0, 0.0, 0.0);
    }
    else if (x < color_threshold) { 
        return mix(
			vec4(0.0, 0.0, 0.0, 0.0),
			color,
			round((x - background_threshold) / (color_threshold - background_threshold))
		);
    }
	else {
		return color;
	}
}

void fragment()
{
	vec2 modifier = 1.0/(SCREEN_PIXEL_SIZE * pixelation);
	vec2 uv = floor(UV * modifier) / modifier;
	float shade = pattern(uv * zoom);
	COLOR = colormap(shade, uv);
}
Live Preview
Tags
2d, Abstract, animated, background, canvas, canvasitem, fbm, flow, fractal, godotshader, noise, Procedural, warped
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 shadecore_dev

Related shaders

guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments