2 votes

Chroma key Fragment Shader ne parvient pas à trouver la couleur

J'essaie d'écrire un fragment-shader qui fonctionne comme un filtre chromatique pour une couleur spécifique (par exemple, rendre tous les pixels avec un vert spécifique transparent).

Le shader que j'écris est destiné à être utilisé dans WebGL via PIXI.js.

JSFiddle : https://jsfiddle.net/IbeVanmeenen/hexec6eg/14/

Jusqu'à présent, j'ai écrit ce code pour le shader, basé sur le shader que j'ai trouvé aquí .

varying vec2 vTextureCoord;

uniform float thresholdSensitivity;
uniform float smoothing;
uniform vec3 colorToReplace;
uniform sampler2D uSampler;

void main() {
    vec4 textureColor = texture2D(uSampler, vTextureCoord);

    float maskY = 0.2989 * colorToReplace.r + 0.5866 * colorToReplace.g + 0.1145 * colorToReplace.b;
    float maskCr = 0.7132 * (colorToReplace.r - maskY);
    float maskCb = 0.5647 * (colorToReplace.b - maskY);

    float Y = 0.2989 * textureColor.r + 0.5866 * textureColor.g + 0.1145 * textureColor.b;
    float Cr = 0.7132 * (textureColor.r - Y);
    float Cb = 0.5647 * (textureColor.b - Y);

    float blendValue = smoothstep(thresholdSensitivity, thresholdSensitivity + smoothing, distance(vec2(Cr, Cb), vec2(maskCr, maskCb)));
    gl_FragColor = vec4(textureColor.rgb, textureColor.a * blendValue);
}

Maintenant, quand je définis et teste ceci, rien ne se passe. Le problème se situe au niveau du shader, car les autres filtres que j'ai essayés fonctionnent.

La couleur que j'utilise pour le test est rgb(85, 249, 44) .

Le code complet pour le shader avec PIXI est ci-dessous :

function ChromaFilter() {
    const vertexShader = null;
    const fragmentShader = [
        "varying vec2 vTextureCoord;",

        "uniform float thresholdSensitivity;",
        "uniform float smoothing;",
        "uniform vec3 colorToReplace;",
        "uniform sampler2D uSampler;",

        "void main() {",
            "vec4 textureColor = texture2D(uSampler, vTextureCoord);",

            "float maskY = 0.2989 * colorToReplace.r + 0.5866 * colorToReplace.g + 0.1145 * colorToReplace.b;",
            "float maskCr = 0.7132 * (colorToReplace.r - maskY);",
            "float maskCb = 0.5647 * (colorToReplace.b - maskY);",

            "float Y = 0.2989 * textureColor.r + 0.5866 * textureColor.g + 0.1145 * textureColor.b;",
            "float Cr = 0.7132 * (textureColor.r - Y);",
            "float Cb = 0.5647 * (textureColor.b - Y);",

            "float blendValue = smoothstep(thresholdSensitivity, thresholdSensitivity + smoothing, distance(vec2(Cr, Cb), vec2(maskCr, maskCb)));",
            "gl_FragColor = vec4(textureColor.rgb, textureColor.a * blendValue);",
        "}"
    ].join('\n');

    let uniforms = {};

    PIXI.Filter.call(this,
        vertexShader,
        fragmentShader,
        uniforms
    );

    this.uniforms.thresholdSensitivity = 0.4;
    this.uniforms.smoothing = 0.1;
    this.uniforms.colorToReplace = [0.33, 0.97, 0.17];

    this.glShaderKey = 'chromakey';
}

ChromaFilter.prototype = Object.create(PIXI.Filter.prototype);
ChromaFilter.prototype.constructor = ChromaFilter;

Ceci est appliqué à la vidéo-sprite comme ceci :

videoBase = new PIXI.VideoBaseTexture(videoLoaderVid);
videoBase.on('loaded', () => {
    video = videoBase.source;
    video.volume = 0;
    video.pause();
    video.currentTime = 0;

    videoTexture = new PIXI.Texture(videoBase);
    videoSprite = new PIXI.Sprite(videoTexture);

    const filter = new ChromaFilter();
    videoSprite.filters = [filter];

    resolve();
});

Et PIXI est mis en place comme ça :

stage = new PIXI.Container();

renderer = PIXI.autoDetectRenderer(720, 720, {
    preserveDrawingBuffer: true,
    clearBeforeRender: true
});

canvasContainer.appendChild(renderer.view);

Le site vidéo se trouve dans son propre conteneur DisplayObjectContainer et est affiché au-dessus d'un autre conteneur DisplayObjectContainer (d'où la nécessité d'un filtre chromatique).


UPDATE :

Le shader fixe peut être trouvé ici :
https://gist.github.com/IbeVanmeenen/d4f5225ad7d2fa54fabcc38d740ba30e

Et une démo fixe peut être trouvée ici :
https://jsfiddle.net/IbeVanmeenen/hexec6eg/17/

1voto

Kirill Dmitrenko Points 2101

Le shader est bon, le problème est que les uniformes ( colorToReplace , thresholdSensitivity y smoothing ) ne sont pas passés, ils sont tous mis à 0. Avec un peu de chance, j'ai découvert que pour résoudre ce problème, vous devez supprimer le troisième paramètre que vous passez à la commande PIXI.Filter constructeur :

/* ... */
PIXI.Filter.call(this, vertexShader, fragmentShader) // no uniforms param here
/* ... */

PS. Vous n'avez pas répondu dans le chat, donc je poste mes conclusions ici.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X