0 votes

How would I go about creating a toon shader/canvas item material?

I have a Sprite node with a diffuse texture an a normal map. Since I'm using pixel art, it would look so much better this way.

I'll take any help, this is really important to me.

asked Jan 9 in Engine by dejvid_bejlej (32 points)

1 Answer

0 votes

If you don't know anything about shader, review the godot manual, then you can go to pages like shadertoy and convert the shader you like.

Few things change in language, for example in shadertoy and the screen resolution is expressed as iResolution and in godot it is (1.0 / SCREENPIXELSIZE).

I leave an example of this shader: https://www.shadertoy.com/view/XlSSRW
Look at its code and compare how it becomes godot:

shader_type canvas_item;
uniform float nColors =4.0;

vec3 lerp(vec3 colorone, vec3 colortwo, float value)
    return (colorone + value*(colortwo-colorone));

vec3 RGBToHSV( vec3 RGB ){

    vec4 k = vec4(0.0, -1.0/3.0, 2.0/3.0, -1.0);
    vec4 p = RGB.g < RGB.b ? vec4(RGB.b, RGB.g, k.w, k.z) : vec4(RGB.gb, k.xy);
    vec4 q = RGB.r < p.x   ? vec4(p.x, p.y, p.w, RGB.r) : vec4(RGB.r, p.yzx);
    float d = q.x - min(q.w, q.y);
    float e = 1.0e-10;
    return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);

vec3 HSVToRGB( vec3 HSV ){

    vec4 k = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
    vec3 p = abs(fract(HSV.xxx + k.xyz) * 6.0 - k.www);
    return HSV.z * lerp(k.xxx, clamp(p - k.xxx, 0.0, 1.0), HSV.y);

void fragment()
    float vx_offset = 0.5;
    //vec2 uv = FRAGCOORD.xy / (1.0/SCREEN_PIXEL_SIZE);
    vec2 uv=UV;   
    vec3 tc = texture(TEXTURE, uv).rgb;
    vec2 coord = vec2(0.,0.);

    float cutColor = 1./nColors;

    if(uv.x < (vx_offset-0.001))

        tc = RGBToHSV(tc);

        vec2 target_c = cutColor*floor(tc.gb/cutColor);

        tc = HSVToRGB(vec3(tc.r,target_c));
    else if (uv.x>=(vx_offset+0.01))

        tc  = cutColor*floor(tc/cutColor);

    if(tc.g > (tc.r + tc.b)*0.7)
        //tc.rgb = vec3(0.2,0.2,0.2);

    COLOR = vec4(tc, 1.0);


To assign it to a sprite, for example, in the sprite options go to material, new material shader, edit, shader: new shader, edit, and paste the code in the shader editor.

answered Jan 9 by estebanmolca (1,203 points)

Thanks for the reply!

Yeah, I don't know anything about shading language, that's why I tried using visual editor.

I'm trying to get the shadows using Light2D and a Sprite with normal maps. Sprite textures have transparent pixels. I've pasted your code and this is what I got:
enter image description here

In comparison, this is what I got so far using visual editor (the light source is in the top right):
enter image description here

So, yeah. I'm trying to make it work like that, but the shadow is too intense and I don't know how to reduce it. Also, the shadow gets darker the closer the light source is.

I know it's hard to follow what I'm trying to achieve because I don't really know much about shaders.
Bottom line is - I want the Light2D to cast cell shadows, not smooth shadows on a Sprite with a normal map.

Thanks for your answer, I'll keep trying to make it work.

Sorry, for reading fast I got confused, I thought you meant the ShaderMaterial but this is referred to the CanvasItemMaterial. I will also see how your CanvasItemMaterial behaves in godot

No worries at all, I'm thankful for any help

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.