【问题标题】:three.js Uncaught RangeError: Maximum call stack size exceeded in render loopthree.js Uncaught RangeError:渲染循环中超出了最大调用堆栈大小
【发布时间】:2016-11-07 15:07:10
【问题描述】:

好的.. 对 JS 和 three.js 来说太新了,我很想知道为什么我在函数自调用中会出现堆栈超出,因为 three.js 在每个设计中都会自然调用。然而,只有当我从主函数中删除调用时才会发生这种情况。

我基本上采用了来自 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);
    });
};

一旦我将渲染循环移到初始父调用之外,我就会收到“stackoverflow”错误....

未捕获的 RangeError:超出最大调用堆栈大小

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

我错过了什么?

【问题讨论】:

    标签: javascript three.js


    【解决方案1】:

    问题在于这一行:

    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();
    }
    

    它不那么漂亮,但通常是这样完成的。如果你真的需要将渲染循环公开为公共函数,你可以——但我怀疑没有任何理由这样做。

    【讨论】:

    • 谢谢你的朋友,这填补了我对 JS 知识的一些空白。真的很有帮助。
    猜你喜欢
    • 2014-06-11
    • 2017-05-23
    • 1970-01-01
    • 2018-03-18
    • 2011-12-01
    • 1970-01-01
    • 2022-09-29
    • 2017-12-12
    相关资源
    最近更新 更多