在HTML画布视频上的SVG过滤器 [英] SVG Filter on HTML Canvas Video

查看:99
本文介绍了在HTML画布视频上的SVG过滤器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我想在画布上创建毛刺效果,从网络摄像头获取每一帧。下面的代码。这里的代码仅适用于 width:200px height:200px 如果将此值更改为 width:600px height:400px (容器大小),毛刺效应停止工作。以下是代码,您可以在其中更改值canvas.width,canvas.height并自行查看 CodePen 。有人知道,这是什么原因以及如何解决?或者它对feTurbulence有一些限制吗?


$ b

const addEffect =(element,filter )=> {element.style.webkitFilter =`url(#$ {filter})`; element.style.mozFilter =`url(#$ {filter})`; element.style.filter =`url(#$ {filter})`;}; const runEffect =()=> {const turb = document.querySelector('#displacement feTurbulence'); const turbVal = {val:0.000001}; const btTl = new TimelineLite({paused:true,onUpdate(){turb.setAttribute('baseFrequency',`0 $ {turbVal.val}`);},}); (turbVal,0.2,{val:0.3}); btTl.to(turbVal,0.2,{val:0.000001}); btTl.restart();}; const URL = window.URL || window.webkitURL || window.mozURL || window.msURL; const video = document.createElement('video'); navigator.mediaDevices.getUserMedia({video:true,})。then((stream)=> {video.src = URL.createObjectURL(stream); }); const canvas = document.querySelector('#canvas'); const ctx = canvas.getContext('2d'); addEffect(canvas,'displacement'); setInterval(()=> runEffect(),1000) ; const loop =()=> {ctx.drawImage(video,0,0,canvas.width,canvas.height); requestAnimationFrame(loop);}; loop();

。容器{margin:0 auto;宽度:600px; height:400px; margin-top:100px; box-shadow:1px 1px 20px#666; position:relative;}。container> canvas {position:absolute;背景颜色:红色; mix-blend-mode:darken;} svg {position:absolute;宽度:0; height:0;}

< script src =https ://cdnjs.cloudflare.com/ajax/libs/gsap/1.18.0/TweenMax.min.js>< / script>< div class =container> < canvas id =canvaswidth =200pxheight =200px>< / canvas> < svg xmlns =http://www.w3.org/2000/svgversion =1.1class =svg-filters> < DEFS> < filter id =displacement> < feTurbulence type =fractalNoisebaseFrequency =0.0numOctaves =1result =warp>< / feTurbulence> < feDisplacementMap xChannelSelector =RyChannelSelector =Gscale =80in =SourceGraphicin2 =warp/> < /滤光器> < / DEFS> < / SVG> < / div>

解决方案

似乎有一些错误导致画布在尺寸较大时不能很快重绘。您可以通过调整CSS属性(如下例中的不透明度)来强制重绘。

-hide =falsedata-console =truedata-babel =true>

  const addEffect =(element,filter)=> {element.style.webkitFilter =`url(#$ {filter})`; element.style.mozFilter =`url(#$ {filter})`; element.style.filter =`url(#$ {filter})`;}; const runEffect =()=> {const turb = document.querySelector('#displacement feTurbulence'); const turbVal = {val:0.000001}; const btTl = new TimelineLite({paused:true,onUpdate(){turb.setAttribute('baseFrequency',`0 $ {turbVal.val}`);},}); (turbVal,0.2,{val:0.3}); btTl.to(turbVal,0.2,{val:0.000001}); btTl.restart();}; const URL = window.URL || window.webkitURL || window.mozURL || window.msURL; const video = document.createElement('video'); navigator.mediaDevices.getUserMedia({video:true,})。then((stream)=> {video.src = URL.createObjectURL(stream); }); const canvas = document.querySelector('#canvas'); const ctx = canvas.getContext('2d'); addEffect(canvas,'displacement'); setInterval(()=> runEffect(),1000) ; / ** *使用hack强制画布重绘* / const refreshCanvas = function(){let on = true; return()=> {on =!on; canvas.style.opacity = on? 1:0.999; }}(); const loop =(timestamp)=> {ctx.drawImage(video,0,0,canvas.width,canvas.height); refreshCanvas(); //调用我们的hack requestAnimationFrame(loop);}; loop();  

  .container {margin:0 auto;宽度:600px; height:400px; margin-top:100px; box-shadow:1px 1px 20px#666; position:relative;}。container> canvas {position:absolute;背景颜色:红色; mix-blend-mode:darken;} svg {position:absolute;宽度:0; height:0;}  

< script src =https ://cdnjs.cloudflare.com/ajax/libs/gsap/1.18.0/TweenMax.min.js>< / script>< div class =container> < canvas id =canvaswidth =600height =400>< / canvas> < svg xmlns =http://www.w3.org/2000/svgversion =1.1class =svg-filters> < DEFS> < filter id =displacement> < feTurbulence type =fractalNoisebaseFrequency =0.0numOctaves =1result =warp>< / feTurbulence> < feDisplacementMap xChannelSelector =RyChannelSelector =Gscale =80in =SourceGraphicin2 =warp/> < /滤光器> < / DEFS> < / SVG> < / div>


So I wanna create glitch effect on canvas, that get every frame from webcam. Code below. Here the code, which works only if width: 200px height: 200px if change this value to width: 600px height: 400px(container size), glitch effect stops working. Here's code where you can change value canvas.width, canvas.height, and see it by yourself CodePen. Does someone know, what a reason for that and how fix it? Or it's some kinda limitations on feTurbulence?

const addEffect = (element, filter) => {
  element.style.webkitFilter = `url(#${filter})`;
  element.style.mozFilter = `url(#${filter})`;
  element.style.filter = `url(#${filter})`;
};

const runEffect = () => {
  const turb = document.querySelector('#displacement feTurbulence');
  const turbVal = { val: 0.000001 };

  const btTl = new TimelineLite({
    paused: true,
    onUpdate() {
      turb.setAttribute('baseFrequency', `0 ${turbVal.val}`);
    },
  });
  btTl.to(turbVal, 0.2, { val: 0.3 });
  btTl.to(turbVal, 0.2, { val: 0.000001 });

  btTl.restart();
};

const URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
const video = document.createElement('video');

navigator.mediaDevices.getUserMedia({
  video: true,
}).then((stream) => {
  video.src = URL.createObjectURL(stream);
});

const canvas = document.querySelector('#canvas');

const ctx = canvas.getContext('2d');
addEffect(canvas, 'displacement');
setInterval(() => runEffect(), 1000);

const loop = () => {
  ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
  requestAnimationFrame(loop);
};
loop();

.container {
  margin: 0 auto;
  width: 600px;
  height: 400px;
  margin-top: 100px;
  box-shadow: 1px 1px 20px #666;
  position: relative;
}
.container > canvas {
  position: absolute;
  background-color: red;
  mix-blend-mode: darken;
}
svg {
  position: absolute;
  width: 0;
  height: 0;
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.18.0/TweenMax.min.js"></script>
<div class="container">
      <canvas id="canvas" width="200px" height="200px"></canvas>
      <svg xmlns="http://www.w3.org/2000/svg" version="1.1" class="svg-filters">
        <defs>
          <filter id="displacement">
              <feTurbulence type="fractalNoise" baseFrequency="0.0" numOctaves="1" result="warp"></feTurbulence>
              <feDisplacementMap xChannelSelector="R" yChannelSelector="G" scale="80" in="SourceGraphic" in2="warp" />
          </filter>
        </defs>
      </svg>
    </div>

解决方案

It seems that there is some bug causing the canvas to not be redrawn fast enough when it is larger in size. You can force it to redraw by tweaking a CSS property, such as opacity in the example below.

const addEffect = (element, filter) => {
  element.style.webkitFilter = `url(#${filter})`;
  element.style.mozFilter = `url(#${filter})`;
  element.style.filter = `url(#${filter})`;
};

const runEffect = () => {
  const turb = document.querySelector('#displacement feTurbulence');
  const turbVal = { val: 0.000001 };

  const btTl = new TimelineLite({
    paused: true,
    onUpdate() {
      turb.setAttribute('baseFrequency', `0 ${turbVal.val}`);
    },
  });
  btTl.to(turbVal, 0.2, { val: 0.3 });
  btTl.to(turbVal, 0.2, { val: 0.000001 });

  btTl.restart();
};

const URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
const video = document.createElement('video');

navigator.mediaDevices.getUserMedia({
  video: true,
}).then((stream) => {
  video.src = URL.createObjectURL(stream);
});

const canvas = document.querySelector('#canvas');

const ctx = canvas.getContext('2d');
addEffect(canvas, 'displacement');
setInterval(() => runEffect(), 1000);

/**
 * Use a hack to force the canvas to redraw
 */
const refreshCanvas = function(){
  let on = true;
  return () => {
    on = !on;
    canvas.style.opacity = on ? 1 : 0.999;
  }
}();


const loop = (timestamp) => {
    ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
    refreshCanvas(); // call our hack
    requestAnimationFrame(loop);
};
loop();

.container {
  margin: 0 auto;
  width: 600px;
  height: 400px;
  margin-top: 100px;
  box-shadow: 1px 1px 20px #666;
  position: relative;
}
.container > canvas {
  position: absolute;
  background-color: red;
  mix-blend-mode: darken;
}
svg {
  position: absolute;
  width: 0;
  height: 0;
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.18.0/TweenMax.min.js"></script>
<div class="container">
      <canvas id="canvas" width="600" height="400"></canvas>
      <svg xmlns="http://www.w3.org/2000/svg" version="1.1" class="svg-filters">
        <defs>
          <filter id="displacement">
              <feTurbulence type="fractalNoise" baseFrequency="0.0" numOctaves="1" result="warp"></feTurbulence>
              <feDisplacementMap xChannelSelector="R" yChannelSelector="G" scale="80" in="SourceGraphic" in2="warp" />
          </filter>
        </defs>
      </svg>
    </div>

这篇关于在HTML画布视频上的SVG过滤器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆