Gif不能在Firefox上播放canvas动画



我在Firefox上有这个奇怪的bug,当有画布动画时,用作背景图像的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就停止了。

有人看过了吗?

这确实是最近(一周)的回归,显然是由这个提交引起的。
我打开了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>

最新更新