lygia
/draw
/arrows
)Draw arrows for vector fields from https://www.shadertoy.com/view/4s23DG
Dependencies:
Use:
<float> arrows(<vec2> position, <vec2> velocity [, <vec2> resolution] )
// #ifndef ARROWS_LINE_STYLE
// #define ARROWS_LINE_STYLE
// #endif
#ifndef ARROWS_TILE_SIZE
#define ARROWS_TILE_SIZE 32.0
#endif
#ifndef ARROWS_HEAD_ANGLE
#define ARROWS_HEAD_ANGLE 0.5
#endif
// Used for ARROWS_LINE_STYLE
#ifndef ARROWS_HEAD_LENGTH
#define ARROWS_HEAD_LENGTH ARROWS_TILE_SIZE/5.0
#endif
#ifndef ARROWS_SHAFT_THICKNESS
#define ARROWS_SHAFT_THICKNESS 2.0
#endif
#ifndef FNC_ARROWS
#define FNC_ARROWS
// Computes the center pixel of the tile containing pixel pos
vec2 arrowsTileCenterCoord(vec2 pos) {
return (floor(pos / ARROWS_TILE_SIZE) + 0.5) * ARROWS_TILE_SIZE;
}
// v = field sampled at tileCenterCoord(p), scaled by the length
// desired in pixels for arrows
// Returns 1.0 where there is an arrow pixel.
float arrows(vec2 p, vec2 v, vec2 resolution) {
p *= resolution;
// Make everything relative to the center, which may be fractional
p -= arrowsTileCenterCoord(p);
float mag_v = length(v);
float mag_p = length(p);
if (mag_v > 0.0) {
// Non-zero velocity case
vec2 dir_v = v / mag_v;
// We can't draw arrows larger than the tile radius, so clamp magnitude.
// Enforce a minimum length to help see direction
mag_v = clamp(mag_v, 5.0, ARROWS_TILE_SIZE / 2.0);
// Arrow tip location
v = dir_v * mag_v;
#if defined(ARROWS_STYLE_LINE)
// Signed distance from shaft
float shaft = lineSDF(p, v, -v);
// Signed distance from head
float head = min( lineSDF(p, v, 0.4*v + 0.2*vec2(-v.y, v.x)),
lineSDF(p, v, 0.4*v + 0.2*vec2(v.y, -v.x)));
return step(min(shaft, head), 1.);
#elif defined(ARROWS_STYLE_LINE_TRIANGLE)
// Line arrow style
return saturate(1.0 +
max( ARROWS_SHAFT_THICKNESS / 4.0 -
max(abs(dot(p, vec2(dir_v.y, -dir_v.x))), // Width
abs(dot(p, dir_v)) - mag_v + ARROWS_HEAD_LENGTH / 2.0), // Length
// Arrow head
min(0.0,
dot(v - p, dir_v) - cos(ARROWS_HEAD_ANGLE / 2.0) * length(v - p)) * 2.0 + // Front sides
min(0.0,
dot(p, dir_v) + ARROWS_HEAD_LENGTH - mag_v) ) ); // Back
#else
// V arrow style
return saturate(1.0 +
// min(0.0, mag_v - mag_p) * 2.0 + // length
min(0.0, dot(normalize(v - p), dir_v) - cos(ARROWS_HEAD_ANGLE / 2.0)) * 2.0 * length(v - p) + // head sides
min(0.0, dot(p, dir_v) + 1.0) + // head back
min(0.0, cos(ARROWS_HEAD_ANGLE / 2.0) - dot(normalize(v * 0.33 - p), dir_v)) * mag_v * 0.8 ); // cutout
#endif
}
return 0.0;
}
float arrows(vec2 p, vec2 v) { return arrows(p, v, vec2(1.0)); }
#endif
Dependencies:
Use:
<float> arrows(<float2> position, <float2> velocity [, <float2> resolution] )
// #ifndef ARROWS_LINE_STYLE
// #define ARROWS_LINE_STYLE
// #endif
#ifndef ARROWS_TILE_SIZE
#define ARROWS_TILE_SIZE 32.0
#endif
#ifndef ARROWS_HEAD_ANGLE
#define ARROWS_HEAD_ANGLE 0.5
#endif
// Used for ARROWS_LINE_STYLE
#ifndef ARROWS_HEAD_LENGTH
#define ARROWS_HEAD_LENGTH ARROWS_TILE_SIZE/5.0
#endif
#ifndef ARROWS_SHAFT_THICKNESS
#define ARROWS_SHAFT_THICKNESS 2.0
#endif
#ifndef FNC_ARROWS
#define FNC_ARROWS
// Computes the center pixel of the tile containing pixel pos
float2 arrowsTileCenterCoord(float2 pos) {
return (floor(pos / ARROWS_TILE_SIZE) + 0.5) * ARROWS_TILE_SIZE;
}
// v = field sampled at tileCenterCoord(p), scaled by the length
// desired pixels for arrows
// Returns 1.0 where there is an arrow pixel.
float arrows(float2 p, float2 v, float2 resolution) {
p *= resolution;
// Make everything relative to the center, which may be fractional
p -= arrowsTileCenterCoord(p);
float mag_v = length(v);
float mag_p = length(p);
if (mag_v > 0.0) {
// Non-zero velocity case
float2 dir_v = v / mag_v;
// We can't draw arrows larger than the tile radius, so clamp magnitude.
// Enforce a minimum length to help see direction
mag_v = clamp(mag_v, 5.0, ARROWS_TILE_SIZE / 2.0);
// Arrow tip location
v = dir_v * mag_v;
#if defined(ARROWS_STYLE_LINE)
// Signed distance from shaft
float shaft = lineSDF(p, v, -v);
// Signed distance from head
float head = min( lineSDF(p, v, 0.4*v + 0.2*float2(-v.y, v.x)),
lineSDF(p, v, 0.4*v + 0.2*float2(v.y, -v.x)));
return step(min(shaft, head), 1.);
#elif defined(ARROWS_STYLE_LINE_TRIANGLE)
// Line arrow style
return saturate(1.0 +
max( ARROWS_SHAFT_THICKNESS / 4.0 -
max(abs(dot(p, float2(dir_v.y, -dir_v.x))), // Width
abs(dot(p, dir_v)) - mag_v + ARROWS_HEAD_LENGTH / 2.0), // Length
// Arrow head
min(0.0,
dot(v - p, dir_v) - cos(ARROWS_HEAD_ANGLE / 2.0) * length(v - p)) * 2.0 + // Front sides
min(0.0,
dot(p, dir_v) + ARROWS_HEAD_LENGTH - mag_v) ) ); // Back
#else
// V arrow style
return saturate(1.0 +
// min(0.0, mag_v - mag_p) * 2.0 + // length
min(0.0, dot(normalize(v - p), dir_v) - cos(ARROWS_HEAD_ANGLE / 2.0)) * 2.0 * length(v - p) + // head sides
min(0.0, dot(p, dir_v) + 1.0) + // head back
min(0.0, cos(ARROWS_HEAD_ANGLE / 2.0) - dot(normalize(v * 0.33 - p), dir_v)) * mag_v * 0.8 ); // cutout
#endif
}
return 0.0;
}
float arrows(float2 p, float2 v) { return arrows(p, v, float2(1.0)); }
#endif
MIT License (MIT) Copyright 2014, Morgan McGuire
LYGIA is dual-licensed under the Prosperity License and the Patron License for sponsors and contributors.
Sponsors and contributors are automatically added to the Patron License and they can ignore the any non-commercial rule of the Prosperity Licensed software (please take a look to the exception).
It's also possible to get a permanent comercial license hook to a single and specific version of LYGIA.
Sign up for the news letter bellow, joing the LYGIA's channel on Discord or follow the Github repository