Reduce "first render" lag? renderer.compileAsync() is not doing anything

In my scene, I have a a 16x16 grid of InstancedMeshes. Each InstancedMesh has about 10,000 instances of a single-polygon (3-vertex) geometry. Each single-polygon geometry instance represents a little tuft of grass, and is scattered randomly across each tile.

At any given time, around ~650,000 instances are visible in the camera frustum. I am using a tiled layout to help the renderer cull the non-visible InstancedMeshes, since each InstancedMesh is culled based on the collective bounding box of all its instances.

This is my attempt at foliage on an open-world terrain.

For the first few seconds after the scene loads, whenever I look around with the first-person camera, there is a lot of lag and stutter.

After the first few seconds, however, the FPS jumps up to normal levels (60fps+).

I tried using renderer.compileAsync() on each InstancedMesh to “precompile” the shaders, but that didn’t do anything.

Next, I tried using THREE.Points, and that worked really well (there was no “first render” lag)–except the size of each point is limited to 1 pixel :frowning:.

How can I eliminate this “first render” lag?

If all textures, models are loaded, then render once all meshes with frustumCulled=false, visible=true (all textures, geometries must be already loaded) and only then run project.
If you have got mesh which while not in scene, then render it separately like scene, but mesh.

function meshes_frustum_visible(item,mode){

if(mode==1){
item.traverse(function(child){
if(child.isMesh){
child.last_visible=child.visible;
child.visible=true;
child.last_frustumCulled=child.frustumCulled;
child.frustumCulled=false;
}
});
}
else{
item.traverse(function(child){
if(child.isMesh){
child.visible=child.last_visible;
child.frustumCulled=child.last_frustumCulled;
child.last_visible=undefined;
child.last_frustumCulled=undefined;
}
});
}

}

meshes_frustum_visible(scene,1);
renderer.render(scene,camera);
meshes_frustum_visible(scene,2);

meshes_frustum_visible(mesh_while_not_in_scene,1);
renderer.render(mesh_while_not_in_scene,camera);
meshes_frustum_visible(mesh_while_not_in_scene,2);

run_project();
5 Likes

Perfect! That worked–it got rid of all the “first render” lag. Thank you.

I modified it a bit:

function precompileAsync(renderer, scene, camera) {
    const visibleKey = crypto.randomUUID();
    const frustumCulledKey = crypto.randomUUID();
    const meshes = [];
    scene.traverse(o => {
		if (o.isMesh && (o.frustumCulled || !o.visible)) {
			o[visibleKey] = o.visible;
			o[frustumCulledKey] = o.frustumCulled;
			o.visible = true;
			o.frustumCulled = false;
			meshes.push(o);
		}
    });
    await renderer.renderAsync(scene, camera);
    for (const mesh of meshes) {
        mesh.visible = mesh[visibleKey];
        mesh.frustumCulled = mesh[frustumCulledKey];
        delete mesh[visibleKey];
        delete mesh[frustumCulledKey];
    }
}
2 Likes

I’ve wondered about this too… I’ve also seen compileAsync not really appear to do much.. I wonder if its also dependent on frustumCulled being false…

1 Like

compileAsync compiles all materials (shaders) in the given scene, maybe without geometry.
src\renderers\common\Renderer.js

Right.. that’s what it says.. but then why does it need the extra params like a camera and targetScene?

And it doesn’t seem to do whatever a pre-render with frustumculled false does…

I’m skeptical…

Maybe… its not shader compilation that is stuttering, but texture+geometry upload ?

texture and geometry compiles when use renderer.render(scene,camera);
Also can use renderer.initTexture(texture); , renderer.initRenderTarget(target);

Yeah. Just saying.. what a lot of people think is shader compilation stutter, is really only a small bit of the overall stutter caused by first texture+geometry uploads… maybe?

1 Like

it takes time to load into the video card memory both textures and geometry in the required form. for example, a texture weighs 4096*4096 weighs 1 MB and it is PNG, but in the video card it will be 88.08 MB. if its ktx format, then maybe less mb in videocard and time.

1 Like

The camera seems like it does nothing, it gets set in a render state but it doesnt seem the compilation really depends on it. Weird, i’d remove that argument.