These may well be of use to others so I thought I’d get them into a serviceable state and do a mini-tutorial on their usage. OK, maybe ‘tutorial’ is too grand a word but I’ve commented the code thoroughly at least! Links to the HLSL source files for these shaders are included at the bottom of this article (scroll down).
I’m assuming the reader has a basic knowledge of HLSL – if not then there’s an excellent introductory tutorial here.
The shaders provided both draw a user-defined number of concentric shapes. The stroke width and spacing between the shapes can be set via user-defined parameters, as can the amount the spacing and stroke width increases at each iteration.
A parameter ‘multiply_increments’ allows the user to set whether the spacing/stroke width increment as applied linearly (by addition) or exponentially (by multiplication).
The supplied texture is used to draw the shapes (I often use a 2×2 white square), a user-defined tint can be applied to this.
All sizes, widths etc are calculated as a proportion of the texture size so usually between 0.0f and 1.0f though you can go larger than 1.0f if you wish some of your outer shape to be drawn outside of the texture (and therefore cropped).
Setting the shader parameters from your .net code would look something like the code below. Adjust these parameters over time to get the kind of trippy effects you see in some of the example GIFs. Maybe you could smooth these parameter changes using LERPing?

Two Geometric Shaders Overlaid
// The tint that will be applied to the texture – set all values
// to 1.0 to leave the texture untouched
Microsoft.Xna.Framework.Vector4 tint;
tint.W = 1.0f; // alpha – 0.0f – 1.0f
tint.X = 1.0f; // red – 0.0f – 1.0f
tint.Y = 1.0f; // green – 0.0f – 1.0f
tint.Z = 1.0f; // blue – 0.0f – 1.0f
shader.Parameters [“tint”].SetValue(tint);
// The size of the first shape to be drawn
shader.Parameters [“size”].SetValue ( 1.0f );
// The stroke width of the first shape to be drawn
shader.Parameters [“strokewidth”].SetValue ( 0.1f );
// The initial spacing between shapes
shader.Parameters [“spacing”].SetValue ( 0.1f );
// The number of shapes
shader.Parameters [“repeats”].SetValue ( 3 );
// The amount by which spacing increases for each consecutive shape drawn
shader.Parameters [“spacing_increment”].SetValue ( 0.0f );
// The amount by which stroke width increases for each consecutive shape drawn
shader.Parameters [“strokewidth_increment”].SetValue ( 0.0f );
// Whether the spacing/stroke width increment as applied linearly (by addition)
// or exponentially (by multiplication).
shader.Parameters [“multiply_increments”].SetValue ( false );
// Adjust depending on how you’re doing your rendering
SpriteBatch.Begin (…);
shader.CurrentTechnique.Passes[0].Apply ();
SpriteBatch.End (…);
The code below shows some example values – don’t try and cut/paste this as it uses my own tweening classes and a wrapper class for the shader itself. It should be good enough to get an idea of how to set things up though…
float width = 0.0025f;
// My wrapper class for the shader
shader = GeometryShader.CircleShader ();
// Used by my wrapper class – the size I’m drawing the texture on screen
shader.ScaleX = 506;
shader.ScaleY = 506;
// Set up initial spacing and stroke width for the shader
shader.Spacing = width;
shader.StrokeWidth = width;
// Spacing and stroke width will increase by 50% for each concentric shape drawn
shader.SpacingIncrement = 1.5f;
shader.StrokeWidthIncrement = 1.5f;
shader.MultiplyIncrements = true;
// Sets up the values to tween the size of the outer shape over a 30 frame seamless loop
// First two values are the start and end size
shader.TweenSize = new Tween (1.0f, 1.0f + shader.Spacing/shader.SpacingIncrement + shader.StrokeWidth/shader.StrokeWidthIncrement, 30, Tween.Linear);
// Sets up the values to tween the spacing over a 30 frame seamless loop
// First two values are the start and end spacing
shader.TweenSpacing = new Tween (width, width / shader.SpacingIncrement, 30, Tween.Linear);
// Sets up the values to tween the stroke width over a 30 frame seamless loop
// First two values are the start and end stroke width
shader.TweenStrokeWidth = new Tween (width, width / shader.StrokeWidthIncrement, 30, Tween.Linear);
I have plans to add more shape types at a later stage and combine these into one uber-shader that also also shapes to be combined in different ways. Watch this blog for updates…
If this is of use to you I’d welcome more followers on Twitter.
Dev Time: 2 days
Total Dev Time: approx 123 days

Two Circle Shaders Slightly Offset

Square Shader With Additional Rotation Applied