Large lag when an object appears in the view

Dear all,
I have an application based on Three.js that loads/unloads objects in the world (for LOD, streaming and various other reasons). I made my best to avoid lags while the user is navigating the scene for example using web workers to download the new objects (i.e., the WWOBJLoader2).
What I found out is that, despite of this, there is a large lag when a new object first appears in the view (not when it is loaded in memory by the Loader). My question is: does threejs send the object (and its texture) to the graphic card when it first appears in the scene? Is it that lag that I am experiencing? Is it something related to the geometry, the texture, some processing or…?
Is there any way to avoid this lag?
When I say “lag” I mean that it freezes the controller (and it is very annoying for the user).
Thanks!

I dont really know, but if the object has a lot of children, i fought this by limiting the amout of children displayed… in the end to looked real bad.

It shouldn’t be my case: I have a very flat arrangement, every object is a child of the root and there are 60 objects in the scene (each one with its texture). The whole scene contains about 3 millions vertices and 1 million faces.

Yes, assuming you’ve never used the corresponding material and texture before. The compilation of the shader program takes some times, also the texture decode and upload. The resulting lag is in general visible for the user since the corresponding frame time is comparatively long.

You can try to use WebGLRenderer.compile in order to improve your performance. But this only works if your materials are already part of the scene.

I should probably open another question and not revive this topic. But just to clarify, is it as easy as scene.add(material) to ‘pre-add’ the material that will/may be needed and then retrieve it when I create the mesh var mesh = new THREE.Mesh( geometry, scene.getObjectByName(object.name); where object.name is the name of the material. Or would that be nonsense and bad for performance?

Pretty sure you can only add an Object3D to a scene and not a material directly. You probably could create a Mesh or something and assign it your material and add the mesh to the scene. This may not work though as it will still need to be in camera frustum to push to gpu. There probably (hopefully) is a better way to do this as I too would like to just push everything at once to the gpu and avoid this lag when the scene is initially complete.

Maybe disable frustum culling on all objects for their first frame? Not sure if that would work.

Just to clarify, you can’t add a material directly to the scene graph. It has to be a property of a 3D object like a mesh.

That does only work if the object is part of the scene graph. In this case, I would use WebGLRenderer.compile().

I tried WebGLRenderer.compile() but it kept crashing my app for some reason.

This is what I am using now:

this.mesh.frustumCulled = false;

var self = this;

this.mesh.onAfterRender = function(){
	
	self.renderCount++;
	
	if( self.renderCount >= 1 && !self.mesh.frustumCulled ){
		
		self.mesh.frustumCulled = true;
		
	}
	
};

this being an object that I assign the mesh itself to in this case. But as Mugen87 mentioned, if the object is dynamically added to the scene at runtime with materials/attributes that have not yet been passed to the gpu, you will get some lag as it loads regardless if its in view or not.

Not a perfect solution, but I am happy with it.

1 Like

Updated to this:

mesh.frustumCulled = false;

mesh.onAfterRender = function(){
	
	mesh.frustumCulled = true;
	
	mesh.onAfterRender = function(){};
	
};
4 Likes

Did you ever solve this problem?

Precompiling works fine to avoid huge compilation delays, if there is a big streamed load it can be processed in steps such as 1 material per frame. For progressive loading of assets i start this process before the objects are in visible range (while being a billboard).

If you don’t use a LOD based streaming you could assign a placeholder material while in progress if stable framerate is priority.

Other things can contribute to a delay at first frame as well, such as non-power of 2 textures which get resized.

1 Like

Ahhhhh very nice, I do have MANY warnings about this. Will optimize that.

So are you saying, I should really load all assets in at the start? Kinda sucks because I want like 10,000 assets. This is why I wanted it on the fly.

Only for a reasonable amout of assets like in a typical smaller game map, not like a open world game with a huge map of course.

As mentioned i stream assets too, and it is important to make sure your asset actually come as buffer geometry. Like with textures, if they are a regular THREE.Geometry they will get converted before upload. Material programs only might get a problem if you have complex shaders or a huge set of different shader codes. If you expect a lot (like 20-60 or more) to drop in within a single frame and you experience a huge frame drop you can distribute the payload across mutliple frames.

I had this issue happening when setting my object visibility from false to true for the first time.

None of the solutions I found online to fix this worked for me, but I did figure out a hack which was setting the scale of my object to 0, and then setting it to its intended scale when I needed it visible on screen.

This is working I’m guessing because even if its scale 0, it’s still considered part of the view and loaded on the GPU?

:open_mouth: that is a really smart hack!
Yes, I guess it is because what takes time is to load the object into the GPU. But I do not see this issue in many other engines (e.g. Ogre3D), so it is something related to Three.js or to Javascript.

1 Like

I have the same problem here… When i add a new model/object with a lot of children & faces etc. I have a lag while adding the object, it is not possible to load step by step a GLB model and add it also instead of loading & adding everyhing once?

1 Like