Yeah I use lerp/smoothstep to subtly blend between each step of the toon shader. Likewise, the cloud noise it not perfectly sharp, which helps with flickering. Good luck with the shader programming, it's fun to learn!
September 20, 2025 at 11:07 PM
Yeah I use lerp/smoothstep to subtly blend between each step of the toon shader. Likewise, the cloud noise it not perfectly sharp, which helps with flickering. Good luck with the shader programming, it's fun to learn!
I probably had the grass density too high, it can really be more sparse and still have the desired effect. The clouds are a global noise texture sampled in the light function with world space UVs (when LIGHT_IS_DIRECTIONAL) and used as attenuation for my custom toon shading.
September 19, 2025 at 11:25 PM
I probably had the grass density too high, it can really be more sparse and still have the desired effect. The clouds are a global noise texture sampled in the light function with world space UVs (when LIGHT_IS_DIRECTIONAL) and used as attenuation for my custom toon shading.
I don't know how Unity does rendering these days, but Godot uses forward rendering, so I just put my custom outline material on each object and it works. In the Water section of the article I have a paragraph about the depth/normals pre-pass, as that information is required for the outlines.
August 4, 2025 at 10:11 PM
I don't know how Unity does rendering these days, but Godot uses forward rendering, so I just put my custom outline material on each object and it works. In the Water section of the article I have a paragraph about the depth/normals pre-pass, as that information is required for the outlines.
You can either bake that information into the multimesh instance data or sample it from a texture. For my tree leaves, I sample positions/normals on a mesh and pass that into the multimesh. If you're doing procedural terrain grass, let's hope you have a heightmap to sample from.
July 24, 2025 at 10:47 PM
You can either bake that information into the multimesh instance data or sample it from a texture. For my tree leaves, I sample positions/normals on a mesh and pass that into the multimesh. If you're doing procedural terrain grass, let's hope you have a heightmap to sample from.
No problem. You'll need to make sure all your inputs to your lighting model are the same for grass and ground. I set LIGHT_VERTEX equal to the model origin (MODELVIEW_MATRIX[3].xyz) and NORMAL equal to ground/surface normal.
July 24, 2025 at 10:12 PM
No problem. You'll need to make sure all your inputs to your lighting model are the same for grass and ground. I set LIGHT_VERTEX equal to the model origin (MODELVIEW_MATRIX[3].xyz) and NORMAL equal to ground/surface normal.
Thanks, friend. Specifically for this style, it can be hard to add a sense of depth to the scene without it looking too 3D, which is why I spent much effort on the god-rays. Also, smooth shading can look odd, but sharp shadows can cause flickering, due to the low resolution; it's a balancing act.
June 9, 2025 at 10:04 AM
Thanks, friend. Specifically for this style, it can be hard to add a sense of depth to the scene without it looking too 3D, which is why I spent much effort on the god-rays. Also, smooth shading can look odd, but sharp shadows can cause flickering, due to the low resolution; it's a balancing act.
a point on the plane; I check the shadow attenuation at that point (using a custom Godot shader language function), coloring the fragment if lit; then ray march a few more times using a defined gap to create the layers of light.
May 25, 2025 at 5:54 AM
a point on the plane; I check the shadow attenuation at that point (using a custom Godot shader language function), coloring the fragment if lit; then ray march a few more times using a defined gap to create the layers of light.
I find it difficult to explain, but I'll give it a shot. I have a post-processing shader that ray marches into the scene; there is a mathematically defined plane in world space that is parallel to the sun direction; in view space, using the x/y coords of the current fragment, I solve for z to get...
May 25, 2025 at 5:54 AM
I find it difficult to explain, but I'll give it a shot. I have a post-processing shader that ray marches into the scene; there is a mathematically defined plane in world space that is parallel to the sun direction; in view space, using the x/y coords of the current fragment, I solve for z to get...
The red and green channels encode a vector pointing away from the centre of each cell. That way, my shader can extract the horizontal direction relative to the view, even when rotated. The blue channel is random per cell, used for timing offset of animation. Alpha channel is…
April 21, 2025 at 12:39 AM
The red and green channels encode a vector pointing away from the centre of each cell. That way, my shader can extract the horizontal direction relative to the view, even when rotated. The blue channel is random per cell, used for timing offset of animation. Alpha channel is…