【问题标题】:Gif not playing over canvas animation on FirefoxGif 没有在 Firefox 上播放画布动画
【发布时间】:2021-05-17 08:29:56
【问题描述】:

我在 Firefox 上遇到了这个奇怪的错误,当有画布动画时,用作背景图像的 gif 无法播放。就像这个例子一样。如果你在 Webkit 上检查一下,那完全没问题。

const separation = 100, amountX = 70, amountY = 50;
let container, camera, scene, renderer, particles;
let count = 0, windowHalfX = window.innerWidth / 2, windowHalfY = window.innerHeight / 2, cameraPosition = 80;

const init = () => {
  container = document.createElement('div');
  document.body.appendChild(container);
  
  camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000);
  camera.position.x = cameraPosition;
  camera.position.y = 1000;
  camera.position.z = -550;
  camera.zoom = 1.2;
  
  scene = new THREE.Scene();
  
  const numParticles = amountX * amountY;
  const positions = new Float32Array(numParticles * 3);
  const scales = new Float32Array(numParticles);

  let i = 0, j = 0;
  
  for(let ix = 0; ix < amountX; ix++) {
    for(let iy = 0; iy < amountY; iy++) {
      positions[i] = ix * separation - ((amountX * separation ) / 2);
      positions[i + 1] = 0;
      positions[i + 2] = iy * separation - ((amountY * separation ) / 2);

      scales[j] = 1;

      i += 3;
      j ++;
    }
  }
  
  const geometry = new THREE.BufferGeometry();
  geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
  geometry.setAttribute('scale', new THREE.BufferAttribute(scales, 1));
  
  const material = new THREE.ShaderMaterial({
    uniforms: {
      color: {value: new THREE.Color(0xeae6c3)},
    },
    vertexShader: document.getElementById('vertexshader').textContent,
    fragmentShader: document.getElementById('fragmentshader').textContent,
  });
  
  particles = new THREE.Points(geometry, material);
  scene.add(particles);
  
  renderer = new THREE.WebGLRenderer({antialias: true});
  renderer.setClearColor(0x192735, 1);
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(window.innerWidth, window.innerHeight);
  container.appendChild(renderer.domElement);
  container.style.touchAction = 'none';
  
  window.addEventListener( 'resize', onWindowResize );
};

const onWindowResize = () => {
  windowHalfX = window.innerWidth / 2;
  windowHalfY = window.innerHeight / 2;

  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize( window.innerWidth, window.innerHeight );
};

const render = () => {
  camera.lookAt(scene.position);

  const positions = particles.geometry.attributes.position.array;
  const scales = particles.geometry.attributes.scale.array;

  let i = 0, j = 0;

  for (let ix = 0; ix < amountX; ix ++) {
    for (let iy = 0; iy < amountY; iy ++) {
      positions[i + 1] = (Math.sin((ix + count) * 0.3) * 50) + (Math.sin((iy + count) * 0.5) * 50);

      scales[j] = (Math.sin((ix + count) * 0.3) + 1) * 7 + (Math.sin((iy + count) * 0.5) + 1) * 7;

      i += 3;
      j ++;
    }
  }

  particles.geometry.attributes.position.needsUpdate = true;
  particles.geometry.attributes.scale.needsUpdate = true;

  renderer.render(scene, camera);

  count += 0.011;
};

const animate = () => {
  requestAnimationFrame(animate);

  render();
};

init();
animate();

const moveCamera = () => {
  cameraPosition = 150;
};
body::after {
  content: '';
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 1000;
  background-image: url(https://res.cloudinary.com/axiol/image/upload/v1612477975/CodePen/noise.gif);
  opacity: 0.05;
  pointer-events: none;
}

canvas {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  display: none;
  z-index: -1;
}
<script src="https://unpkg.com/three@0.125.2/build/three.min.js"></script>
<script type="x-shader/x-vertex" id="vertexshader">
  attribute float scale;
  void main() {
    vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
    gl_PointSize = scale * (300.0 / - mvPosition.z);
    gl_Position = projectionMatrix * mvPosition;
  }
</script>

<script type="x-shader/x-fragment" id="fragmentshader">
  uniform vec3 color;
  void main() {
  if (length(gl_PointCoord - vec2(0.5, 0.5)) > 0.475 ) discard;
    gl_FragColor = vec4(color, 1.0);
  }
</script>

我真的不知道这可能来自哪里。在另一个测试中,我有同样的问题。但是在第二个上,画布正在对鼠标移动做出反应。并且当鼠标移动时,gif动画。但是一旦它停止,gif 就会停止。

有人看过吗?

【问题讨论】:

  • 看起来像是最近的回归,我无法在 macOs BigSur 上从当前稳定的 85.0.2 进行复制,但在我的夜间更新后它也卡住了(以前的版本是一个月大的)。如果我有时间,我会尝试进行平分,但目前你能确认你在哪个版本上进行了测试吗?还有一个 hackish 解决方法是强制每帧重绘:jsfiddle.net/qfrcm7db
  • @Kaiido 看起来你可能是对的。当前运行 86.0b9。但是如果我切换到当前的live版本(85.0.2),看起来就可以了

标签: javascript css canvas three.js


【解决方案1】:

这确实是最近(一周)的回归,显然是由this commit 引起的。
我确实打开了https://bugzilla.mozilla.org/1692736,希望他们能在它登陆稳定分支之前修复它。

您可以通过在您自己的 Firefox 中禁用 WebRender 来解决此错误,方法是转到 about:config,然后将 gfx.webrender.force-disabled 切换为 false,或者强制重新渲染 gif 被渲染的元素,例如通过CSS 动画中的最小不透明度变化:

const separation = 100, amountX = 70, amountY = 50;
let container, camera, scene, renderer, particles;
let count = 0, windowHalfX = window.innerWidth / 2, windowHalfY = window.innerHeight / 2, cameraPosition = 80;

const init = () => {
  container = document.createElement('div');
  document.body.appendChild(container);
  
  camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000);
  camera.position.x = cameraPosition;
  camera.position.y = 1000;
  camera.position.z = -550;
  camera.zoom = 1.2;
  
  scene = new THREE.Scene();
  
  const numParticles = amountX * amountY;
  const positions = new Float32Array(numParticles * 3);
  const scales = new Float32Array(numParticles);

  let i = 0, j = 0;
  
  for(let ix = 0; ix < amountX; ix++) {
    for(let iy = 0; iy < amountY; iy++) {
      positions[i] = ix * separation - ((amountX * separation ) / 2);
      positions[i + 1] = 0;
      positions[i + 2] = iy * separation - ((amountY * separation ) / 2);

      scales[j] = 1;

      i += 3;
      j ++;
    }
  }
  
  const geometry = new THREE.BufferGeometry();
  geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
  geometry.setAttribute('scale', new THREE.BufferAttribute(scales, 1));
  
  const material = new THREE.ShaderMaterial({
    uniforms: {
      color: {value: new THREE.Color(0xeae6c3)},
    },
    vertexShader: document.getElementById('vertexshader').textContent,
    fragmentShader: document.getElementById('fragmentshader').textContent,
  });
  
  particles = new THREE.Points(geometry, material);
  scene.add(particles);
  
  renderer = new THREE.WebGLRenderer({antialias: true});
  renderer.setClearColor(0x192735, 1);
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(window.innerWidth, window.innerHeight);
  container.appendChild(renderer.domElement);
  container.style.touchAction = 'none';
  
  window.addEventListener( 'resize', onWindowResize );
};

const onWindowResize = () => {
  windowHalfX = window.innerWidth / 2;
  windowHalfY = window.innerHeight / 2;

  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize( window.innerWidth, window.innerHeight );
};

const render = () => {
  camera.lookAt(scene.position);

  const positions = particles.geometry.attributes.position.array;
  const scales = particles.geometry.attributes.scale.array;

  let i = 0, j = 0;

  for (let ix = 0; ix < amountX; ix ++) {
    for (let iy = 0; iy < amountY; iy ++) {
      positions[i + 1] = (Math.sin((ix + count) * 0.3) * 50) + (Math.sin((iy + count) * 0.5) * 50);

      scales[j] = (Math.sin((ix + count) * 0.3) + 1) * 7 + (Math.sin((iy + count) * 0.5) + 1) * 7;

      i += 3;
      j ++;
    }
  }

  particles.geometry.attributes.position.needsUpdate = true;
  particles.geometry.attributes.scale.needsUpdate = true;

  renderer.render(scene, camera);

  count += 0.011;
};

const animate = () => {
  requestAnimationFrame(animate);

  render();
};

init();
animate();

const moveCamera = () => {
  cameraPosition = 150;
};
/*
  we animate a very small opacity variation
  to force rerendering of the gif image
*/
@keyframes bug1692736 { to { opacity: 0.051; } }
body::after {
  animation: bug1692736 10s infinite;
  content: '';
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 1000;
  background-image: url(https://res.cloudinary.com/axiol/image/upload/v1612477975/CodePen/noise.gif);
  opacity: 0.05;
  pointer-events: none;
}

canvas {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  display: none;
  z-index: -1;
}
<script src="https://unpkg.com/three@0.125.2/build/three.min.js"></script>
<script type="x-shader/x-vertex" id="vertexshader">
  attribute float scale;
  void main() {
    vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
    gl_PointSize = scale * (300.0 / - mvPosition.z);
    gl_Position = projectionMatrix * mvPosition;
  }
</script>

<script type="x-shader/x-fragment" id="fragmentshader">
  uniform vec3 color;
  void main() {
  if (length(gl_PointCoord - vec2(0.5, 0.5)) > 0.475 ) discard;
    gl_FragColor = vec4(color, 1.0);
  }
</script>

【讨论】:

  • 很好的解决方法,谢谢。不应该对性能很苛刻。我会关注那张票,再次感谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-19
  • 2013-03-08
  • 2016-03-24
  • 1970-01-01
  • 2013-05-21
  • 2012-04-14
相关资源
最近更新 更多