three.js Uncaught RangeError:渲染循环中超过了最大调用堆栈大小

three.js Uncaught RangeError: Maximum call stack size exceeded in render loop

本文关键字:过了 调用 堆栈 中超 循环 Uncaught js RangeError three      更新时间:2023-09-26

好的。。对JS和three.JS来说是个新手,我很想知道为什么我在函数自调用中会获得堆栈超越,即three.jss在每个设计中都会自然调用。然而,只有当我将调用从主函数中移除时,才会发生这种情况。

我基本上已经从three.js-Documentation中取了立方体的例子,我正在尝试设置动画,这样我就可以动态地添加和减去场景中的对象,并将其发送到特定的画布。

来自three.js 的原始代码

        var scene = new THREE.Scene();
        var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
        var renderer = new THREE.WebGLRenderer();
        renderer.setSize( window.innerWidth, window.innerHeight );
        document.body.appendChild( renderer.domElement );
        var geometry = new THREE.BoxGeometry( 1, 1, 1 );
        var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
        var cube = new THREE.Mesh( geometry, material );
        scene.add( cube );
        camera.position.z = 5;
        var render = function () {
            requestAnimationFrame( render );
            cube.rotation.x += 0.1;
            cube.rotation.y += 0.1;
            renderer.render(scene, camera);
        };
        render();

关注动画调用render();是在reqestAnimationFrame()函数中自调用的。为了分解程序结构以供将来使用,我这样设置(在后视镜中不是最好的选择(:

function e3Dview(){
    // Set the e Canvas
    this.canvas = document.getElementById("eplot3D")
    scene = new THREE.Scene();
    camera = new THREE.PerspectiveCamera( 75, this.canvas.width / this.canvas.height, 0.1, 1000 );
    renderer = new THREE.WebGLRenderer({ canvas: eplot3D });
    renderer.setSize( this.canvas.width, this.canvas.height);
    var geo = new THREE.BoxGeometry( 1, 1, 1 );
    var mat = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
    mat.wireframe = true
    this.cube = new THREE.Mesh( geo, mat );
    scene.add( this.cube );
    camera.position.z = 5;
    controls = new THREE.OrbitControls( camera, renderer.domElement );
    // Execute render
    this.renderloop();
};
e3Dview.prototype.renderloop = function(){
    requestAnimationFrame( this.renderloop() );
    this.cube.rotation.x += 0.01;
    this.cube.rotation.y += 0.01;
    renderer.render(scene, camera);
};
e3Dview.prototype.sceneClear = function(){
     scene.children.forEach(function(object){
        scene.remove(object);
    });
};

一旦我将渲染循环移动到inital父调用之外,我就会得到一个"stackoverflow"错误。。。。

未捕获范围错误:超出了最大调用堆栈大小

所以我的问题是,当render在requestAnimationFrame中调用自己时,这是怎么回事,但当在父调用之外发生同样的事情时,堆栈没有被清除,它失败了?

我错过了什么?

问题出在这一行:

requestAnimationFrame( this.renderloop() );

在这里,您有效地立即调用renderloop((,而不是将函数作为回调传递给requestAnimationFrame,从而导致无限递归循环。

当然,人们可能会尝试将其更改为以下内容,但这也不起作用,因为传递的函数原型不绑定到任何对象:

requestAnimationFrame( this.renderloop ); // This won't work, either.

这里的解决方案是将函数绑定到对象的范围:

requestAnimationFrame( this.renderloop.bind(this) ); // This will work, but overhead at 60FPS might not be worth it

我建议将renderloop函数作为私有方法移动到e3Dview构造函数中,如下所示:

function e3Dview(){
    var $this = this; // Hold the current object's scope, for accessing properties from within the callback method.
    ...
    function renderloop() {
        requestAnimationFrame( renderloop );
        $this.cube.rotation.x += 0.01;
        $this.cube.rotation.y += 0.01;
        renderer.render(scene, camera);
    }
    renderloop();
}

它没有那么漂亮,但通常都是这样做的。如果你真的需要将renderloop公开为一个公共函数,你可以——但我怀疑没有任何理由这样做