Gif 不在 Firefox 上播放画布动画

时间:2021-02-14 00:31:48

标签: javascript css canvas three.js

我在 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 就会停止。

有人已经看过了吗?

1 个答案:

答案 0 :(得分: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>