Procedural Hex Barrier for Godot 4
First. This shader is an update of Procedural Hex Barrier Shader for Godot 4
There is some modifications that may be interesting:
- The number of global positions (objects interacting) is determied by the size of a vec3 array, not by code.
- The shader displays fine with non square meshes
- The entire hex grid can be visible even it’s far from any object
You can see comments in the shader.
GDScript code may look something like that:
@onready var barrier_mesh:MeshInstance3D = $BarrierMesh
var shader:ShaderMaterial
func _ready()->void :
var final_size = SildeHelpers.final_size(barrier_mesh)
shader = barrier_mesh.get_active_material(0)
shader.set_shader_parameter("width", final_size.x)
shader.set_shader_parameter("height", final_size.y)
func _process(delta: float) -> void :
# Beware, 64 must match (be equal or less) that poss array length defined in shader.
var poss = GameHandler.get_livings().map( func(liv:Living) : return liv.global_position ).slice(0, 64)
shader.set_shader_parameter("cant_poss", len(poss) )
shader.set_shader_parameter("poss", poss)
Shader code
/*
Original Wall Shield Shader by KINOMOTO Yui
Modified by Silderán for Godot 4.4
MIT License
*/
shader_type spatial;
render_mode unshaded, depth_draw_never, world_vertex_coords;
// set the width and height of the mesh. So que hexagons will be rendered fine.
uniform float width = 15.0;
uniform float height = 15.0;
// The densoty of hex on the barrier.
uniform float density = 5.0;
// Set it to false and the grid will only be visible along with background.
uniform bool hex_allways_visible = true;
uniform float line_speed = 0.5;
uniform float ripple_speed = 1.0;
uniform vec4 line_color : source_color = vec4( 0.2, 1.0, 1.0, 1.0 );
uniform vec4 ripple_color : source_color = vec4( 0.6, 0.7, 1.0, 0.7 );
uniform vec4 surface_color : source_color = vec4( 0.01, 0.18, 0.7, 0.4 );
// This must be set to the number of global positions set in the poss[] array in GDScript
uniform int cant_poss : hint_range(0, 64, 1);
// This is the vec3 array for the global possitions of the objects that will interact with the barrier.
// the length of the array must be harcoded. There os no option to set it dinamically
uniform vec3 poss[64];
varying vec3 world_vertex;
float hex_cells( vec2 uv )
{
float x = uv.x * width * density;
float y = mod( floor(x), 2.0 ) * 0.5 + ( uv.y * height ) * density;
vec2 base_chip = abs( vec2( 0.5 ) - mod( vec2( x, y ), 1.0 ) );
return abs( max( base_chip.x * 1.5 + base_chip.y, base_chip.y * 2.0 ) - 1.0 );
}
void vertex()
{
world_vertex = VERTEX;
}
void fragment( )
{
float hex = hex_cells( UV );
vec3 final_line_color = clamp( line_color.rgb + ( fract( length( UV * min(height, width) * 0.5 ) + TIME * line_speed ) * 2.0 - 1.0 ), vec3( 0.0 ), vec3( 1.0 ) );
float ripple = float( abs( hex - mod( -TIME * ripple_speed, 1.0 ) ) * 5.0 < 0.2 );
vec4 final = mix(
mix(
surface_color
, ripple_color
, ripple
)
, vec4( final_line_color, 1.0 )
, float( hex < 0.02 )
);
if( !hex_allways_visible || (hex > 0.01) )
{
float newAlpha = 0.0;
for( int i = min(cant_poss, poss.length())-1; i >= 0; i--)
{
float dist = length(world_vertex - poss[i]);
newAlpha = max(newAlpha, clamp(1.0 - dist * 0.3, 0.0, 1.0) * 1.3);
}
ALPHA = newAlpha;
}
ALBEDO = final.rgb;
}
