Doom Screen Melt Effect

A version of the Screen melt effect from Doom that plays as you start a level.

Values do need to be set by an outside script for the shader to work correctly.

This example code I used to achieve a similar effect to Doom. Creating a duplicate texture of the screen to overlay as menus swap, then melting away that duplicate texture with this shader.

extends ColorRect

var melting := false
var timer := 0.0 //Incremented by melt_speed then applied to the timer variable in the shader

@export var x_resolution := 100.0 //Value must be greater or equal to y_offsets.length() in the shader
@export var max_offset := 2.0
@export var melt_speed := 0.02


# Called when the node enters the scene tree for the first time.
func _ready():
	hide()


# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(_delta):
	if melting:
		timer += melt_speed
		self.material.set_shader_parameter("timer", timer)
	elif Input.is_action_just_pressed("Dev_Log"):
		generate_offsets()

# Call this before transitioning, creates a copy of the screen texture so changes
# can be made underneath before melting to show the new screen.
func generate_offsets():
	var offsets = []
	for i in x_resolution:
		offsets.append(randf_range(1.0, max_offset))
	self.material.set_shader_parameter("y_offsets", offsets)
	
	var img = get_viewport().get_texture().get_image()
	var tex = ImageTexture.create_from_image(img)
	self.material.set_shader_parameter("melt_tex", tex)
	
	show()

# Call this after generate_offsets
func transition():
	self.material.set_shader_parameter("melting", true)
	melting = true
Shader code
shader_type canvas_item;

//Incremented by outside script to move effect
uniform float timer = 0.0; 

//Array size determines how many vertical strips appear
uniform float[64] y_offsets; 

//Texture to melt away, example above uses a duplicate screen texture as a transition
uniform sampler2D melt_tex; 

//Controls whether the effect can play
uniform bool melting = false;

void fragment() {
	vec2 tex_uv = SCREEN_UV;
	if (melting)
	{
		float index = tex_uv.x * float(y_offsets.length());
		tex_uv.y -= timer * y_offsets[int(index)];
		
		if (tex_uv.y < 0.0 || tex_uv.y > 1.0) discard;
	}
	
	COLOR = texture(melt_tex, tex_uv);
}
Tags
doom, fragment, Melt, Melting, transition
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

Pixel Melt

Screen Noise Effect Shader

Rain drops on screen – notexture

Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments