Loading three.js from a class

Hi! I’m still pretty new to three.js, coming from non-web developing. What I’m trying to achieve is a custom class where all three.js-logic is located, such as loading objects, rendering, etc. The class so far sets up a scene, camera and renderer and from another javascript file I create this class and runs the render process, working as expected. However, the document is entirely blank. There is a canvas but it has a height and width of 0. I have a suspicion that the document might be poorly connected to the class I made, but as I said I have very little experience in web development.

The class setup looks like this:

import * as THREE from 'https://cdn.skypack.dev/three@v0.128.0/build/three.module.js';

export class SceneManager{
    scene;
    camera;
    renderer;
    constructor(screenWidth, screenHeight){
        this.scene = new THREE.Scene();
        this.camera = new THREE.PerspectiveCamera(70, screenWidth/screenHeight, 0.1, 1000);

        this.renderer = new THREE.WebGLRenderer({canvas: document.getElementById('ThreeScene') , antialias: true});
        this.renderer.setSize(screenWidth, screenHeight);
        document.body.appendChild(this.renderer.domElement);
    }
    animate(){
        requestAnimationFrame(this.animate.bind(this));
        this.render();
    }
    render(){
        this.renderer.render(this.scene, this.camera);
    }
}

From here I import SceneManager from another javascript file:

import {SceneManager} from "./gallery_objects.js";

const screenWidth = 420;
const screenHeight = 750;

const sceneManager = new SceneManager(screenWidth, screenHeight);

sceneManager.animate();

From the html-file I imported the latter file as a module and added a canvas with the same ID as in SceneManager, and the function animate runs at 60 fps, but nothing appears. Any ideas?

Avoid the usage of bind() per animation step. Try to use this pattern:

export class SceneManager{
    scene;
    camera;
    renderer;
    constructor(screenWidth, screenHeight){
        this.scene = new THREE.Scene();
        this.camera = new THREE.PerspectiveCamera(70, screenWidth/screenHeight, 0.1, 1000);

        this.renderer = new THREE.WebGLRenderer({canvas: document.getElementById('ThreeScene') , antialias: true});
        this.renderer.setSize(screenWidth, screenHeight);
        document.body.appendChild(this.renderer.domElement);

        this._animate = animate.bind( this );
    }
    render(){
        this.renderer.render(this.scene, this.camera);
    }
}

function animate() {

	requestAnimationFrame( this._animate );

	this.render();

}
1 Like

That works, but didn’t change the fact that the canvas has a width and height of 0. The canvas is initiated like this:
<canvas id="ThreeScene" width="420" height="750"></canvas>
But somehow it is resized to 0 at start. Forcing a resize shows the red background I set with this.scene.background = new THREE.Color(0xff0000); but none of the objects i added onto the scene appear.

If you query a canvas element from the DOM, you don’t need this line:

document.body.appendChild(this.renderer.domElement);

Remove this line or let the renderer create its own canvas. In this case, you have to append it to the DOM.

I removed the canvas and changed the WebGLRenderer constructor to this.renderer = new THREE.WebGLRenderer({antialias: true});. Canvas size is still 0, unfortunately

Thanks for the quick replies :slight_smile:

Fixed the problem, it was a simple error on my part. I had created an extended class of SceneManager and forgot to pass the constructor arguments when calling super();. Thanks for the help!

1 Like