2016-11-07 2 views
0

Ok .. so neu in JS und three.js und ich bin sehr neugierig zu wissen, warum ich eine Stack-Überschreitung in einer Funktion selbst Aufruf, dass three.js ruft natürlich pro Design auf. Aber es passiert nur, wenn ich den Anruf aus der Hauptfunktion entferne.three.js Uncaught RangeError: Maximale Callstack-Größe in Render-Schleife überschritten

Ich habe im Grunde das Würfelbeispiel aus three.js-Documentation genommen und ich versuche, die Animation so zu erstellen, dass ich Objekte dynamisch aus der Szene hinzufügen und subtrahieren sowie an eine bestimmte Leinwand senden kann.

Originalcode von 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(); 

auf die Animation Anruf Fokussierung in render(); wird selbst in reqestAnimationFrame() Funktion aufgerufen. die Programmstruktur für die zukünftige Verwendung zu brechen, habe ich es wie folgt aus (in Hinter Sicht nicht die beste Option):

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

Sobald ich die Rendering-Schleife außerhalb des inital Mutter Anruf verschiebe ich eine „Stackoverflow“ erhalten Fehler ....

Uncaught Auslöser Range: Maximale Call-Stack-Größe überschritten

Also meine Frage ist, wie es ist, dass, wenn Anrufe sich in der request machen, die in Ordnung ist, aber wenn die gleiche Sache außerhalb geschieht die Eltern rufen die s an Tack ist nicht geklärt und es scheitert?

Was fehlt mir?

Antwort

3

Das Problem ist mit dieser Zeile:

requestAnimationFrame(this.renderloop()); 

Hier sind Sie effektiv renderloop() aufrufe sofort, anstatt die Funktion als Callback zu, so dass eine unendliche Rekursion Schleife verursacht.

Natürlich könnte man versuchen, es zu folgenden Änderungen, aber das wird auch nicht funktionieren, weil die Funktion Prototyp übergeben wird ist nicht auf ein Objekt gebunden:

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

Eine Lösung ist hier zu binden die Funktion auf den Umfang des Objekts:

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

ich empfehle die renderloop Funktion in den e3Dview Konstruktor als private Methode zu bewegen, etwa so:

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

Es ist nicht so schön, aber so ist es im Allgemeinen. Wenn Sie Renderloop wirklich als öffentliche Funktion verfügbar machen wollen, könnten Sie das - aber ich vermute, dass es keinen Grund dafür gibt.

+0

Danke Kumpel, das schließt ein paar Lücken in meinem JS-Wissen. Wirklich hilfreich. – CromeX

Verwandte Themen