Description
In src/nodes/core/NodeUtils.js, hash is defined as a variadic function:
|
/** |
|
* Computes a hash for the given list of parameters. |
|
* |
|
* @private |
|
* @method |
|
* @param {...number} params - A list of parameters. |
|
* @return {number} The hash. |
|
*/ |
|
export const hash = ( ...params ) => cyrb53( params ); |
Because it's variadic, every time it's called, it allocates an array to hold the arguments in params.
The problem is that this function is called at least once for every Mesh in a scene for each render inside RenderObject.getDynamicCacheKey(), and twice if receiveShadow = true.
For a three.js scene with 1,000 meshes being rendered at 120 frames per second, this results in 120,000 arrays being allocated per second. With receiveShadow = true, that's 240,000 arrays per second, not a small number.
You can see this repeated allocation happening at runtime if you run a performance analysis and look at the call stack:
_renderObjectDirect → get → needsUpdate → getDynamicCacheKey → hash$1 → NewDenseFullyAllocatedArray
The following method should be changed to use a pre-allocated scratch array, and pass that to hashArray() instead of hash() so no temporary arrays are allocated.
|
/** |
|
* Returns the dynamic cache key which represents a key that is computed per draw command. |
|
* |
|
* @return {number} The cache key. |
|
*/ |
|
getDynamicCacheKey() { |
|
|
|
let cacheKey = 0; |
|
|
|
// `Nodes.getCacheKey()` returns an environment cache key which is not relevant when |
|
// the renderer is inside a shadow pass. |
|
|
|
if ( this.material.isShadowPassMaterial !== true ) { |
|
|
|
cacheKey = this._nodes.getCacheKey( this.scene, this.lightsNode ); |
|
|
|
} |
|
|
|
if ( this.camera.isArrayCamera ) { |
|
|
|
cacheKey = hash( cacheKey, this.camera.cameras.length ); |
|
|
|
} |
|
|
|
if ( this.object.receiveShadow ) { |
|
|
|
cacheKey = hash( cacheKey, 1 ); |
|
|
|
} |
|
|
|
cacheKey = hash( cacheKey, this.renderer.contextNode.id, this.renderer.contextNode.version ); |
|
|
|
return cacheKey; |
|
|
|
} |
Version
r186
Description
In
src/nodes/core/NodeUtils.js,hashis defined as a variadic function:three.js/src/nodes/core/NodeUtils.js
Lines 86 to 94 in 5c5a575
Because it's variadic, every time it's called, it allocates an array to hold the arguments in
params.The problem is that this function is called at least once for every
Meshin a scene for each render insideRenderObject.getDynamicCacheKey(), and twice ifreceiveShadow = true.For a three.js scene with 1,000 meshes being rendered at 120 frames per second, this results in 120,000 arrays being allocated per second. With
receiveShadow = true, that's 240,000 arrays per second, not a small number.You can see this repeated allocation happening at runtime if you run a performance analysis and look at the call stack:
The following method should be changed to use a pre-allocated scratch array, and pass that to
hashArray()instead ofhash()so no temporary arrays are allocated.three.js/src/renderers/common/RenderObject.js
Lines 921 to 955 in 5c5a575
Version
r186