@virtualscenery/greenscreenstream
Version:
Genereate new MediaStreams or Canvas elements based on MediaStreams (webcam) with any background image/video. Greenscreen your webcam and enable virtual backgrounds in your web applications.
134 lines (123 loc) • 4.64 kB
text/typescript
/**
* GLSL fragment shader source code as a string.
*
* This shader samples a texture (`A`) using normalized screen coordinates
* and outputs the resulting color to `fragColor`.
*
* Uniforms:
* - `resolution`: The resolution of the output in pixels (vec2).
* - `A`: The input texture (sampler2D).
*
* Usage:
* Assign this constant to a shader program that expects the above uniforms.
*/
export const MAIN_FRAG: string = `
uniform vec2 resolution;
uniform sampler2D A;
out vec4 fragColor;
void main(){
vec2 uv = gl_FragCoord.xy/resolution.xy;
fragColor = texture(A, uv);
}
`;
/**
* GLSL vertex shader source code for the main vertex shader.
*
* This shader takes a 2D position attribute (`pos`) as input and sets the `gl_Position`
* for rendering. It also declares an output variable `fragColor`, though it is not assigned
* in this shader. The shader is intended for use in rendering full-screen quads or similar
* geometry where only position is required.
*
* @remarks
* - `layout(location = 0) in vec2 pos;` specifies the input attribute location.
* - `gl_Position` is set using the input position with z = 0.0 and w = 1.0.
* - The output `fragColor` is declared for compatibility with fragment shaders.
*/
export const MAIN_VERT: string = `
layout(location = 0) in vec2 pos;
out vec4 fragColor;
void main() {
gl_Position = vec4(pos.xy,0.0,1.0);
}
`;
/**
* GLSL vertex shader source code for a simple buffer.
*
* This shader takes a 2D position attribute (`pos`) as input and sets the `gl_Position`
* for each vertex. It also declares an output variable `fragColor`, which can be used
* in the fragment shader stage. The shader is intended for use in rendering full-screen
* quads or similar geometry where only position data is required.
*
* @remarks
* - The input attribute `pos` is expected at location 0.
* - The output `fragColor` is declared but not assigned in this shader; it is typically
* used in the fragment shader.
*/
export const BUFFER_VERT: string = `
layout(location = 0) in vec2 pos;
out vec4 fragColor;
void main() {
gl_Position = vec4(pos.xy,0.0,1.0);
}
`;
/**
* GLSL fragment shader source for chroma key compositing.
*
* This shader blends a foreground (webcam) texture with a background texture
* using chroma keying (typically for green screen effects). It converts colors
* from RGB to YUV space to perform color similarity checks, allowing for
* configurable tolerance via the `maskRange` uniform.
*
* Uniforms:
* - `time`: Current time (unused in this shader).
* - `resolution`: The resolution of the output image.
* - `webcam`: Foreground texture (e.g., webcam feed).
* - `background`: Background texture to composite behind the foreground.
* - `chromaKey`: The chroma key color to remove (in RGBA).
* - `maskRange`: vec2 specifying the inner and outer tolerance for chroma keying.
*
* Outputs:
* - `fragColor`: The final composited color for each fragment.
*
* The shader uses a helper function `colorclose` to determine how close a pixel's
* color is to the chroma key color in YUV space, and blends the foreground and
* background accordingly.
*/
export const BUFFER_FRAG: string = `
uniform float time;
uniform vec2 resolution;
uniform sampler2D webcam;
uniform sampler2D background;
uniform vec4 chromaKey;
uniform vec2 maskRange;
out vec4 fragColor;
mat4 RGBtoYUV = mat4(
0.257, 0.439, -0.148, 0.0,
0.504, -0.368, -0.291, 0.0,
0.098, -0.071, 0.439, 0.0,
0.0625, 0.500, 0.500, 1.0
);
float colorclose(vec3 yuv, vec3 keyYuv, vec2 tol)
{
float tmp = sqrt(pow(keyYuv.g - yuv.g, 2.0) + pow(keyYuv.b - yuv.b, 2.0));
if (tmp < tol.x)
return 0.0;
else if (tmp < tol.y)
return (tmp - tol.x)/(tol.y - tol.x);
else
return 1.0;
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 fragPos = 1. - fragCoord.xy / resolution.xy;
vec4 fg = texture(webcam, vec2(1.-fragPos.x,fragPos.y));
vec4 bg = texture(background, vec2(1.-fragPos.x,fragPos.y));
vec4 keyYUV = RGBtoYUV * chromaKey;
vec4 yuv = RGBtoYUV * fg;
float mask = 1.0 - colorclose(yuv.rgb, keyYUV.rgb, maskRange);
fragColor = max(fg - mask * chromaKey, 0.0) + bg * mask;
}
void main(){
mainImage(fragColor,gl_FragCoord.xy);
}
`;