Help to understand the Three.JS LOD - Level of Details

Hey, there. I’ve started learning some advanced concepts of three.js in which LOD - level of details is the one, but I’m having some issues and need some help on that.

I’m using one gltf model of the city from sketchfeb and trying to achieve lazy loading of buildings while we zoom in/out or move/drag the model. Here is the code: -

let scene: Scene, camera: PerspectiveCamera, renderer:WebGLRenderer, controls:OrbitControls;
const loader = new GLTFLoader();
const loadGLTF = () => {
    loader.load('../assets/models/city_paris/scene.gltf', async(gltf: GLTF) => {        
        console.log(gltf);       
        scene.add( gltf.scene );      
        scene.animations = gltf.animations;
        scene.traverse(function(obj:any) {                      
            if(obj.isMesh){
                const lod = new LOD();
                var geometry = obj.geometry;
                var material = obj.material;
                var mesh = new Mesh(geometry, material);                
                lod.addLevel(mesh, 75);      
                lod.updateMatrix();
                lod.matrixAutoUpdate = false;
                scene.add( lod );
            }
        })
        animate();        
    }, undefined, (error:any) => console.log(error))    
}

const animate = () => {
    requestAnimationFrame( animate );
    controls.update();  
    renderer.render( scene, camera );
}

const init = () => {

    scene = new Scene();
    scene.background = new Color( 0x000000 );
    camera = new PerspectiveCamera(75, 2, 0.1, 1000 );
    camera.position.y = 3;
    camera.position.z = -7;

    const light: AmbientLight = new AmbientLight(0xFFFFFF, 1);
    scene.add(light)

    const dirLight = new DirectionalLight(0xFFFDDA, 1); 
    scene.add(dirLight);

    const pointlight:PointLight = new PointLight(0xFFFFFF, 267.9, 3.88);   
    scene.add(pointlight);

    renderer = new WebGLRenderer({antialias: false});
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize( window.innerWidth, window.innerHeight );
    renderer.outputEncoding = sRGBEncoding;
    renderer.physicallyCorrectLights = true;
    const element = document.getElementById('threejs-container') as HTMLDivElement;
    element.appendChild( renderer.domElement );
    
    controls = new OrbitControls( camera, renderer.domElement );    
    controls.target.set( 0, 0, 0 );
    controls.enableDamping = true;
    controls.dampingFactor = 0.05;    
    
    controls.update();
    loadGLTF();    
}

window.addEventListener('resize', function() {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);    
});


init();

But, my model looks like this -

I think the LOD’s configurations create a copy of the model on the left side of the model. LOD seems to be working, but not sure if is it correct or, how to fix it. So what I want is only the model will be visible and while on zoom in/out or move/drag model it hides/shows the object within the camera.

Please help me with this, so I can understand how LOD work with GLTF models. I’ve searched a lot but didn’t find any examples of LOD with GLTF.

LOD - Three.js Tutorials (sbcode.net)

image

@seanwasere thanks for the reply, I’ve gone through the example already that you’ve shared, but still I didn’t understand what I’m doing wrong.

If you think I need to change something on the code so can you point out or share something?

I only see one level of LOD in you code.

If I added two more, like this,

lod.addLevel(mesh, 75);
lod.addLevel(mesh, 100);
lod.addLevel(mesh, 150);

then it comes like this, I don’t think that’s the right way. How many levels do we need to define and how?

The official example demonstrates LOD perfectly well.
three.js/webgl_lod.html at master · mrdoob/three.js (github.com)
Whether your model is GLTF, OBJ, generated manually from primitives, it doesn’t matter.
Basically different geometries that are shown/hidden depending on distance from camera.
Maybe LOD isn’t the technique you are looking for.

What I’m trying to achieve is something like google Maps. Like in Google Maps, when we drag the map then it loads the other parts of the map where we move/drag.

Similarly, I want my model to be lazily loaded, which means when I try to drag/move or zoom in/out my model, it should load/hide the other parts of the model.

Do you think we can achieve this using LOD?

One more question, the link you previously referred to, in that code, they are loading 3 types of model for each tree type means (high, medium or low). So, do I need to do similar to that?

you could store your different level of detail geometries in one glTF/glB if you wanted.
A better term to search for might be “Lazy Loaded LOD”, but then there is probably a better term, since this doesn’t return much.
I built something like this many years ago, but most of the work was in the server side choosing which assets to return based on lat/lon. It was built by hand, not using any off the shelf libs.

Perhaps you want to build something like this (keep zooming in)
F4map Demo - Interactive 3D map