【发布时间】:2017-06-08 16:15:55
【问题描述】:
我正在尝试编写一个片段着色器,用作特定颜色的色度键过滤器(例如,使具有特定绿色的所有像素透明)。
我正在编写的着色器是用于 WebGL 槽 PIXI.js。
JSFiddle:https://jsfiddle.net/IbeVanmeenen/hexec6eg/14/
到目前为止,我为着色器编写了这段代码,基于我找到的着色器here。
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);
}
现在,当我定义和测试它时,什么都没有发生。 问题出在着色器上,因为我尝试过的其他滤镜都可以工作。
我用于测试的颜色是rgb(85, 249, 44)。
使用 PIXI 的着色器的完整代码如下:
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;
这适用于视频精灵,如下所示:
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();
});
而 PIXI 是这样设置的:
stage = new PIXI.Container();
renderer = PIXI.autoDetectRenderer(720, 720, {
preserveDrawingBuffer: true,
clearBeforeRender: true
});
canvasContainer.appendChild(renderer.view);
视频精灵位于它自己的 DisplayObjectContainer 上,并显示在另一个 DisplayObjectContainer 上方(因此需要色度过滤器)
更新:
固定着色器可以在这里找到:
https://gist.github.com/IbeVanmeenen/d4f5225ad7d2fa54fabcc38d740ba30e
可以在此处找到固定演示:
https://jsfiddle.net/IbeVanmeenen/hexec6eg/17/
【问题讨论】:
-
您是否尝试将
blendValue输出到另一个频道?画布是否有 alpha,是否为过滤器正确设置了混合? -
@KirillDmitrenko 感谢您的回复!我已经稍微更新了这个问题,所以你的所有问题都应该在那里得到回答。你会如何处理“你有没有尝试将 blendValue 输出到另一个通道”(仍然在 WebGL 方面学习很多)
-
在片段着色器的
main函数末尾添加gl_FragColor = vec4(blendValue, 0, 0, 1);。 -
现在(逻辑上)看到很多红色,只有部分视频是纯黑色可见的,其余部分都是红色的。我错过了什么吗?
-
不,听起来差不多。我责备混合。我对 PIXI API 并不完全熟悉,但从他们的文档看来,默认混合应该是正确的。如果您只使用滤镜绘制精灵,请尝试将
transparent: true添加到PIXI.autoDetectRenderer选项并将着色器输出从gl_FragColor = vec4(textureColor.rgb, textureColor.a * blendValue);更改为gl_FragColor = textureColor * blendValue(假设您的视频纹理是不透明的)。
标签: javascript webgl shader fragment-shader pixi.js