Help toon shader

Hello, Everyone. I’m Hizard.
I always get a lot of help.
This time, it’s a request for help with the toon shader.

Idk anything about shaders and all I’ve written is following the code.
Therefore, I desperately need your help.

Code:

var MyToonShader = pc.createScript('myToonShader');

// initialize code called once per entity
MyToonShader.prototype.initialize = function() {
    this.lightEntity = this.app.root.findByName('Light');
    var toonShaderVert = this.app.assets.find('toonShader.vert').resource;
    var toonShaderFrag = this.app.assets.find('toonShader.frag').resource;

    const shader = pc.createShaderFromCode(this.app.graphicsDevice, toonShaderVert, toonShaderFrag, "myToon", {
        aPosition: pc.SEMANTIC_POSITION,
        aNormal: pc.SEMANTIC_NORMAL,
        aUv: pc.SEMANTIC_TEXCOORD0,
    });

    const material = new pc.Material();
    material.shader = shader;

    let originalTexture = null;
    var renders = this.entity.findComponents("render");
    renders.forEach((render) => {
        const meshInstances = render.meshInstances;
        for (let i = 0; i < meshInstances.length; ++i) {
            const meshInstance = meshInstances[i];
            if(!originalTexture) {
                const originalMaterial = meshInstance.material;
                originalTexture = originalMaterial.diffuseMap;
            }
            meshInstance.material = material;
        }
    });

    const lightPosArray = [
        this.lightEntity.getPosition().x,
        this.lightEntity.getPosition().y,
        this.lightEntity.getPosition().z
    ]

    material.setParameter('uLightPos', lightPosArray);
    material.setParameter('uTexture', originalTexture);
    material.update();
};

fragment

precision mediump float;
uniform sampler2D uTexture;
varying float vertOutTexCoord;
varying vec2 texCoord;
void main(void)
{
    float v = vertOutTexCoord;
    v = float(int(v * 6.0)) / 6.0;
    //vec4 color = texture2D (uTexture, texCoord); // try this to use the diffuse color.
    vec4 color = vec4(1.0, 1.0, 1.0, 1.0); // Change this line
    gl_FragColor = color * vec4(v, v, v, 1.0);
}

vertex

// Attributes per vertex: position, normal and texture coordinates
attribute vec4 aPosition;
attribute vec3 aNormal;
attribute vec2 aUv;

uniform mat4   matrix_viewProjection;
uniform mat4   matrix_model;
uniform mat4   matrix_view;
uniform mat3   matrix_normal;
uniform vec3   uLightPos;

// Color to fragment program
varying float vertOutTexCoord;
varying vec2 texCoord;

void main(void)
{
    mat4 modelView = matrix_view * matrix_model;
    mat4 modelViewProj = matrix_viewProjection * matrix_model;

    // Get surface normal in eye coordinates
    vec3 eyeNormal = normalize(matrix_normal * aNormal);

    // Get vertex position in eye coordinates
    vec4 vertexPos = modelView * aPosition;
    vec3 vertexEyePos = vertexPos.xyz / vertexPos.w;

    // Get vector to light source
    vec3 lightDir = normalize(uLightPos - vertexEyePos);

    // Dot product gives us diffuse intensity. The diffuse intensity will be
    // used as the 1D color texture coordinate to look for the color of the
    // resulting fragment (see fragment shader).
    vertOutTexCoord = max(0.0, dot(eyeNormal, lightDir));
    texCoord = aUv;

    // Transform the geometry
    gl_Position = modelViewProj * aPosition;
}

Source: PlayCanvas Examples - shader-toon

Result:

  • I’d like to keep the existing material and apply only toon shading.
  • All of material in character is no texture file, only color value.
  • I think I need to modify part color of Fragment, right?

Update

  • The coloring was successful.

Code:

var MyToonShader = pc.createScript('myToonShader');

MyToonShader.attributes.add('toonColor', { type: 'rgba', default: [0,0,0,1]});

MyToonShader.prototype.initialize = function() {
    ......
    material.setParameter('toonColor', this.toonColor.data);
    material.update();
};

fragment:

precision mediump float;
uniform sampler2D uTexture;
uniform vec4 toonColor;
varying float vertOutTexCoord;
varying vec2 texCoord;
void main(void)
{
    float v = vertOutTexCoord;
    v = float(int(v * 6.0)) / 6.0;
    //vec4 color = texture2D (uTexture, texCoord); // try this to use the diffuse color.
    vec4 color = toonColor;// vec4(1.0, 1.0, 1.0, 1.0);
    gl_FragColor = color * vec4(v, v, v, 1.0);
}

Hi @Hizard,

If you are looking to utilize the existing materials/shaders then you need to rework your shader to use shader chunks (override the PlayCanvas internal shaders) instead of creating a full custom shader.

There are some examples here: Tutorials | Learn PlayCanvas

There has been work recently in the engine to split the internal shaders to frontend / backend, to make it easier to add lighting support to custom shaders. Someone from the PlayCanvas team may be able to offer some insight on how to use that @Elliott @mvaligursky.

1 Like

Oh, I have to rework shader to use shader chunks.
Following the tutorial, I’ll try.

I don’t know what this work means, but I think I know it’s a good feature for everyone. :sweat_smile:

1 Like