Shaders are cool, dynamic crosshairs too. So how about we use some shader stuff to make dynamic crosshairs like the one below.
If you can't see the above shader try using a desktop browser.
I'll be using plain old glsl in my code snippets here, feel free to port it to any other shading language out there.
If you want to try it out right in your browser check out book of shaders editor.
The Book of Shaders is also an excellent resource if you want to learn more about shaders.
Shout out to glslCanvas.js.
It is what is being used to render the shaders on my blog.
The basic idea of creating shapes in a fragment shader is to make a mask using shader functions that fills the crosshair shape you want, and then animate this mask using time or another uniform.
You can create multiple simple masks and then put them together to make composite masks. You can sometimes get away with texture masks instead of creating them by shader code. But the beauty of anything made with a shader are that they can be scaled arbitrarily without loss in quality. Finally this mask can be multiplied with a color to get your final crosshair.
Here are a few simple masks that can be used to make more complex masks and how they look.
// circle mask
float mask_circle(vec2 st, vec2 center, float radius) {
return 1.0 - smoothstep(radius - SMOOTH_AMOUNT,
radius + SMOOTH_AMOUNT,
length(st - center));
}
// elliptical mask
float mask_ellipse(vec2 st, vec2 center, float r1, float r2) {
st -= center;
float d = st.x * st.x / (r1 * r1) + st.y * st.y / (r2 * r2);
return 1.0 - smoothstep(1.0 - 10.0 * SMOOTH_AMOUNT,
1.0 + 10.0 * SMOOTH_AMOUNT, d);
}
// ring mask
float mask_ring(vec2 st, vec2 center, float in, float out) {
return (1.0 - mask_circle(st, center, in)) *
mask_circle(st, center, out);
}
// plus mask
float mask_plus(vec2 st, vec2 center, float width) {
return 1.0 - min(
smoothstep(width - SMOOTH_AMOUNT,
width + SMOOTH_AMOUNT, abs(st.x)),
smoothstep(width - SMOOTH_AMOUNT,
width + SMOOTH_AMOUNT, abs(st.y))
);
}
// square mask
float mask_square(vec2 st, vec2 center, float width) {
return 1.0 - max(
smoothstep(width - SMOOTH_AMOUNT,
width + SMOOTH_AMOUNT, abs(st.x)),
smoothstep(width - SMOOTH_AMOUNT,
width + SMOOTH_AMOUNT, abs(st.y))
);
}
|
|
|
|
|
|
You can see the extensive use of simple shader functions like
smoothstep
, min
, max
, and abs
.
The mask_plus
works by doing a union of a vertical and horizontal strip to form a plus.
The mask_square
works in the exact opposite way, it uses the intersection of the vertical and horizontal strip to form a square.
The mask_ring
works by using two mask_circle
calls and cutting out the inner circle from the outer circle.
You can see now how you can combine multiple masks, this can be generalised similar to set theory!!?
// Mask Arithmetic? WTF
mask = 1.0 - mask // inverse of mask
// union and intersection using max, min
mask = max(mask1, mask2) // mask1 union mask2
mask = min(mask1, mask2) // mask1 intersection mask2
// union and intersection using addition, multiplication
mask = clamp(0.0, 1.0, mask1 + mask2) // mask1 union mask2
mask = mask1 * mask2 // mask1 intersection mask2
// here intersection can be any of the methods shown above
mask = mask1 intersection (1.0 - mask2) // mask1 set-subtract mask2
Who knows, maybe more of the boolean algebra works on these? Maybe de-morgans laws. An idea for another post perhaps.
Another trick to move your masks is transforming the uvs before passing them into the masks. You can do stuff like translating, rotating and scaling, the masks.
|
|
|
These are the glsl functions that transform the uv space.
// transform functions go BRRRRR
vec2 translate(vec2 uv, vec2 t) {
return uv + t;
}
vec2 scale(vec2 uv, vec2 s) {
return uv / s;
}
// rotate about mid
vec2 rotate(vec2 uv, float rotation, vec2 mid) {
return vec2(
cos(rotation) * (uv.x - mid.x) +
sin(rotation) * (uv.y - mid.y) + mid.x,
cos(rotation) * (uv.y - mid.y) -
sin(rotation) * (uv.x - mid.x) + mid.y
);
}
Here are a few more crosshairs and fun shaders to look at.
TLDR: masks and transformations, Half life, Needler, Halo 5's boltshot reticule, Regular crosshair