Recently delving into the world of JS and three.js, I've encountered an issue with a stack exceedance in a self-calling function that is invoked by three.js as part of its design. Strangely, this stack exceedance only occurs when I remove the call from the main function.
I started off with the cube example taken from the official Three.js documentation. My goal is to create dynamic animations where objects can be added or removed from the scene, and displayed on a specified canvas.
The original code snippet from Three.js looks like this:
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();
As I studied the animation call render();
which recursively calls itself within requestAnimationFrame()
, I attempted to structure my program for future flexibility but ran into issues:
function e3Dview() {
// Setting up 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);
// Executing the rendering loop
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);
});
};
Upon moving the rendering loop outside the initial parent call, I encountered a "stackoverflow" error...
Uncaught RangeError: Maximum call stack size exceeded
This leads me to question why does the render
function calling itself within requestAnimationFrame work fine, whereas doing the same outside results in a failed stack clearance?
What might I be overlooking in this situation?