Breakable Glass

Shader code
shader_type canvas_item;

render_mode blend_mix;

//////////////////////////////////////////////////////////
// SCREEN
//////////////////////////////////////////////////////////

uniform sampler2D screen_tex :
hint_screen_texture,
filter_linear_mipmap;

//////////////////////////////////////////////////////////
// MAIN
//////////////////////////////////////////////////////////

uniform float break_progress :
hint_range(0.0, 1.0) = 0.0;

uniform vec2 impact_point =
vec2(0.5, 0.5);

//////////////////////////////////////////////////////////
// GLASS MASK SHAPE
//////////////////////////////////////////////////////////

uniform bool use_glass_mask = true;

uniform bool glass_mask_circle = true;

uniform vec2 glass_mask_scale =
vec2(0.35, 0.35);

uniform vec2 glass_mask_position =
vec2(0.5, 0.5);

uniform float glass_mask_rotation :
hint_range(-180.0, 180.0) = 0.0;

uniform float glass_mask_softness :
hint_range(0.0, 0.5) = 0.02;

//////////////////////////////////////////////////////////
// IMPACT SHAPE
//////////////////////////////////////////////////////////

uniform bool use_circle_impact = true;

uniform vec2 impact_shape_scale =
vec2(1.0, 1.0);

uniform float impact_rotation :
hint_range(-180.0, 180.0) = 0.0;

//////////////////////////////////////////////////////////
// SHARDS
//////////////////////////////////////////////////////////

uniform int pieces_x = 12;
uniform int pieces_y = 8;

uniform float point_jitter :
hint_range(0.0, 0.48) = 0.34;

uniform float shard_scatter :
hint_range(0.0, 2.0) = 0.35;

uniform float gravity :
hint_range(0.0, 6.0) = 2.4;

uniform float rotation_amount :
hint_range(0.0, 8.0) = 2.0;

uniform float delay_variation :
hint_range(0.0, 1.0) = 0.35;

//////////////////////////////////////////////////////////
// CRACKS
//////////////////////////////////////////////////////////

uniform float crack_width :
hint_range(0.0001, 0.03) = 0.002;

uniform float crack_brightness :
hint_range(0.0, 5.0) = 1.5;

uniform float crack_density :
hint_range(0.0, 3.0) = 1.0;

uniform vec4 crack_color :
source_color =
vec4(1.0,1.0,1.0,1.0);

//////////////////////////////////////////////////////////
// GLASS
//////////////////////////////////////////////////////////

uniform vec4 glass_tint :
source_color =
vec4(0.75,0.9,1.0,0.15);

uniform float transparency :
hint_range(0.0,1.0) = 0.15;

//////////////////////////////////////////////////////////
// HOLES
//////////////////////////////////////////////////////////

uniform float center_hole_size :
hint_range(0.0,0.5) = 0.08;

uniform float hole_irregularity :
hint_range(0.0,1.0) = 0.4;

//////////////////////////////////////////////////////////
// FX
//////////////////////////////////////////////////////////

uniform float refraction :
hint_range(0.0,0.1) = 0.015;

uniform float chromatic :
hint_range(0.0,0.05) = 0.003;

uniform float shake :
hint_range(0.0,0.1) = 0.008;

uniform bool pixelated = false;

uniform float pixel_size :
hint_range(1.0,256.0) = 4.0;

//////////////////////////////////////////////////////////

const int SEARCH_RADIUS = 1;

//////////////////////////////////////////////////////////
// HASH
//////////////////////////////////////////////////////////

float hash12(vec2 p) {

	vec3 p3 =
	fract(vec3(p.xyx) * 0.1031);

	p3 += dot(p3, p3.yzx + 33.33);

	return fract(
		(p3.x + p3.y)
		* p3.z
	);
}

vec2 hash22(vec2 p) {

	return vec2(
		hash12(p + vec2(1.23,4.56)),
		hash12(p + vec2(7.89,0.12))
	);
}

//////////////////////////////////////////////////////////
// ROT
//////////////////////////////////////////////////////////

mat2 rot(float a) {

	float s = sin(a);
	float c = cos(a);

	return mat2(
		vec2(c,-s),
		vec2(s,c)
	);
}

//////////////////////////////////////////////////////////
// NOISE
//////////////////////////////////////////////////////////

float noise(vec2 p){

	vec2 i = floor(p);
	vec2 f = fract(p);

	float a = hash12(i);
	float b = hash12(i + vec2(1.0,0.0));
	float c = hash12(i + vec2(0.0,1.0));
	float d = hash12(i + vec2(1.0,1.0));

	vec2 u =
	f*f*(3.0-2.0*f);

	return mix(a,b,u.x)
	+ (c-a)*u.y*(1.0-u.x)
	+ (d-b)*u.x*u.y;
}

//////////////////////////////////////////////////////////
// CELL POINT
//////////////////////////////////////////////////////////

vec2 cell_point(vec2 cell_id) {

	vec2 h = hash22(cell_id);

	return cell_id
	+ 0.5
	+ (h - 0.5)
	* (point_jitter * 2.0);
}

//////////////////////////////////////////////////////////
// VORONOI
//////////////////////////////////////////////////////////

void voronoi_info(
	vec2 p,
	out vec2 owner_cell,
	out vec2 owner_point,
	out float edge_dist
){

	vec2 base = floor(p);

	float best_d = 1e20;
	float second_d = 1e20;

	vec2 best_cell = vec2(0.0);
	vec2 best_point = vec2(0.0);

	for(int j=-SEARCH_RADIUS;j<=SEARCH_RADIUS;j++){

		for(int i=-SEARCH_RADIUS;i<=SEARCH_RADIUS;i++){

			vec2 c =
			base + vec2(float(i),float(j));

			vec2 pt =
			cell_point(c);

			float d =
			distance(p,pt);

			if(d < best_d){

				second_d = best_d;
				best_d = d;

				best_cell = c;
				best_point = pt;

			}else if(d < second_d){

				second_d = d;
			}
		}
	}

	owner_cell = best_cell;
	owner_point = best_point;

	edge_dist =
	second_d - best_d;
}

//////////////////////////////////////////////////////////
// GLASS MASK
//////////////////////////////////////////////////////////

float glass_mask(vec2 uv){

	vec2 local_uv =
	uv - glass_mask_position;

	float rot_rad =
	radians(glass_mask_rotation);

	local_uv =
	rot(rot_rad) * local_uv;

	local_uv /= glass_mask_scale;

	float dist;

	if(glass_mask_circle){

		dist = length(local_uv);

	}else{

		vec2 d = abs(local_uv);

		dist = max(d.x, d.y);
	}

	return 1.0 - smoothstep(
		1.0 - glass_mask_softness,
		1.0,
		dist
	);
}

//////////////////////////////////////////////////////////
// SHARD TRANSFORM
//////////////////////////////////////////////////////////

void piece_transform(

	vec2 piece_cell,

	out float t,
	out vec2 piece_offset_uv,
	out float piece_angle

){

	float rnd =
	hash12(piece_cell);

	float rnd2 =
	hash12(piece_cell + 17.37);

	float rnd3 =
	hash12(piece_cell + 91.11);

	vec2 grid =
	vec2(
		float(pieces_x),
		float(pieces_y)
	);

	vec2 piece_uv =
	(piece_cell + 0.5) / grid;

	float impact_dist =
	distance(
		piece_uv,
		impact_point
	);

	float radial_delay =
	impact_dist * delay_variation;

	float delay =
	rnd * 0.2
	+ radial_delay;

	t = clamp(
		(break_progress - delay)
		/ max(0.0001,1.0-delay),
		0.0,
		1.0
	);

	vec2 explode_dir =
	normalize(
		piece_uv
		- impact_point
	);

	float explode_force =
	(1.0 - impact_dist);

	explode_force =
	max(explode_force,0.0);

	float drift_x =
	explode_dir.x
	* shard_scatter
	* t
	* explode_force;

	float drift_y =
	explode_dir.y
	* shard_scatter
	* 0.35
	* t
	* explode_force;

	float fall_y =
	gravity
	* t
	* t
	* (0.3 + rnd2);

	piece_offset_uv =
	vec2(
		drift_x,
		drift_y + fall_y
	);

	piece_angle =
	(rnd - 0.5)
	* rotation_amount
	* t
	* explode_force;
}

//////////////////////////////////////////////////////////
// MAIN
//////////////////////////////////////////////////////////

void fragment() {

	vec2 uv = UV;

	//////////////////////////////////////////////////////
	// PIXEL
	//////////////////////////////////////////////////////

	if(pixelated){

		uv =
		floor(uv * pixel_size)
		/ pixel_size;
	}

	//////////////////////////////////////////////////////
	// SHAKE
	//////////////////////////////////////////////////////

	uv += vec2(
		sin(TIME*120.0 + uv.y*40.0),
		cos(TIME*90.0 + uv.x*50.0)
	) * shake * break_progress;

	//////////////////////////////////////////////////////
	// FRACTURE SPACE
	//////////////////////////////////////////////////////

	vec2 grid =
	vec2(
		float(pieces_x),
		float(pieces_y)
	);

	vec2 p_now =
	uv * grid;

	//////////////////////////////////////////////////////
	// CURRENT SHARD
	//////////////////////////////////////////////////////

	vec2 now_cell;
	vec2 now_point;

	float now_edge;

	voronoi_info(
		p_now,
		now_cell,
		now_point,
		now_edge
	);

	//////////////////////////////////////////////////////
	// TRANSFORM
	//////////////////////////////////////////////////////

	float t;

	vec2 piece_offset_uv;

	float piece_angle;

	piece_transform(
		now_cell,
		t,
		piece_offset_uv,
		piece_angle
	);

	//////////////////////////////////////////////////////
	// SHARD CENTER
	//////////////////////////////////////////////////////

	vec2 piece_center_uv =
	now_point / grid;

	//////////////////////////////////////////////////////
	// REVERSE TRANSFORM
	//////////////////////////////////////////////////////

	vec2 rel_now =
	uv - piece_center_uv;

	vec2 uv_from =
	piece_center_uv
	+ rot(-piece_angle)
	* (rel_now - piece_offset_uv);

	//////////////////////////////////////////////////////
	// SCREEN MASK
	//////////////////////////////////////////////////////

	float inside_screen =

	step(0.0, uv_from.x)
	*
	step(0.0, uv_from.y)
	*
	step(uv_from.x,1.0)
	*
	step(uv_from.y,1.0);

	vec2 safe_uv =
	clamp(
		uv_from,
		vec2(0.0),
		vec2(1.0)
	);

	//////////////////////////////////////////////////////
	// ORIGINAL SHARD
	//////////////////////////////////////////////////////

	vec2 p_from =
	safe_uv * grid;

	vec2 from_cell;
	vec2 from_point;

	float from_edge;

	voronoi_info(
		p_from,
		from_cell,
		from_point,
		from_edge
	);

	float same_piece =
	1.0
	- step(
		0.001,
		distance(
			from_cell,
			now_cell
		)
	);

	//////////////////////////////////////////////////////
	// IMPACT SHAPE
	//////////////////////////////////////////////////////

	vec2 local_uv =
	uv - impact_point;

	float rot_rad =
	radians(impact_rotation);

	local_uv =
	rot(rot_rad) * local_uv;

	local_uv /= impact_shape_scale;

	float impact_dist;

	if(use_circle_impact){

		impact_dist =
		length(local_uv);

	}else{

		vec2 d = abs(local_uv);

		impact_dist =
		max(d.x, d.y);
	}

	//////////////////////////////////////////////////////
	// REFRACTION
	//////////////////////////////////////////////////////

	vec2 refract_dir =
	(normalize(
		uv - impact_point
	) * refraction);

	vec2 refract_uv =
	SCREEN_UV
	+ refract_dir
	* t;

	//////////////////////////////////////////////////////
	// CHROMATIC
	//////////////////////////////////////////////////////

	float r =
	texture(
		screen_tex,
		refract_uv
		+ vec2(chromatic,0.0)
	).r;

	float g =
	texture(
		screen_tex,
		refract_uv
	).g;

	float b =
	texture(
		screen_tex,
		refract_uv
		- vec2(chromatic,0.0)
	).b;

	vec4 col =
	texture(
		screen_tex,
		SCREEN_UV
	);

	col.rgb = vec3(r,g,b);

	//////////////////////////////////////////////////////
	// GLASS TINT
	//////////////////////////////////////////////////////

	col.rgb =
	mix(
		col.rgb,
		glass_tint.rgb,
		transparency
	);

	//////////////////////////////////////////////////////
	// CRACK EDGES
	//////////////////////////////////////////////////////

	float edge =
	1.0
	- smoothstep(
		0.0,
		crack_width,
		now_edge
	);

	//////////////////////////////////////////////////////
	// RADIAL CRACKS
	//////////////////////////////////////////////////////

	float radial =
	abs(
		sin(
			atan(
				uv.y - impact_point.y,
				uv.x - impact_point.x
			)
			* 30.0
		)
	);

	radial =
	pow(radial, 24.0);

	float radial_fade =
	smoothstep(
		1.0,
		0.0,
		impact_dist
	);

	float crack_mask =
	radial
	* radial_fade
	* break_progress
	* crack_density;

	//////////////////////////////////////////////////////
	// COMBINE CRACKS
	//////////////////////////////////////////////////////

	float cracks =
	max(edge, crack_mask);

	col.rgb +=
	crack_color.rgb
	* cracks
	* crack_brightness;

	//////////////////////////////////////////////////////
	// CENTER HOLE
	//////////////////////////////////////////////////////

	float hole_noise =
	noise(uv * 40.0);

	float hole =
	smoothstep(
		center_hole_size
		+ hole_noise
		* hole_irregularity
		* 0.05,

		0.0,

		impact_dist
	);

	hole *=
	smoothstep(
		0.3,
		0.8,
		break_progress
	);

	//////////////////////////////////////////////////////
	// ALPHA
	//////////////////////////////////////////////////////

	col.a *= inside_screen;
	col.a *= same_piece;
	col.a *= (1.0 - hole);

	//////////////////////////////////////////////////////
	// GLASS MASK
	//////////////////////////////////////////////////////

	if(use_glass_mask){

		float mask =
		glass_mask(uv);

		col.a *= mask;
	}

	//////////////////////////////////////////////////////
	// FINAL
	//////////////////////////////////////////////////////

	COLOR = col;
}
Live Preview
Tags
glass
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 Dep Emily

Related shaders

guest

0 Comments
Oldest
Newest Most Voted