Stylized Cartoon Grass
WHAT IS THIS?
Another grass shader. But prettier, optimized, and cartoon-looking
HOW TO SET THIS UP?!!
See the repository here, or download it here. Or see the plugin used here. Or follow the next instructions:
You need to set up 3 texture maps see [Screenshot 2] for an example:
- Grass Color. The color of the top of the grass. Looked from above
- Terrain Color. The color of the bottom of the grass. Looked from above
- Mask Front. The gradient from top-to-bottom color [Screenshot 1]
You can of course use NoiseTexture2D for the top and bottom, and GradientTexture2D for the frontal mask.
You also need up to 4 grass textures. Use the one in [Screenshot 3] for example. The rules to make your own grass texture are:
- Must be pure color white
- Use transparency
- Optionally, use black for extra details like a margin as in the preview images
Remember to use a MultimeshInstance3D to scatter your grass. Or, if you allow me, use my scatterer tool to paint beautiful scenes like the ones shown here: https://github.com/dip000/godot-landscaper
Anyway, let me know if something is broken or any thoughts, optimizations, etc… See ya!
Shader code
shader_type spatial;
render_mode unshaded, shadows_disabled, cull_disabled; //Use 'cull_back' if billboard Y
// Internally capped at 16
const int TOTAL_GRASS_VARIANTS = 4;
uniform bool enable_details = true;
uniform bool billboard_y = false;
uniform vec3 detail_color:source_color = vec3(0.2);
uniform vec2 world_size = vec2(10.0);
uniform vec2 world_position = vec2(0);
// Colors of all of the grass instanced from a MultiMesh as seen from the top
uniform sampler2D grass_color:source_color,filter_linear_mipmap,repeat_disable;
uniform sampler2D terrain_color:source_color,filter_linear_mipmap,repeat_disable;
// This must be in gray scale. Usually a GradientTexture2D but can be anything you want, even empty for plain color
uniform sampler2D gradient_mask:source_color,filter_linear_mipmap,repeat_disable,hint_default_black;
uniform sampler2D variants[TOTAL_GRASS_VARIANTS];
// 'instance' keyword is only for Vulkan rendering drivers and allows multiple grass variants with the same material
instance uniform int variant_index;
void vertex(){
// Wind sway
float root = (1.0 - UV.y);
vec3 sway;
sway.x = sin(NODE_POSITION_WORLD.x + TIME * 1.25 + UV.y) * root * 0.10;
sway.y = sin(NODE_POSITION_WORLD.x + TIME * 0.6 + UV.y) * root * 0.08;
sway.z = cos(NODE_POSITION_WORLD.z + TIME * 0.45 + UV.y) * root * 0.15;
if(billboard_y){
VERTEX += sway;
MODELVIEW_MATRIX = VIEW_MATRIX * mat4(vec4(normalize(cross(vec3(0.0, 1.0, 0.0), INV_VIEW_MATRIX[2].xyz)), 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(normalize(cross(INV_VIEW_MATRIX[0].xyz, vec3(0.0, 1.0, 0.0))), 0.0), MODEL_MATRIX[3]);
}
else{
VERTEX += (vec4(sway, 1.0) * MODEL_MATRIX).xyz;
}
// Vertex to world space (from center of texture)
vec2 world_space = world_position + (MODEL_MATRIX * vec4(VERTEX, 1.0)).xz / world_size;
// Coloring the mesh vertices will look exactly the same as coloring the pixels but more performant (asuming there are enough subdivisions along z-axis)
vec3 recolor_top = texture(grass_color, world_space).rgb;
vec3 recolor_root = texture(terrain_color, world_space).rgb;
float mask = texture(gradient_mask, UV).r;
// Mask the top of the grass with one color, mask the root with another, and add them
COLOR.rgb = recolor_top * mask;
COLOR.rgb += recolor_root * (1.0-mask);
}
void fragment() {
// Apply vertex color to albedo
ALBEDO = COLOR.rgb;
vec4 detail_mask = texture(variants[variant_index], UV);
// Details will look awfull if you try to vertex-color it, so is better to process it here
if(enable_details){
ALBEDO = mix(detail_color, ALBEDO, detail_mask.r);
}
// Enables alpha scissor
ALPHA = detail_mask.a;
ALPHA_SCISSOR_THRESHOLD = 0.8;
}
This is beautiful and I really want to be able to use it but I can’t seem to be able to move the area that it allows me to paint the grass in. I can create terrain within the default bounds but there’s no clear way to move the bounds or expand them which is severely limiting. I’m able to paint terrain within the bounds and then add grass to it and then drag the terrain to where I want it in my level but if I want to edit it at all once its outside of those default bounds, it disappears. I also don’t see any clear way to scale the grass. By default it’s too small for what I need. Again, fantastic work though. Very excited to see where this goes.
Hi, thank you for the feedback!
Expanding and moving the canvas area does sound like a good idea. I’ll add it to the future updates thanks!
Moving and rotating the terrain manually is not possible right now, definitely on the priority list!
For the grass size, there’s a property “size” under the “Grass Spawn” brush and what it does is essentially:
Update: Plug-in allows you to move the terrain and add as many terrains as you like. You can resize the canvas area and it will always move where the terrain is. Also has a custom instance scatterer for spawning trees rocks etc…
This looks wonderful but I’m using Godot 4.3 and I can’t seem to make this work, I tried installing the plugin and pretty much everything works except for the grass that doesn’t spawn, I’ve tried setting every external resource to the ones included in a way that seemed logical but nothing worked, some directions to help me understand what I’m missing would very much be appreciated 🙂
Hi sorry for taking days to respond.
For some reason, the SVG files were not loading correctly after the Godot 4.3 update.
textures were extracted, Inkscape was updated and SVG files were resaved so hopefully that fixes the grass shader demo and the plugin as well.
Thanks for letting me know though!