Safari requestAnimationFrame 以 30fps 运行

Dja*_*ave 5 safari three.js

我有一个移动和渲染飞机的基本场景。

  • Chrome 中的帧率为 120 fps
  • Safari 中的帧率为 30 fps

我怎样才能将它们标准化,并在两者上获得相似的性能,最好是达到 120fps 的速率?

Safari 的 30fps 给我的感觉就是杀手。

到目前为止,我已经尝试使用:

this.renderer = new THREE.WebGLRenderer({
  canvas: this.canvas,
  powerPreference: "high-performance",
});
Run Code Online (Sandbox Code Playgroud)

但该powerPreference属性似乎没有任何明显的区别,所以我认为这是requestAnimationFrame我需要修复的时间。

this.renderer = new THREE.WebGLRenderer({
  canvas: this.canvas,
  powerPreference: "high-performance",
});
Run Code Online (Sandbox Code Playgroud)
const mod = (k, n) => ((k %= n) < 0) ? k+n : k;
const lerp = (v0, v1, t) => (1 - t) * v0 + t * v1;
const fpsElem = document.querySelector("#fps");

const ThreeCarousel = {
  clock: new THREE.Clock(),
  sizes: {
    width: window.innerWidth,
    height: window.innerHeight
  },
  slideGap: 2,
  slides: [],
  cols: [
    0xC4E7D4,
    0x998DA0,
    0xC4DACF,
    0xB9C0DA,
    0x63585E,
  ],
  p: 0,
  targetP: 0,
  currentX: 0,
  dragReduce: 0.01,
  wheelReduce: 0.001,
  s: 0.01,
  slidePosition(i){
    const max = this.slides.length * this.slideGap;
    const p = mod(this.p + (i * this.slideGap), max)
    
    return p - max / 2;
    
  },
  addObjects() {
    for(var i = 0; i < 5; i++){
      // const geometry = new THREE.BoxGeometry(1, 1, 1);
      const geometry = new THREE.PlaneGeometry(1.1, 1.5);
      const material = new THREE.MeshBasicMaterial({ color: this.cols[i] });
      const mesh = new THREE.Mesh(geometry, material);
      mesh.position.x = this.slidePosition(i);
      this.slides.push(mesh);
      this.scene.add(mesh);
    }
  },
  addCamera() {
    this.camera = new THREE.PerspectiveCamera(
      75,
      this.sizes.width / this.sizes.height,
      0.1,
      100
    );
    this.camera.position.z = 3;
    this.scene.add(this.camera);
  },
  addRenderer() {
    this.renderer = new THREE.WebGLRenderer({
      canvas: this.canvas,
      powerPreference: "high-performance",
    });
    this.renderer.setSize(this.sizes.width, this.sizes.height);
    this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
  },
  addEvents(){
    window.addEventListener("resize", this.resize.bind(this));
    this.canvas.addEventListener("pointerdown", this.startDrag.bind(this));
    this.canvas.addEventListener("pointerup", this.stopDrag.bind(this));
    this.canvas.addEventListener("pointercancel", this.stopDrag.bind(this));
    this.canvas.addEventListener("pointerout", this.stopDrag.bind(this));
    this.canvas.addEventListener("pointermove", this.drag.bind(this));
    this.canvas.addEventListener("wheel", this.wheelDrag.bind(this));
  },
  startDrag(e){
    this.dragging = true;
    this.currentX = e.screenX;
  },
  stopDrag(e){
    this.dragging = false;
  },
  drag(e){
    if(!this.dragging){
      return;
    }
    this.targetP = this.targetP - (this.currentX - e.screenX) * this.dragReduce;
    this.currentX = e.screenX;
  }, 
  wheelDrag(e){
    if(Math.abs(e.deltaY) > Math.abs(e.deltaX)){
      return;
    }
    e.preventDefault();
    e.stopPropagation();
    this.targetP += e.deltaX * this.dragReduce * -1;
  },
  resize(){
    // Update sizes
    this.sizes.width = window.innerWidth;
    this.sizes.height = window.innerHeight;

    // Update camera
    this.camera.aspect = this.sizes.width / this.sizes.height;
    this.camera.updateProjectionMatrix();

    // Update renderer
    this.renderer.setSize(this.sizes.width, this.sizes.height);
    this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
  },
  init() {
    this.canvas = document.querySelector("canvas#carousel");
    this.scene = new THREE.Scene();
    this.addObjects();
    this.addCamera();
    this.addRenderer();
    this.addEvents();
    this.then = 0;

    const tick = (now) => {
      now *= 0.001;                          // convert to seconds
      const deltaTime = now - this.then;          // compute time since last frame
      this.then = now;                            // remember time for next frame
      const fps = 1 / deltaTime;             // compute frames per second
      fpsElem.textContent = fps.toFixed(1);  // update fps display
      this.p = lerp(this.p, this.targetP, 0.06);
      const elapsedTime = this.clock.getElapsedTime();
      this.slides.forEach((slide, i) => {
        slide.position.x = this.slidePosition(i);
        slide.rotation.y = (Math.PI / 30) * slide.position.x + Math.PI / 12;
      })
      this.renderer.render(this.scene, this.camera);
      window.requestAnimationFrame(tick);
    };

    tick();
  }
};

ThreeCarousel.init();
Run Code Online (Sandbox Code Playgroud)
html, body, canvas{
  height: 100%;
}

div{
  position: fixed;
  top: 0;
  left: 0;
  color: #fff;
}
Run Code Online (Sandbox Code Playgroud)

有一些关于限制帧速率和减慢帧速率的旧答案,但是在 Safari 上似乎没有任何 60fps 的工作。这是此处找到的演示之一的屏幕截图:

在此输入图像描述

Dja*_*ave 9

我很尴尬 \xe2\x80\x94\xc2\xa0 在“系统偏好设置”>“电池”>“电源适配器”中查看,发现选中了“低功耗模式”。取消选中此选项会给我带来完全不令人印象深刻但可以忍受的 60 fps。

\n

不确定我将如何检测其他客户端是否在此模式下运行以相应地更新我的应用程序,但必须找到解决方法。

\n

在此输入图像描述

\n

  • 问题与 JavaScript 函数“requestAnimationFrame”有关。答案展示了如何使该函数以 60fps 运行。 (5认同)
  • 我也明白你的观点,但是在找到(尽管非代码解决方案)之后,我认为它可能会帮助遇到相同问题的人。也许投反对票,我们就可以继续我们的生活了。 (5认同)