Interaction with canvas element required in order to generate model?

Hey there,

My GLB model won’t appear on page load, instead the model will only generate after a user has interacted with the canvas. Is anyone familiar with why this may be occurring?

My JS output is as follows:

 if ( WEBGL.isWebGLAvailable() ) {
      console.log("webgl is available");
      container = document.getElementById( 'model-canvas-wrapper' );

     var camera , controls, scene, renderer;

     init();
     animate();

     function init(){
      // Create the camera
      camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 50);

        // camera.position dictates how far away it will be from the rotational axis. 1 is close and 1< is further away
        // Ultimatley, this will dictate the size of the object - by varying the distance between the object and the camera
        camera.position.z = 7.25;

        // Set camera controls (REMEMBER: It's the camera that's rotating, not the object)
        // controls = new THREE.TrackballControls( camera );
        controls = new THREE.TrackballControls(camera, document.getElementById('model-canvas-wrapper'));
        controls.addEventListener('change', render);

        // Removes camera pan on right click
        controls.noPan = true;

        // Removes camera zoom on scroll
        controls.noZoom = true;

        // Create the scene where the object will be located
        scene = new THREE.Scene();

        // Add light to the scene so that objects can be seen
        ambientLight = new THREE.AmbientLight(0x404040, 5, 0.5);
        scene.add(ambientLight);

        // Add a spotlight to the scene for some direct lighting
        light = new THREE.PointLight(0xf5f5f5, 5, 5)

        // variable.position.set(x, y, z) references where the light will be angled
        light.position.set(3, 4, 3);
        light.castShadow = true;
        light.shadow.camera.near = 0.001;
        light.shadow.camera.far = 25;
        scene.add(light);

        renderer = new THREE.WebGLRenderer({
            alpha: true 
        });

        renderer.setSize(window.innerWidth, window.innerHeight);
        container.appendChild( renderer.domElement );

        var loader = new THREE.GLTFLoader();
        renderer.gammaOutput = true;
        renderer.gammaFactor = 2.2;

        loader.load( '../models/glb/test-model.glb', function ( glb ) {
            
            object = glb.scene.children[0];
            // variable.scale.set(x, y, z) references the size of the object
            object.scale.set(1.4,1.4,1.4);
            // .position refers to the location of the object on the canvas
            object.position.set(-0.02,-0.75,2);
            // .rotation refers to the angle of the object
            object.rotation.set(90, 0.25, -0.5);
            
            scene.add( object );

            // This code will center the cameras roatational axis around the loaded object.
            var boundingBox = new THREE.Box3();
            boundingBox.setFromObject( object );
            var center = boundingBox.getCenter();
            // set camera to rotate around center of object
            controls.target = center;

            scene.add('https://grvty.ca/wp-content/uploads/2019/09/Apple_Macintosh_1985-2.glb');

        }, undefined, function ( error ) {
            console.error( error );

        } );

    }

    function animate(){

        requestAnimationFrame( animate );
        controls.update();
    }

    function render(){
        renderer.render(scene, camera );
    }

    console.log("error");     

 } else {

     var warning = WEBGL.getWebGLErrorMessage();
     document.getElementById( 'model-canvas-wrapper' ).appendChild( warning );

     console.log("webgl is NOT available");

 }

Thanks for your insight! I apprecitate the assistance and direction of the communitiy.

Cheers

controls.addEventListener('change', render);

At the moment, your renderer only renders your scene once your controls object emits a change event. It emits a change event when a user interacts with the controls.

What you can do instead is call render() from inside your animate() function. This will render your scene every frame regardless of if the user has interacted or if anything has changed within the scene. This is the easiest and most common solution, as when you build a more complicated app, trying to keep track of changes and rendering only on a change gets very complicated.

An alternate solution would be to call render() inside the callback function to loader.load() after you have added your model to the scene.