The functionality of THREE.Clock
broke in release r74 when attempting to run in Node.js (installed via npm package 'three'). Functions like .start()
& .getDelta()
complain about ReferenceError: performance is not defined
(as in performance.now()
).
I might be missing something, but it would seem the changes in 71ddb80818c504028a0cd1dd4c61de0edaa237a8 removed the polyfill for performance.now
necessary to run THREE (Clock) in Node; as far as I can tell, Node.js doesn't have a global performance
implemented.
I am not sure if/how much issues #7787, or #7800 are involved.
Running w/ r74 (current broken state):
$ node
> var THREE = require('three');
undefined
> var myclock = new THREE.Clock();
undefined
> myclock.start()
ReferenceError: performance is not defined
at THREE.Clock.start (/data/users/rlinsalata/workspaces/js_ws/node_playground/node_modules/three/three.js:7911:20)
at repl:1:10
at REPLServer.self.eval (repl.js:110:21)
at Interface.<anonymous> (repl.js:239:12)
at Interface.EventEmitter.emit (events.js:95:17)
at Interface._onLine (readline.js:202:10)
at Interface._line (readline.js:531:8)
at Interface._ttyWrite (readline.js:760:14)
at ReadStream.onkeypress (readline.js:99:10)
at ReadStream.EventEmitter.emit (events.js:98:17)
> myclock.getDelta()
ReferenceError: performance is not defined
at THREE.Clock.start (/data/users/rlinsalata/workspaces/js_ws/node_playground/node_modules/three/three.js:7911:20)
at THREE.Clock.getDelta (/data/users/rlinsalata/workspaces/js_ws/node_playground/node_modules/three/three.js:7938:9)
at repl:1:10
at REPLServer.self.eval (repl.js:110:21)
at Interface.<anonymous> (repl.js:239:12)
at Interface.EventEmitter.emit (events.js:95:17)
at Interface._onLine (readline.js:202:10)
at Interface._line (readline.js:531:8)
at Interface._ttyWrite (readline.js:760:14)
at ReadStream.onkeypress (readline.js:99:10)
> THREE.REVISION
'74'
Running w/ r73 (old working state):
$ node
> var THREE = require('three');
> THREE.REVISION
'73'
> var myclock = new THREE.Clock();
> myclock.start()
> myclock.getDelta()
20.876
> myclock.getDelta()
1.437
> myclock.getDelta()
4.405
Version Info:
Three version r74
npm package 'three' [email protected]
Node v5.2.0
Ubuntu 14.04
Hmm, is using THREE.Clock a common thing on node.js? What's your use case?
Maybe a solution would be to add a polyfill for your project?
For me, not working on iOS8 based devices. I have added this r73 polyfill and works again:
//
if ( self.performance === undefined ) {
self.performance = {};
}
if ( self.performance.now === undefined ) {
( function () {
var start = Date.now();
self.performance.now = function () {
return Date.now() - start;
}
} )();
}
@rethink-rlinsalata As you can see here, the High Resolution Time API is widely supported in all major browsers. So it's of course comprehensible to remove the respective polyfill.
I would use in a node.js environment not a polyfill, but the more accurate process.hrtime() API. Check out the npm package present, which is built on top of process.hrtime
.
+1
THREE.Clock
doesn't work on iOS 8 (Chrome and Safari).
The way the values are currently being processed adds up numerical error.
I guess we might as well just use Date
.
0.001
is periodic in binary (check the bits here). This error can be minimized dividing by 1000
.
Further, the digits before the dot in elapsedTime
eat up precision the higher the value gets. I guess the performance.mark
method might be the intended way to avoid this problem.
I guess the performance.mark method might be the intended way to avoid this problem.
Good suggestion. I just wonder how performant is performance.mark
and performance.measure
when we use it in an animation loop. If we want to calculating the elapsed time with performance.measure
, we always need two marks. The API also recommends to clear obsolet marks and measures which are stored by the browser.
@Mugen87
I just wonder how performant is performance.mark and performance.measure when we use it in an animation loop.
Maybe we just shouldn't. Milliseconds are actually quite alright when it comes to timing animations.
The API is for benchmarking, for which we'd have to
random
all over the place, andin order to get reproducible results.
use a clock that can be switched to provide discrete time (based on a frame counter) for timing the effect
Sounds interesting. @tschw Do you know some references or examples about this topic? I would really like to learn something about this...
@tschw
use a clock that can be switched to provide discrete time (based on a frame counter) for timing the effect
@Mugen87
Sounds interesting. @tschw Do you know some references or examples about this topic? I would really like to learn something about this...
Not as much interesting as it sounds, I guess. I meant: Take a fixed start value and always increment the same constant every frame - just as you would do for rendering to a video file.
If you want to know how a particular, possibly small change affects the performance, you must have a bit of scale and make sure you always measure the same process.
I see! Things are more clear for me now. :+1:
Still this error. r84
@Mugen87 ( performance || Date ).now()
results to error in node.
( typeof performance === 'undefined' ? Date : performance ).now()
works.
https://github.com/mrdoob/three.js/blob/master/src/core/Clock.js#L23
@mrdoob I think we should implement @sasha240100 suggestion with a respective comment.
We use performance
only in these two lines in the entire three.js
core:
https://github.com/mrdoob/three.js/blob/master/src/core/Clock.js#L23
https://github.com/mrdoob/three.js/blob/master/src/core/Clock.js#L57
I was looking into this the other day - the equivalent to performance.now()
in node is process.hrtime()
. Unfortunately it returns an array [seconds, nanoseconds]
馃槖
Tween.js includes a polyfill. It's not that small though:
// Include a performance.now polyfill.
// In node.js, use process.hrtime.
if (typeof (window) === 'undefined' && typeof (process) !== 'undefined') {
TWEEN.now = function () {
var time = process.hrtime();
// Convert [seconds, nanoseconds] to milliseconds.
return time[0] * 1000 + time[1] / 1000000;
};
}
// In a browser, use window.performance.now if it is available.
else if (typeof (window) !== 'undefined' &&
window.performance !== undefined &&
window.performance.now !== undefined) {
// This must be bound, because directly assigning this function
// leads to an invocation exception in Chrome.
TWEEN.now = window.performance.now.bind(window.performance);
}
// Use Date.now if it is available.
else if (Date.now !== undefined) {
TWEEN.now = Date.now;
}
// Otherwise, use 'new Date().getTime()'.
else {
TWEEN.now = function () {
return new Date().getTime();
};
}
If we want the same level of accuracy as performance.now()
in node, we'll need something similar I guess. It's probably overkill though, this might be enough:
function now() {
if ( typeof (process) !== 'undefined' ) {
var time = process.hrtime();
// Convert [seconds, nanoseconds] to milliseconds.
return time[0] * 1000 + time[1] / 1000000;
}
return ( performance || Date ).now();
}
@Mugen87 I made a pull request #10732. Check please
Most helpful comment
+1
THREE.Clock
doesn't work on iOS 8 (Chrome and Safari).