Reputation: 9329
I have a basic scene that moves and renders planes.
How can I normalise these, and get similar performance across both, ideally toward the 120fps rate?
The 30fps Safari is giving me is a killer.
So far, I have tried using:
this.renderer = new THREE.WebGLRenderer({
canvas: this.canvas,
powerPreference: "high-performance",
});
But the powerPreference
attribute doesn't seem to make any noticeable difference, so I think it is the requestAnimationFrame
timing that I need to fix.
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();
html, body, canvas{
height: 100%;
}
div{
position: fixed;
top: 0;
left: 0;
color: #fff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/0.145.0/three.min.js"></script>
<canvas id="carousel"></canvas>
<div>fps: <span id="fps"></span></div>
There are older answers about throttling framerates and slowing them down, however nothing seems to work at 60fps on Safari. Here is a screenshot of one of the demos found here:
Upvotes: 5
Views: 1941
Reputation: 9329
I'm embarrassed — looking in System Preferences > Battery > Power Adapter I found that Low Power Mode was checked. Unchecking this gives me a thoroughly unimpressive but bearable 60fps.
Not sure how I will detect if other clients are running in this mode to update my app accordingly, but will have to find a work around.
Upvotes: 10