Toon Shader (WIP)

This is still a WIP…

…and don’t ask about the mushroom headgear on the AIs, I know it’s weird. Just testing node attachments there :laughing:

nice, even shadow have a lines border )
did you use screen normal buffer for this freestyle lines effect ?

Maybe it will be useful
wiki.unity3d.com/index.php/TeamFortress2Shader

Maybe it will be useful
it’s very interesting)
I try to figure out with this little bit, a made some simplest test with toon.
actually in this picture below I use only diffuse texture (diff + ao) + ramp ramp texture from wiki TF topic. And rim color falls (from world pos) from - sky as emissive color

crappy shader (only for testing purpose) litSolidToon.glsl pastebin.com/gbMLBacG

[quote=“codingmonkey”]nice, even shadow have a lines border )
did you use screen normal buffer for this freestyle lines effect ?[/quote]

Thanks. :slight_smile: This was some older code that I was talking about on previous posts. It uses Sobel filters for edge detection.

[quote=“codingmonkey”]>Maybe it will be useful
it’s very interesting)
I try to figure out with this little bit, a made some simplest test with toon.
actually in this picture below I use only diffuse texture (diff + ao) + ramp ramp texture from wiki TF topic. And rim color falls (from world pos) from - sky as emissive color

crappy shader (only for testing purpose) litSolidToon.glsl pastebin.com/gbMLBacG[/quote]

Nice, still looks close from reference though.

[quote=“codingmonkey”]>
crappy shader (only for testing purpose) litSolidToon.glsl pastebin.com/gbMLBacG[/quote]

It uses default lighting

float diff = GetDiffuse(normal, vWorldPos.xyz, lightDir);

Urho used notnormalized directions ? It is correct?

float GetDiffuse(vec3 normal, vec3 worldPos, out vec3 lightDir)
{
        ...
        lightDir = cLightDirPS;
            ....
            return abs(dot(normal, lightDir));
void PS()
{
    ...
    gl_FragColor = vec4(finalColor.rgb, 1.0);
    if (cLightDirPS != normalize(cLightDirPS))
        gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}

Without self-shadowing and fog, only perpixel light sources and forward rendering

[code]void PS()
{
// DIFF
vec4 diffInput = texture2D(sDiffMap, vTexCoord.xy);
vec3 normal = normalize(vNormal);
float NdotL = dot(normal, normalize(cLightDirPS)) * 0.5 + 0.5;
NdotL = clamp(NdotL, 0.01, 0.99);
vec3 ramp = texture2D(sNormalMap, vec2(NdotL, 0.5)).rgb;
vec3 finalColor = diffInput.rgb * ramp;

// SPEC
vec3 cameraDir = cCameraPosPS - vWorldPos.xyz;
vec3 h = normalize(normalize(cLightDirPS) + normalize(cameraDir));
float nh = max(0, dot(normal, h));
float spec = pow(nh, 64);
finalColor += cLightColor.rgb * spec;

// RIM
vec3 rimDir = normalize(cameraDir);
float rimContribution = 1.0 - dot(normal, rimDir);
rimContribution = clamp(rimContribution, 0.0, 1.0);
rimContribution = pow(rimContribution, cRimPower);
rimContribution = clamp(rimContribution, 0.0, 1.0);
vec3 rimColor = rimContribution* cRimColor.rgb * cRimColor.a;
finalColor += rimColor;

gl_FragColor = vec4(finalColor.rgb, 1.0);

}
[/code]

Also i use ramp texture

Add selfshadowing and fog

void PS()
{
    // DIFF
    vec4 diffInput = texture2D(sDiffMap, vTexCoord.xy);
    vec3 normal = normalize(vNormal);
    float NdotL = dot(normal, normalize(cLightDirPS)) * 0.5 + 0.5;
    NdotL = clamp(NdotL, 0.01, 0.99);
    vec3 ramp = texture2D(sNormalMap, vec2(NdotL, 0.5)).rgb;
    #ifdef SHADOW
       ramp *= GetShadow(vShadowPos, vWorldPos.w);
    #endif
    ramp += cAmbientColor;
    ramp = clamp(ramp, 0.0, 1.0);
    vec3 finalColor = diffInput.rgb * ramp;
    
    // SPEC
    vec3 cameraDir = cCameraPosPS - vWorldPos.xyz;
    vec3 h = normalize(normalize(cLightDirPS) + normalize(cameraDir));
    float nh = max(0, dot(normal, h));
    float spec = pow(nh, 64);
    finalColor += cLightColor.rgb * spec;

    // RIM
    vec3 rimDir = normalize(cameraDir);
    float rimContribution = 1.0 - dot(normal, rimDir);
    rimContribution = clamp(rimContribution, 0.0, 1.0);
    rimContribution = pow(rimContribution, cRimPower);
    rimContribution = clamp(rimContribution, 0.0, 1.0);
    vec3 rimColor = rimContribution* cRimColor.rgb * cRimColor.a;
    finalColor += rimColor;
    
    // FOG
    #ifdef HEIGHTFOG
        float fogFactor = GetHeightFogFactor(vWorldPos.w, vWorldPos.y);
    #else
        float fogFactor = GetFogFactor(vWorldPos.w);
    #endif
    finalColor = GetFog(finalColor, fogFactor);
    
    gl_FragColor = vec4(finalColor.rgb, 1.0);
}

For correct working it is needed to move the center of gradient to the bright side

Rim to outline (not perfect)

void PS()
{
    // DIFF
    vec4 diffInput = texture2D(sDiffMap, vTexCoord.xy);
    vec3 normal = normalize(vNormal);
    float NdotL = dot(normal, normalize(cLightDirPS)) * 0.5 + 0.5;
    NdotL = clamp(NdotL, 0.01, 0.99);
    vec3 ramp = texture2D(sNormalMap, vec2(NdotL, 0.5)).rgb;
    #ifdef SHADOW
       ramp *= GetShadow(vShadowPos, vWorldPos.w);
    #endif
    ramp += cAmbientColor;
    ramp = clamp(ramp, 0.0, 1.0);
    vec3 finalColor = diffInput.rgb * ramp;
    
    // SPEC
    vec3 cameraDir = cCameraPosPS - vWorldPos.xyz;
    vec3 h = normalize(normalize(cLightDirPS) + normalize(cameraDir));
    float nh = max(0, dot(normal, h));
    float spec = pow(nh, 64);
    finalColor += cLightColor.rgb * spec;

    // BLACK RIM
    vec3 rimDir = normalize(cameraDir);
    float rimContribution = dot(normal, rimDir);
    rimContribution = clamp(rimContribution * 1.5, 0.0, 1.0);
    finalColor *= rimContribution;
    
    // FOG
    #ifdef HEIGHTFOG
        float fogFactor = GetHeightFogFactor(vWorldPos.w, vWorldPos.y);
    #else
        float fogFactor = GetFogFactor(vWorldPos.w);
    #endif
    finalColor = GetFog(finalColor, fogFactor);
    
    gl_FragColor = vec4(finalColor.rgb, 1.0);
}

I’m totally going to grab that rim shader, I’ve always wanted rim lighting :stuck_out_tongue: