在Three.js中创建3D画布作为类时,属性未定义。

huangapple go评论52阅读模式
英文:

Property undefined in Three JS creating 3D canvas as a class

问题

我正在尝试使用Three.js创建一个Web 3D场景,为了更好地维护性,我选择将其编写为一个类。

export class RenderCanvas {

    #canvas;             // document.querySelector(idOfCanvas)
    #renderer;            // WebgL renderer
    #scene;
    #controls            // Trackball control
    #camera
    // ... other properties 
    
    constructor(){ /* ... */ } 
    startup() { 
        this.#renderer = new THREE.WebGLRenderer({
            antialias: true,
            canvas: this.#canvas
        });
        // Other initializations 
    }
    loadGeometries() { /* add models and lights into the scene */ }

    update(time) {
        const canvas = this.#renderer.domElement;
        this.#camera.aspect = canvas.clientWidth / canvas.clientHeight;
        this.#camera.updateProjectionMatrix();
        // This is for resizing the render area and fit the resolution

        requestAnimationFrame(this.update);
        this.#controls.update();

        this.#renderer.render(this.#scene, this.#camera);
    }

    main() {
        this.startup();
        this.addLights();
        this.loadGeometries(); 

        requestAnimationFrame(this.update);
    }
}

在另一个脚本中,我只需要执行let rc = new RenderCanvas();rc.main();

但是在update方法中,第const canvas = this.#renderer.domElement;行,我收到一个控制台错误,错误信息是Uncaught TypeError: Cannot read properties of undefined (reading '#renderer')

我以为在调用update方法时,渲染器已经初始化了。但是错误似乎表明情况并非如此。我是否误解了执行顺序?或者这里涉及到JavaScript作用域的一些内容?

英文:

I'm trying to create a web 3D scene using Three.js, in the hope of better future maintainability I opted to code it as a class

export class RenderCanvas {

    #canvas;             // document.querySelector(idOfCanvas)
    #renderer;            // WebgL renderer
    #scene;
    #controls            // Trackball control
    #camera
    // ... other properties 
    
    constructor(){ /* ... */ } 
    startup() { 
        this.#renderer = new THREE.WebGLRenderer({
            antialias: true,
            canvas: this.#canvas
        });
        // Other initializations 
    }
    loadGeometries() { /* add models and lights into the scene */ }

    update(time) {
        const canvas = this.#renderer.domElement;
        this.#camera.aspect = canvas.clientWidth / canvas.clientHeight;
        this.#camera.updateProjectionMatrix();
        // This is for resizing the render area and fit the resolution

        requestAnimationFrame(this.update);
        this.#controls.update();

        this.#renderer.render(this.#scene, this.#camera);
    }

    main() {
        this.startup();
        this.addLights();
        this.loadGeometries(); 

        requestAnimationFrame(this.update);
    }
}

And in another script I can just do let rc = new RenderCanvas(); and rc.main();.

But in the update method, on line const canvas = this.#renderer.domElement;, I received a console error saying Uncaught TypeError: Cannot read properties of undefined (reading '#renderer').

I thought that by the time update gets called, the renderer is already initiated. But the error seems to indicate otherwise. Am I misunderstanding the execution order? Or is there something about scope in Javascript at play here?

答案1

得分: 1

问题似乎出在你的更新函数上,你应该按照以下两种方式之一进行修改:

方式一:使用bind方法绑定上下文:

update(time) {
    const canvas = this.#renderer.domElement;
    this.#camera.aspect = canvas.clientWidth / canvas.clientHeight;
    this.#camera.updateProjectionMatrix();

    requestAnimationFrame(this.update.bind(this)); // 在这里绑定上下文
    this.#controls.update();
    this.#renderer.render(this.#scene, this.#camera);
}

方式二:使用箭头函数:

update = (time) => {
    const canvas = this.#renderer.domElement;
    this.#camera.aspect = canvas.clientWidth / canvas.clientHeight;
    this.#camera.updateProjectionMatrix();

    requestAnimationFrame(this.update); // 上下文会自动保留
    this.#controls.update();
    this.#renderer.render(this.#scene, this.#camera);
}
英文:

the issue seems to be with the update function you have .. you should do it like on of those two ways :

bind:

update(time) {
    const canvas = this.#renderer.domElement;
    this.#camera.aspect = canvas.clientWidth / canvas.clientHeight;
    this.#camera.updateProjectionMatrix();

    requestAnimationFrame(this.update.bind(this)); // Bind the context here
    this.#controls.update();
    this.#renderer.render(this.#scene, this.#camera);
}

OR - using arrow function:

update = (time) => {
    const canvas = this.#renderer.domElement;
    this.#camera.aspect = canvas.clientWidth / canvas.clientHeight;
    this.#camera.updateProjectionMatrix();

    requestAnimationFrame(this.update); // Context is automatically preserved
    this.#controls.update();
    this.#renderer.render(this.#scene, this.#camera);
}

huangapple
  • 本文由 发表于 2023年8月8日 23:04:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/76860841.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定