BabarJulien Posted September 7, 2018 Share Posted September 7, 2018 I've been doing some profiling while creating a pretty large number of objects in the scene, mainly LinesMeshes and some Planes with DynamicTextures to draw 2d Text. It seems that there are a few places where we perform O(n) search or iteration that causes creation time to grow linearly with the number of already existing objects. examples : - when adding a Mesh to the scene public getGeometryByID(id: string): Nullable<Geometry> { for (var index = 0; index < this.geometries.length; index++) { if (this.geometries[index].id === id) { return this.geometries[index]; } } return null; } => keeping up-to-date a map Id to Geometry could fix this. - when updating the world matrix for (var mesh of this.getScene().meshes) { if (!mesh.subMeshes) { continue; } for (var subMesh of mesh.subMeshes) { if (subMesh.getMaterial() !== this) { continue; } if (!subMesh._materialDefines) { continue; } func(subMesh._materialDefines); } } (first note : I'm not expert in Javascript VM JItter, but it might be worth storing this.getScene().meshes in a local variable to prevent a call to getScene at each iteration). If possible, adding the info in the Mesh whether all subMeshes have been already made dirty might prevent this code from browsing all the subMeshes several times Whe checking the callstack, I get into that code from TransformNode.computeWordMatrix which is called each time a mesh is created, and each time I manually call computeWorldMatrix in case the parenting did change (I want the world bounding box), and also each time I set DynamicTexture's hasAlpha to true (to draw 2D text). Also, I spend some time cloning LinesMesh since it does not support createInstance yet, it would be great to add this ! ? Please let me know if there are existing ways to prevent all those redundant computation to happen. For you info, I'm adding a lot of objects between two frames (I mean, between two calls to scene.render()) JackFalcon 1 Quote Link to comment Share on other sites More sharing options...
JCPalmer Posted September 7, 2018 Share Posted September 7, 2018 I am not sure how much the getGeometryByID() change would help, because I do not even see getGeometryByID(), broken out in your profile data. I assume it is somewhere in Scene.pushGeometry(). Scene.pushGeometry(), along with the 2 functions broken out inside it, have a really high % of self time to total time. Does not leave a huge amount for getGeometryById(). The doubly nested loops are usually places which merit looking at. In another lifetime, I used a language with line level profiling, APL. Function level just kind of sucks. In this case though, the number of meshes which have multimaterials is small, so the inner loop is usually only called once. Something like this might be good from a es6 standpoint, but I have my doubts it will change performance a lot. const meshes = this.getScene().meshes; for (const mesh of meshes) { ... } In the case of LineMeshes, it is using a shaderMaterial, so that would have to be changed. Changing LinesMesh to use a StandardMaterial was talked about before. I was initially sub-classing LinesMesh for Hair, but I eventually gave up in favor of Mesh due to lack of thickness control. Do not remember what was said, but searching 'Hair LinesMesh' may be helpful. JackFalcon 1 Quote Link to comment Share on other sites More sharing options...
Guest Posted September 7, 2018 Share Posted September 7, 2018 Hello Julien! These are good findings. You will feel our struggle regarding optimization soon Here for instance, if we want to optimize the getGeometryByID we need to sacrifice on memory footprint and then other users will complain that they are not using this function a lot so they do not want to pay the price you ask them to pay :). Here I will probably suggest that you override the function to make it closer to your needs directly For the getScene, this is the magic of TypeScript. Here is the code generated: Material.prototype._markAllSubMeshesAsDirty = function (func) { for (var _i = 0, _a = this.getScene().meshes; _i < _a.length; _i++) { var mesh = _a[_i]; if (!mesh.subMeshes) { continue; } for (var _b = 0, _c = mesh.subMeshes; _b < _c.length; _b++) { var subMesh = _c[_b]; if (subMesh.getMaterial() !== this) { continue; } if (!subMesh._materialDefines) { continue; } func(subMesh._materialDefines); } } }; You can see that the getScene is actually called once ComputeWorldMatrix is a complex beast. It is full of caching to make sure the cost is controlled but it needs to be called when you need it You can always call mesh.freezeWorldMatrix() to annihilate its cost Hope this helps! JackFalcon 1 Quote Link to comment Share on other sites More sharing options...
JCPalmer Posted September 7, 2018 Share Posted September 7, 2018 So when setting to transpile to es6, would this still occur? The reason I ask is, for..of is not in es5, once transpiling for es6 there is not a reason to change anything. Seems like that was not the purpose of Typescript. Quote Link to comment Share on other sites More sharing options...
Guest Posted September 7, 2018 Share Posted September 7, 2018 Well good question. I don't know to be fair Quote Link to comment Share on other sites More sharing options...
JCPalmer Posted September 7, 2018 Share Posted September 7, 2018 The only way I can think of for doing this for es5 transpile is: that the spec for es6 says the expression after the 'of' is only evaluated once. That makes sense, you do not want code being written where something in the loop changes the number of items of the expression. If not then the es5 code is a bug, for 2 reasons: The function only runs once & es6 code runs every time As stupid as it would be to do, just calling it had some side-effect Quote Link to comment Share on other sites More sharing options...
Guest Posted September 7, 2018 Share Posted September 7, 2018 agree. So the code can stay as-is Quote Link to comment Share on other sites More sharing options...
BabarJulien Posted September 13, 2018 Author Share Posted September 13, 2018 Hi @Deltakosh I have much more performance troubles when set the alpha property of a lot of Dynamic Textures (to draw 2d text) : Do you know if this kind of issue is being tackled in the WIP performance improvement you mentioned ? If not, is there a way to work around that ? (I'd like to avoid having a modified version of babylon). Thanks Julien Quote Link to comment Share on other sites More sharing options...
Guest Posted September 14, 2018 Share Posted September 14, 2018 Yes there is a way just call scene.blockMaterialDirtyMechanism = true before updating all your textures and reset it to false afterwards BabarJulien 1 Quote Link to comment Share on other sites More sharing options...
BabarJulien Posted September 14, 2018 Author Share Posted September 14, 2018 ok, thanks @Deltakosh! Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.