Skip to main content
added 26 characters in body
Source Link
user3163495
  • 4k
  • 5
  • 39
  • 59

Calling renderer.render() in a requestAnimationFrame() loop will often fire faster than the <canvas> element can update its image, making any "true" FPS measurement inaccurate.

In three.js, how can I block each iteration long enough to let the <canvas> update its image?

For example, let's say you have a laggy three.js scene where you are also displaying the frame number in an HTML element on your page. If you record your screen at a high capture rate (~120Hz), you will notice that the frame number displayed in the HTML element will "skip" a frame or two occasionally, which artificially inflates FPS measurements. For example, between only two unique images in the canvas, the frame number would go from 1,340 to 1,343, essentially skipping 2 frames.

It appears that my requestAnimationFrame() loop is firing faster than the browser can repaint the <canvas> and all the other elements on the page. I have already tried all sorts of "hacks", including the following:

  1. 🤔 Connecting the <canvas> to a <video> element to take advantage of video.requestVideoFrameCallback(callback). This is the only one that stopped the skipped frames, but it introduced a much worse lag that outweighed the benefits.
  2. ❌ Doing this (using MessageChannel): https://webperf.tips/tip/measuring-paint-time (did nothing)
  3. ❌ Doing this: requestAnimationFrame(() => requestAnimationFrame(callback)) (did nothing)

So is there any way I can reliably block each iteration of requestAnimationFrame() to give the canvas (and all the elements on the page) enough time to repaint? This would allow me to get a "true" FPS measurement of the actual frames that were visible on screen.

Here is a JSFiddle demonstrating a laggy scene that prints out the FPS based on a requestAnimationFrame() loop. Just increase the number of instances for this InstancedMesh on this line to something that starts lagging your scene:

const mesh = new THREE.InstancedMesh(geometry, material, 100);

Next, record your screen at a high capture rate and rapidly rotate the camera around. You will notice the frame number skips a frame occasionally.

https://jsfiddle.net/ekypq94d

Here is a small recording of the frame number. Notice how frames 1022 and 1029 are skipped (Chrome was used to test):

enter image description hereenter image description here

Calling renderer.render() in a requestAnimationFrame() loop will often fire faster than the <canvas> element can update its image, making any "true" FPS measurement inaccurate.

In three.js, how can I block each iteration long enough to let the <canvas> update its image?

For example, let's say you have a laggy three.js scene where you are also displaying the frame number in an HTML element on your page. If you record your screen at a high capture rate (~120Hz), you will notice that the frame number displayed in the HTML element will "skip" a frame or two occasionally, which artificially inflates FPS measurements. For example, between only two unique images in the canvas, the frame number would go from 1,340 to 1,343, essentially skipping 2 frames.

It appears that my requestAnimationFrame() loop is firing faster than the browser can repaint the <canvas> and all the other elements on the page. I have already tried all sorts of "hacks", including the following:

  1. 🤔 Connecting the <canvas> to a <video> element to take advantage of video.requestVideoFrameCallback(callback). This is the only one that stopped the skipped frames, but it introduced a much worse lag that outweighed the benefits.
  2. ❌ Doing this (using MessageChannel): https://webperf.tips/tip/measuring-paint-time (did nothing)
  3. ❌ Doing this: requestAnimationFrame(() => requestAnimationFrame(callback)) (did nothing)

So is there any way I can reliably block each iteration of requestAnimationFrame() to give the canvas (and all the elements on the page) enough time to repaint? This would allow me to get a "true" FPS measurement of the actual frames that were visible on screen.

Here is a JSFiddle demonstrating a laggy scene that prints out the FPS based on a requestAnimationFrame() loop. Just increase the number of instances for this InstancedMesh on this line to something that starts lagging your scene:

const mesh = new THREE.InstancedMesh(geometry, material, 100);

Next, record your screen at a high capture rate and rapidly rotate the camera around. You will notice the frame number skips a frame occasionally.

https://jsfiddle.net/ekypq94d

Here is a small recording of the frame number. Notice how frames 1022 and 1029 are skipped:

enter image description here

Calling renderer.render() in a requestAnimationFrame() loop will often fire faster than the <canvas> element can update its image, making any "true" FPS measurement inaccurate.

In three.js, how can I block each iteration long enough to let the <canvas> update its image?

For example, let's say you have a laggy three.js scene where you are also displaying the frame number in an HTML element on your page. If you record your screen at a high capture rate (~120Hz), you will notice that the frame number displayed in the HTML element will "skip" a frame or two occasionally, which artificially inflates FPS measurements. For example, between only two unique images in the canvas, the frame number would go from 1,340 to 1,343, essentially skipping 2 frames.

It appears that my requestAnimationFrame() loop is firing faster than the browser can repaint the <canvas> and all the other elements on the page. I have already tried all sorts of "hacks", including the following:

  1. 🤔 Connecting the <canvas> to a <video> element to take advantage of video.requestVideoFrameCallback(callback). This is the only one that stopped the skipped frames, but it introduced a much worse lag that outweighed the benefits.
  2. ❌ Doing this (using MessageChannel): https://webperf.tips/tip/measuring-paint-time (did nothing)
  3. ❌ Doing this: requestAnimationFrame(() => requestAnimationFrame(callback)) (did nothing)

So is there any way I can reliably block each iteration of requestAnimationFrame() to give the canvas (and all the elements on the page) enough time to repaint? This would allow me to get a "true" FPS measurement of the actual frames that were visible on screen.

Here is a JSFiddle demonstrating a laggy scene that prints out the FPS based on a requestAnimationFrame() loop. Just increase the number of instances for this InstancedMesh on this line to something that starts lagging your scene:

const mesh = new THREE.InstancedMesh(geometry, material, 100);

Next, record your screen at a high capture rate and rapidly rotate the camera around. You will notice the frame number skips a frame occasionally.

https://jsfiddle.net/ekypq94d

Here is a small recording of the frame number. Notice how frames 1022 and 1029 are skipped (Chrome was used to test):

enter image description here

added 489 characters in body
Source Link
user3163495
  • 4k
  • 5
  • 39
  • 59

Calling renderer.render() in a requestAnimationFrame() loop will often fire faster than the <canvas> element can update its image, making any "true" FPS measurement inaccurate.

In three.js, how can I block each iteration long enough to let the <canvas> update its image?

For example, let's say you have a laggy three.js scene where you are also displaying the frame number in an HTML element on your page. If you record your screen at a high capture rate (~120Hz), you will notice that the frame number displayed in the HTML element will "skip" a frame or two occasionally, which artificially inflates FPS measurements. For example, between only two unique images in the canvas, the frame number would go from 1,340 to 1,343, essentially skipping 2 frames.

It appears that my requestAnimationFrame() loop is firing faster than the browser can repaint the <canvas> and all the other elements on the page. I have already tried all sorts of "hacks", including the following:

  1. 🤔 Connecting the <canvas> to a <video> element to take advantage of video.requestVideoFrameCallback(callback). This is the only one that stopped the skipped frames, but it introduced a much worse lag that outweighed the benefits.
  2. ❌ Doing this (using MessageChannel): https://webperf.tips/tip/measuring-paint-time (did nothing)
  3. ❌ Doing this: requestAnimationFrame(() => requestAnimationFrame(callback)) (did nothing)

So is there any way I can reliably block each iteration of requestAnimationFrame() to give the canvas (and all the elements on the page) enough time to repaint? This would allow me to get a "true" FPS measurement of the actual frames that were visible on screen.

Here is a JSFiddle demonstrating a laggy scene that prints out the FPS based on a requestAnimationFrame() loop. Just increase the number of instances for this InstancedMesh on this line to something that starts lagging your scene:

const mesh = new THREE.InstancedMesh(geometry, material, 100);

Next, record your screen at a high capture rate and rapidly rotate the camera around. You will notice the frame number skips a frame occasionally.

https://jsfiddle.net/ekypq94d

Here is a small recording of the frame number. Notice how frames 1022 and 1029 are skipped:

enter image description here

Calling renderer.render() in a requestAnimationFrame() loop will often fire faster than the <canvas> element can update its image, making any "true" FPS measurement inaccurate.

In three.js, how can I block each iteration long enough to let the <canvas> update its image?

For example, let's say you have a laggy three.js scene where you are also displaying the frame number in an HTML element on your page. If you record your screen at a high capture rate (~120Hz), you will notice that the frame number displayed in the HTML element will "skip" a frame or two occasionally, which artificially inflates FPS measurements. For example, between only two unique images in the canvas, the frame number would go from 1,340 to 1,343, essentially skipping 2 frames.

It appears that my requestAnimationFrame() loop is firing faster than the browser can repaint the <canvas> and all the other elements on the page. I have already tried all sorts of "hacks", including the following:

  1. 🤔 Connecting the <canvas> to a <video> element to take advantage of video.requestVideoFrameCallback(callback). This is the only one that stopped the skipped frames, but it introduced a much worse lag that outweighed the benefits.
  2. ❌ Doing this (using MessageChannel): https://webperf.tips/tip/measuring-paint-time (did nothing)
  3. ❌ Doing this: requestAnimationFrame(() => requestAnimationFrame(callback)) (did nothing)

So is there any way I can reliably block each iteration of requestAnimationFrame() to give the canvas (and all the elements on the page) enough time to repaint? This would allow me to get a "true" FPS measurement of the actual frames that were visible on screen.

Here is a JSFiddle demonstrating a laggy scene that prints out the FPS based on a requestAnimationFrame() loop. Just increase the number of instances for this InstancedMesh on this line to something that starts lagging your scene:

const mesh = new THREE.InstancedMesh(geometry, material, 100);

Next, record your screen at a high capture rate and rapidly rotate the camera around. You will notice the frame number skips a frame occasionally.

https://jsfiddle.net/ekypq94d

Calling renderer.render() in a requestAnimationFrame() loop will often fire faster than the <canvas> element can update its image, making any "true" FPS measurement inaccurate.

In three.js, how can I block each iteration long enough to let the <canvas> update its image?

For example, let's say you have a laggy three.js scene where you are also displaying the frame number in an HTML element on your page. If you record your screen at a high capture rate (~120Hz), you will notice that the frame number displayed in the HTML element will "skip" a frame or two occasionally, which artificially inflates FPS measurements. For example, between only two unique images in the canvas, the frame number would go from 1,340 to 1,343, essentially skipping 2 frames.

It appears that my requestAnimationFrame() loop is firing faster than the browser can repaint the <canvas> and all the other elements on the page. I have already tried all sorts of "hacks", including the following:

  1. 🤔 Connecting the <canvas> to a <video> element to take advantage of video.requestVideoFrameCallback(callback). This is the only one that stopped the skipped frames, but it introduced a much worse lag that outweighed the benefits.
  2. ❌ Doing this (using MessageChannel): https://webperf.tips/tip/measuring-paint-time (did nothing)
  3. ❌ Doing this: requestAnimationFrame(() => requestAnimationFrame(callback)) (did nothing)

So is there any way I can reliably block each iteration of requestAnimationFrame() to give the canvas (and all the elements on the page) enough time to repaint? This would allow me to get a "true" FPS measurement of the actual frames that were visible on screen.

Here is a JSFiddle demonstrating a laggy scene that prints out the FPS based on a requestAnimationFrame() loop. Just increase the number of instances for this InstancedMesh on this line to something that starts lagging your scene:

const mesh = new THREE.InstancedMesh(geometry, material, 100);

Next, record your screen at a high capture rate and rapidly rotate the camera around. You will notice the frame number skips a frame occasionally.

https://jsfiddle.net/ekypq94d

Here is a small recording of the frame number. Notice how frames 1022 and 1029 are skipped:

enter image description here

added 489 characters in body
Source Link
user3163495
  • 4k
  • 5
  • 39
  • 59

Calling renderer.render() in a requestAnimationFrame() loop will often fire faster than the <canvas> element can update its image, making any "true" FPS measurement inaccurate.

In three.js, how can I block each iteration long enough to let the <canvas> update its image?

For example, let's say you have a laggy three.js scene where you are also displaying the frame number in an HTML element on your page. If you record your screen at a high capture rate (~120Hz), you will notice that the frame number displayed in the HTML element will "skip" a frame or two occasionally, which artificially inflates FPS measurements. For example, between only two unique images in the canvas, the frame number would go from 1,340 to 1,343, essentially skipping 2 frames.

It appears that my requestAnimationFrame() loop is firing faster than the browser can repaint the <canvas> and all the other elements on the page. I have already tried all sorts of "hacks", including the following:

  1. 🤔 Connecting the <canvas> to a <video> element to take advantage of video.requestVideoFrameCallback(callback). This is the only one that stopped the skipped frames, but it introduced a much worse lag that outweighed the benefits.
  2. ❌ Doing this (using MessageChannel): https://webperf.tips/tip/measuring-paint-time (did nothing)
  3. ❌ Doing this: requestAnimationFrame(() => requestAnimationFrame(callback)) (did nothing)

So is there any way I can reliably block each iteration of requestAnimationFrame() to give the canvas (and all the elements on the page) enough time to repaint? This would allow me to get a "true" FPS measurement of the actual frames that were visible on screen.

Here is a JSFiddle demonstrating a laggy scene that prints out the FPS based on a requestAnimationFrame() loop. Just increase the number of instances for this InstancedMesh on this line to something that starts lagging your scene:

const mesh = new THREE.InstancedMesh(geometry, material, 100);

Next, record your screen at a high capture rate and rapidly rotate the camera around. You will notice the frame number skips a frame occasionally.

https://jsfiddle.net/ekypq94d

Calling renderer.render() in a requestAnimationFrame() loop will often fire faster than the <canvas> element can update its image, making any "true" FPS measurement inaccurate.

In three.js, how can I block each iteration long enough to let the <canvas> update its image?

For example, let's say you have a laggy three.js scene where you are also displaying the frame number in an HTML element on your page. If you record your screen at a high capture rate (~120Hz), you will notice that the frame number displayed in the HTML element will "skip" a frame or two occasionally, which artificially inflates FPS measurements. For example, between only two unique images in the canvas, the frame number would go from 1,340 to 1,343, essentially skipping 2 frames.

It appears that my requestAnimationFrame() loop is firing faster than the browser can repaint the <canvas> and all the other elements on the page. I have already tried all sorts of "hacks", including the following:

  1. 🤔 Connecting the <canvas> to a <video> element to take advantage of video.requestVideoFrameCallback(callback). This is the only one that stopped the skipped frames, but it introduced a much worse lag that outweighed the benefits.
  2. ❌ Doing this (using MessageChannel): https://webperf.tips/tip/measuring-paint-time (did nothing)
  3. ❌ Doing this: requestAnimationFrame(() => requestAnimationFrame(callback)) (did nothing)

So is there any way I can reliably block each iteration of requestAnimationFrame() to give the canvas (and all the elements on the page) enough time to repaint? This would allow me to get a "true" FPS measurement of the actual frames that were visible on screen.

Calling renderer.render() in a requestAnimationFrame() loop will often fire faster than the <canvas> element can update its image, making any "true" FPS measurement inaccurate.

In three.js, how can I block each iteration long enough to let the <canvas> update its image?

For example, let's say you have a laggy three.js scene where you are also displaying the frame number in an HTML element on your page. If you record your screen at a high capture rate (~120Hz), you will notice that the frame number displayed in the HTML element will "skip" a frame or two occasionally, which artificially inflates FPS measurements. For example, between only two unique images in the canvas, the frame number would go from 1,340 to 1,343, essentially skipping 2 frames.

It appears that my requestAnimationFrame() loop is firing faster than the browser can repaint the <canvas> and all the other elements on the page. I have already tried all sorts of "hacks", including the following:

  1. 🤔 Connecting the <canvas> to a <video> element to take advantage of video.requestVideoFrameCallback(callback). This is the only one that stopped the skipped frames, but it introduced a much worse lag that outweighed the benefits.
  2. ❌ Doing this (using MessageChannel): https://webperf.tips/tip/measuring-paint-time (did nothing)
  3. ❌ Doing this: requestAnimationFrame(() => requestAnimationFrame(callback)) (did nothing)

So is there any way I can reliably block each iteration of requestAnimationFrame() to give the canvas (and all the elements on the page) enough time to repaint? This would allow me to get a "true" FPS measurement of the actual frames that were visible on screen.

Here is a JSFiddle demonstrating a laggy scene that prints out the FPS based on a requestAnimationFrame() loop. Just increase the number of instances for this InstancedMesh on this line to something that starts lagging your scene:

const mesh = new THREE.InstancedMesh(geometry, material, 100);

Next, record your screen at a high capture rate and rapidly rotate the camera around. You will notice the frame number skips a frame occasionally.

https://jsfiddle.net/ekypq94d

edited body
Source Link
user3163495
  • 4k
  • 5
  • 39
  • 59
Loading
Source Link
user3163495
  • 4k
  • 5
  • 39
  • 59
Loading