I have been unable to utilize custom shaders and a custom material to properly key out (remove) the green background from a video. The video used was here: https://youtu.be/ZXsQAXx_ao0?feature=shared
Here is the code which includes the shaders and material.
<!DOCTYPE html>
<html>
<head>
<style>
html, body{
background:#323232;
outline: none;
overflow: hidden;
margin:0;}
</style>
</head>
<body>
<canvas id="canvas" class="center " style="overflow:hidden"></canvas>
<script id="vertexShader" type="glsl">
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); }
</script>
<script id="fragmentShader" type="glsl">
uniform sampler2D tex;
uniform float texWidth;
uniform float texHeight;
uniform vec3 keyColor;
uniform float similarity;
uniform float smoothness;
uniform float spill;
varying vec2 vUv;
vec2 RGBtoUV(vec3 rgb) {
return vec2(
rgb.r * -0.169 + rgb.g * -0.331 + rgb.b * 0.5 + 0.5,
rgb.r * 0.5 + rgb.g * -0.419 + rgb.b * -0.081 + 0.5); }
vec4 ProcessChromaKey(vec2 texCoord) {
vec4 rgba = texture2D(tex, texCoord);
float chromaDist = distance(RGBtoUV(texture2D(tex, texCoord).rgb), RGBtoUV(keyColor));
float baseMask = chromaDist - similarity;
float fullMask = pow(clamp(baseMask / smoothness, 0., 1.), 1.5);
rgba.a = fullMask;
float spillVal = pow(clamp(baseMask / spill, 0., 1.), 1.5);
float desat = clamp(rgba.r * 0.2126 + rgba.g * 0.7152 + rgba.b * 0.0722, 0., 1.);
rgba.rgb = mix(vec3(desat, desat, desat), rgba.rgb, spillVal);
return rgba; }
void main(void) {
vec2 texCoord = vUv;
gl_FragColor = ProcessChromaKey(texCoord); }
</script>
<script async src="./js/module-shims.js"></script>
<script type="importmap">{
"imports":{
"three":"./js/three/three.module.js",
"modules/":"./js/three/modules/"}}
</script>
<!-- -->
<script type="module">
import * as THREE from 'three';
window.onload = init
function ChromaKeyMaterial(texture, width, height, keyColor, similarity=0.01, smoothness=0.08, spill=0.1){
let sm = new THREE.ShaderMaterial({
uniforms: {
map: { value: texture },
keyColor: { value: new THREE.Color(keyColor) },
texWidth: { value: width },
texHeight: { value: height },
similarity: { value: similarity },
smoothness: { value: smoothness },
spill: { value: spill } },
vertexShader: document.getElementById('vertexShader').textContent,
fragmentShader: document.getElementById('fragmentShader').textContent,
transparent:true });
return sm }
let camera, scene, renderer, video, geometry, material, mesh, texture
function init() {
video = document.createElement('video');
video.setAttribute('webkit-playsinline','true');
video.setAttribute('playsinline','true');
video.model_auto = false;
video.controls = false;
video.preload = 'auto';
video.muted = false;
video.crossOrigin = 'anonymous';
video.style.display = 'none';
video.autoplay=true;
video.src = 'green.mp4'
scene = new THREE.Scene();
scene.background = new THREE.Color(0x323232);
camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerheight, 0.1, 10000)
camera.position.z = 800
geometry = new THREE.PlaneGeometry(1280,720,5 );
texture = new THREE.VideoTexture(video);
material = new ChromaKeyMaterial(texture,1280,720,'#00ff00');
/*material = new THREE.MeshBasicMaterial({
side: THREE.DoubleSide,
transparent: true,
map: texture});*/
mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
renderer = new THREE.WebGLRenderer({antialias: true, canvas });
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
//document.body.appendChild( renderer.domElement );
window.addEventListener('resize',resize);
resize()
video.play()
render()}
function resize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );}
function render(){
video.needsUpdate=
texture.needsUpdate=
material.needsUpdate=true
renderer.render(scene,camera);
requestAnimationFrame(render);}
</script>
</body>
</html>
I expect the shaders and material to remove the specific color of the background.