Simple, cheap stylized tree shader

I was trying to recreate a simplified version of a stylized tree shader someone made in Unity:

Aafter trying to use a rotation matrix based on rodrigues rotation formula based on the vertex’s UV coordinates, I realised some of my code was creating issues. I took it out and the shader was still working, and realising that the rotation matrix was taking in values that were basically 0.0’s I took the matrix out and it still worked. Discovered that I was taking UV coordinates as if they were viewspace values and converting them to model space.

I doubt I was the first person to realise you could do this, but for my first shader that I programmed myself, I’m very happy with the results. I hope you may find some use of this technique/shader as well.

I have uploaded the texture I used as a ‘screenshot’ if you would like to use it. I dont know how uploading might change the image, but it was just a 256*256 PNG. the effect would probably work a lot better with a cleaner image with no anti-aliasing.

I plan to expand the shader to make use of a normal map to give the leaves depth, and to change that normalmap and rotate the ‘billboards’ in accordance with a wind system compute shader I’m working on.

Make sure the mesh youre applying this to is made of quads, and what the UV is unwrapped so that each of those quads use the entirety of UV space (so each vertex has a UV coordinate of both X and Y equal to either 0 or 1)

Shader code
shader_type spatial ;

render_mode depth_draw_always, alpha_to_coverage ;

uniform sampler2D foliage_texture ;
uniform vec3 foliage_colour : source_color = vec3(0.13, 0.33, 0.25) ;

void vertex()
{	
    NORMAL = -NORMAL ;
    // Generate the 'billboard' 2D coordinates from UV coordinates, shift it to center over UV 0,0.
    vec2 viewspace_offset = UV.xy - vec2(0.5) ; 
	//pretend the coordinates are in viewspace and pass them into inverse(MODELVIEW_MATRIX) to cheat our way into a billboard effect
	vec4 modelspace_offset = inverse(MODELVIEW_MATRIX) * vec4(viewspace_offset.xy, 0.0, 0.0) ;
	
    VERTEX += modelspace_offset.xyz ;
}

void fragment()
{
    ALBEDO = foliage_colour ;
    ALPHA = texture(foliage_texture, UV).g ;
}
Tags
billboard, bush, cheap, foliage, leaves, simple, stylized, tree
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

Cheap water shader

Cheap caustics

Cheap terrain with fake normal map or POM

Subscribe
Notify of
guest

3 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
niceOnline
8 months ago

hey!

Could you upload a super simple demo project? I tried the shader out, with the setup described, and it gives me very different results on Godot 4.1.1

I uploaded a barebones project to github of how I had it setup, the assets I used, and the results.

Would be cool to get the results in your screenshots with so few GPU calculations!

https://github.com/niceandgoodonline/simple-cheap-stylized-tree-shader-issue-demo/tree/main

niceOnline
8 months ago
Reply to  J Hell

Cheers on the quick turn around!

Having a scale uniform is how I’ve seen other implementations of this handle varying base mesh sizes, and also resizing the mesh in editor.

Additionally, with default alpha settings and this technique as the camera gets further away from the model/shader it becomes less and less visible. You can counteract this by setting ALPHA_SCISSOR_THRESHOLD to a value lower than 0.5 (or use ALPHA_HASH_SCALE, if your game has post-effects or an aesthetic that’s ok with how this looks).

With the scissor threshold, the closer to 0 the more “fluffy” the leaves look up close, and the further away you can see them.

Not sure if you’ve seen it, but there is a pretty complex version of this technique available here

https://github.com/FaRu85/Godot-Foliage

it’s what I use for my LOD0 trees and bushes currently