Shaders in LD45, part 1

October 29, 2019 Bram 0 Comments

Recently I was involved in my second Ludum Dare entry “Goblin Keeper” which is a goblin civilisation building and sim game for the theme “you start with nothing”. After my recent escapades into shader language I was responsible for all our shader animations and effects and there was a fair few I wanted to show off. This was a very valuable way for me to solidify my skills having to get results under timed conditions.

https://ldjam.com/events/ludum-dare/45/goblin-keeper

The first most notable comparison to our last entry is the cohesive and; might I add gorgeous art. For this entry we had two new members of our Team, Masha as a full-time artist and Sam as an extra pair of programming hands. Masha really hit the ball out of the park with the assets she created.

the mess for goblins to eat in

The development of this title had a few notable lessons which will need to be taken on board for next time. Firstly, feature creep is a real problem, as our team doubled in size and we managed to achieve a lot in LD 44 we kept on adding features to our initial draft of the game. This was a problem as scaling management had overheads so double the people didn’t necessarily mean double the output. Additionally, two of us had work on the last day of the Jam which lost us a painful amount of development time.

The bobbing buildings

in an effort to make our aesthetic cutesier we wanted the houses to gently bob up and down over time which was a perfect problem for me to flex some shader muscles on. From the get-go I had the right idea of how to solve this problem, just stretch all the vertices on the y axis by a factor of the sin of the current time. However, making it actually have the right visual effect was some extra effort.

shader_type canvas_item;

void vertex(){
	if (VERTEX.y < 0.5)
		VERTEX.y += sin(TIME * 3.0) * 10.00;
	}
}

That’s it – A few areas of note within this shader. Checking if VERTEX.y is greater than 0.5 was figured out with a bit of fiddling, but that makes the stretch only apply to the area above the feet of the house. Without this line the whole house would move up and down over time. Multiplying the time value in the sin function by 3.0 speeds up the animation and multiplying the result by 10.0 increases the magnitude of the stretch.

bobbing house

The wooden arrow

This was my first ever foray into using masks for an effect. We wanted an arrow we could use to highlight selected items which Masha very kindly drew up:

The first thing this needed was the ability to bob up and down over time. my explanation for the bobbing building explains how straightforward that is. The difficult part was I wanted to push myself and get the leaves to gently blow in the wind.

This required me to create a mask, which i did by drawing over the leaves in Gimp. I then passed this texture in as a parameter to the shader

shader_type canvas_item;
uniform sampler2D mask_texture;

void fragment() {

 	vec4 base = texture(mask_texture, UV);
	if (base.a > 0.5){
	    float t = TIME * 2.0;
	    vec2 uv = UV;
	    float uv_x_deform = cos(uv.x);
	    vec2 offs_uv = vec2(cos(t + uv.y ) * 0.5 + sin(t + uv.x) * 0.5 , cos(t + uv.x)* 0.5+ sin(t + uv.y) * 0.5) * 0.01;

	    vec4 img = texture(TEXTURE, uv + vec2(offs_uv.x, offs_uv.y));
	    COLOR = img;
	}else{
		COLOR =texture(TEXTURE, UV);
	}
}

void vertex(){
	VERTEX.g += sin(TIME* 4.0)* 20.0;
}

The approach I took was to read in the mask texture, then check if the pixel had colour in the mask texture. If so, apply a regular deform to that pixels co-ordinates. I chose a convoluted deform to try and make the blowing over time not be too consistent, which I roughly put together with a little Googling. If the texture wasn’t covered by the mask, I just drew it normally. And that’s all you need to make the leaves act independently of the rest of the texture! the final vertex function is responsible for bobbing the texture up and down and that works in the same way as the bobbing houses.

The arrow just blowing and as the full bobbing effect

Noisy highlight

In addition to the arrow highlighting selected goblins I also wanted a marker around their feet as an added layer of confirmation. I tried to get a swirling misty circle to work for a long time, however rotating a load of noise looks very dissimilar from swirling mist, so I settled for a hazy circle of mist which I was happy with.

shader_type canvas_item;
uniform vec4 color: hint_color;

void fragment(){
	vec4 final_color = mix(color,texture(TEXTURE, UV + TIME * 0.01), 0.6);
	
	final_color.a = 0.6 - (distance(vec2(0.03,0.03), UV)/0.05);
	if( final_color.a < 0.0){
		final_color.a = 0.0;
	}
	COLOR = final_color;
}

Godot supports the generation of simplex noise, so I set that as the texture of a sprite below the goblins feet. Then I gave it some motion which is done in the line with the mix(). The tricky part was cropping the texture into a circle – I did this by subtracting the distance from the centre of the circle from the alpha channel as it passes a threshold, in this case 0.6. This caused some sever distortions as the alpha channel went negative so I the clamp the value so if it goes below zero it is set to zero. and that did the trick as shown below.

wrap up

Today is the last day of voting for Ludum dare so if you haven’t had a chance please do check out the title. I intend on doing another post with a few more shaders I worked on in the project and also a postmortem of what I learnt from the experience. stay tuned!

Leave a Reply:

Your email address will not be published. Required fields are marked *