Single SDF hex outline overlay

A shader that draws a single hex outline as an overlay, designed to create borders for a multimesh of hexagonal prisms. This was a learning project so may contain errors but I’ve thrown some reference links and comments to help everyone follow along.

 

References:

https://www.shadertoy.com/view/MsVBWt

https://andrewhungblog.wordpress.com/2018/07/28/shader-art-tutorial-hexagonal-grids/

https://inspirnathan.com/posts/173-interactive-hexagon-grid-tutorial-part-4/

Shader code
/**   
A shader that draws a single hex outline as an overlay, designed to create borders for a multimesh of hexagonal prisms. This was a learning project so could have errors!

References:
https://www.shadertoy.com/view/MsVBWt
https://andrewhungblog.wordpress.com/2018/07/28/shader-art-tutorial-hexagonal-grids/
https://inspirnathan.com/posts/173-interactive-hexagon-grid-tutorial-part-4/

By Paul Chamberlain, contact@arkem.org - MIT License
*/

shader_type spatial;

/** Size of the hex relative to the entire surface */
uniform float hex_size : hint_range(0.0, 0.7, 0.05) = 0.5;
/** Scale positions to account for non-regular hexagons */
uniform vec2 hex_surface_aspect_ratio = vec2(1.0, 1.0);
/** Shift the position of the hexagon */
uniform vec2 hex_offset = vec2(0.0, 0.0);
/** Color that's applied on top of the vertex COLOR (or custom color) */
uniform vec3 tint_color : source_color = vec3(0.0, 0.0, 0.0);
/** Tint intensity value (mixes between COLOR and tint_color) */
uniform float tint_intensity : hint_range(0.0, 1.0) = 1.0;
/** Threshold used for "distance to hex edge" to start drawing the hex */
uniform float threshold : hint_range(0.0, 0.1, 0.01) = 0.01;
/** Modifier to threshold used to finish drawing the hex */
uniform float width : hint_range(0.0, 0.1, 0.01) = 0.03;
/** Only draw hexes facing "up", this value controls the maximum slope allowed */
uniform float min_normal_y : hint_range(0.0, 1.0, 0.1) = 0.75;
/** Pointy-top hexagon versus flat-top hexagon */
uniform bool point_top = true;

varying vec3 local_position; // used instead of UV to be independent of texture usage
varying vec3 local_normal; // used to limit hexagons to "top" faces

/** SDF that defines the shape of a hexagon */
float hex_distance(vec2 p) {
	vec2 abs_p = abs(p);
	vec2 s = point_top ? vec2(1.0, 1.7320508) : vec2(1.7320508, 1.0); // sqrt(3)
	float limit = point_top ? abs_p.x : abs_p.y;
	return max(dot(abs_p, s*.5), limit) - hex_size;
}

void vertex() {
	/** Save vertex data in a "varying" variable so the local/model space value will be available and be interpolated for each fragment */
	local_position = VERTEX;
	local_normal = NORMAL;
}

void fragment() {
	vec2 hex_coords = vec2(local_position.x * hex_surface_aspect_ratio.x, local_position.z * hex_surface_aspect_ratio.y);
	hex_coords += hex_offset;
	float hex_edge_distance = hex_distance(hex_coords);
	float is_eligible = step(min_normal_y, local_normal.y); // slope/facing test
	ALBEDO = COLOR.rgb * mix(COLOR.rgb, tint_color, tint_intensity); // lerp between base color and tint (vertex COLOR or custom color)
	ALPHA = min(is_eligible, step(threshold, hex_edge_distance) - step(threshold + width, hex_edge_distance)); // draw a line
}
Live Preview
Tags
hex, hexagon, multimesh, overlay, SDF
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.

Related shaders

guest

0 Comments
Oldest
Newest Most Voted