Meter

Configurable meter.

9-7-2023: I have updated the shader to version 2. It has been changed slightly to work with Godot 4 by default but there are comments explaining how to use it with earlier versions of Godot.

15-1-2023: I have optimised the code by removing explicit if statements. I used some of the code snippets provided by nonunknown here: https://godotshaders.com/shader/optimize-your-shaders/

Shader code
//	Meter shader v2 by Brian Smith (steampunkdemon.itch.io)
//	MIT Licence

shader_type canvas_item;

// Replace the below references to source_color with hint_color if you are using a version of Godot before 4.
uniform vec4 indictor_color : source_color = vec4(0.0, 0.0, 0.0, 1.0);
uniform vec4 border_color : source_color = vec4(0.5, 0.5, 0.5, 1.0);
uniform vec4 centre_color : source_color = vec4(0.0, 0.0, 0.0, 1.0);
uniform vec4 region1_color : source_color = vec4(0.0, 1.0, 0.0, 1.0);
uniform vec4 region2_color : source_color = vec4(1.0, 1.0, 0.0, 1.0);
uniform vec4 region3_color : source_color = vec4(1.0, 0.0, 0.0, 1.0);
uniform vec4 scale_mark_color : source_color = vec4(0.0, 0.0, 0.0, 1.0);

uniform bool show_edges = false;
uniform bool bottom_border = true;
uniform float meter_start_angle : hint_range(0.0, 0.4) = 0.15;
uniform float indicator_angle : hint_range(0.0, 1.0) = 0.0;
uniform float indicator_length : hint_range(0.1, 1.0) = 0.6;
uniform float indicator_width : hint_range(0.001, 0.02) = 0.01;
uniform float border_width : hint_range(0.0, 0.5) = 0.05;
uniform float centre_width : hint_range(0.0, 0.5) = 0.1;
uniform float region1 : hint_range(0.0, 1.0) = 0.5;
uniform float region2 : hint_range(0.0, 1.0) = 0.75;
uniform float region3 : hint_range(0.0, 1.0) = 0.9;
uniform float regions_end : hint_range(0.0, 1.0) = 1.0;
uniform float scale_marks : hint_range(0.0, 20.0, 1.0) = 10.0;
uniform float major_scale_marks : hint_range(0.0, 20.0, 1.0) = 2.0;
uniform float scale_mark_width : hint_range(0.01, 0.05) = 0.03;
uniform float scale_minor_outer : hint_range(0.0, 1.0) = 0.75;
uniform float scale_major_outer : hint_range(0.0, 1.0) = 0.80;
uniform float scale_inner : hint_range(0.0, 1.0) = 0.65;

float greater_than(float x, float y) {
  return max(sign(x - y), 0.0);
}

void fragment() {
	vec2 uv = UV;
	uv.x = uv.x * 2.0 - 1.0;
	
//	If you do not want to render the border replace the following line of code with:
//	uv.y = uv.y - 1.0;
	uv.y = uv.y * (1.0 + border_width * float(bottom_border)) - 1.0;
	
	float scale_factor = 1.0 - meter_start_angle * 2.0;
	float adjusted_scale_mark_width = scale_mark_width / scale_factor;
	float a = ((atan(uv.y, uv.x) + 3.141592656) / 3.141592656 - meter_start_angle) / scale_factor;
	float l = length(uv);

//	Uncomment the following line if you are applying the shader to a TextureRect and using a version of Godot before 4.
//	COLOR = texture(TEXTURE,UV);

//	If you do not want to render all the colored regions remove the appropriate lines from the following block of code.
	COLOR.rgb = mix(COLOR.rgb, region3_color.rgb, region3_color.a * (greater_than(a, region3) * greater_than(regions_end, a)));
	COLOR.rgb = mix(COLOR.rgb, region2_color.rgb, region2_color.a * (greater_than(a, region2) * greater_than(region3, a)));
	COLOR.rgb = mix(COLOR.rgb, region1_color.rgb, region1_color.a * (greater_than(a, region1) * greater_than(region2, a)));

//	If you do not want to render the scale marks remove the following code block.
//	If you do not want to render the major scale marks remove the second following line.
	COLOR.rgb = mix(COLOR.rgb, scale_mark_color.rgb, scale_mark_color.a * greater_than(a, 0.0 - scale_mark_width) * greater_than(1.0 + scale_mark_width, a) * greater_than(abs(mod(a, 1.0 / scale_marks) * scale_marks * 2.0 - 1.0), 1.0 - (adjusted_scale_mark_width / 6.283185312 / l) * scale_marks) * (greater_than(scale_minor_outer, l) * greater_than(l, scale_inner)));
	COLOR.rgb = mix(COLOR.rgb, scale_mark_color.rgb, scale_mark_color.a * greater_than(a, 0.0 - scale_mark_width) * greater_than(1.0 + scale_mark_width, a) * greater_than(abs(mod(a, 1.0 / major_scale_marks) * major_scale_marks * 2.0 - 1.0), 1.0 - (adjusted_scale_mark_width / 6.283185312 / l) * major_scale_marks) * (greater_than(scale_major_outer, l) * greater_than(l, scale_minor_outer)));

	COLOR.rgb = mix(COLOR.rgb, indictor_color.rgb, indictor_color.a * greater_than(indicator_length, l) * greater_than(indicator_width / scale_factor / l, abs(indicator_angle - a)));
	
//	If you do not want to render the centre remove the following line.
	COLOR.rgb = mix(COLOR.rgb, centre_color.rgb, centre_color.a * greater_than(centre_width, l));

//	If you do not want to render the border remove the following line.
	COLOR.rgb = mix(COLOR.rgb, border_color.rgb, border_color.a * min(greater_than(l, 1.0 - border_width) + greater_than(uv.y, 0.0), 1.0));

//	If you do not want the edges to be transparent remove the following line of code.
//	If you always want the edges to be transparent replace the following line of code with:
//	COLOR.a *= greater_than(1.0, l);
	COLOR.a *= max(sign(1.0 - l), float(show_edges));
}
Tags
meter
The shader code and all code snippets in this post are under MIT license and can be used freely. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

More from Steampunkdemon

Analogue clock face

Simple Rainbow

Dial

Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments