I'm using the Three.js javascript library. To test it I downloaded the an example from here.
I'm trying to display several times the same element using a for loop. There two questions related (1, 2) but it's not exactly what I want. My problem is that if I create the element inside the loop it will only display the last element of the iteration. In this particular case the element in position (12,12).
But, if I do an action like an alert it will display all the elements. Also if I have any other functions that delays the execution.
I saw some examples running, as the mrdoob examples, but I would like this code running because I need to load several mesh instead of generating primitive figures.
// Set up the scene, camera, and renderer as global variables.
var scene, camera, renderer;
var group;
// Call functions
init();
animate();
// Sets up the scene.
function init() {
// Iterator
var i, j;
// Create the scene and set the scene size.
scene = new THREE.Scene();
var WIDTH = window.innerWidth,
HEIGHT = window.innerHeight;
// Create a renderer and add it to the DOM.
renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setSize(WIDTH, HEIGHT);
document.body.appendChild(renderer.domElement);
// Create a camera, zoom it out from the model a bit, and add it to the scene.
camera = new THREE.PerspectiveCamera(45, WIDTH / HEIGHT, 0.1, 20000);
camera.position.set(0,20,20);
scene.add(camera);
// Create an event listener that resizes the renderer with the browser window.
window.addEventListener('resize', function() {
var WIDTH = window.innerWidth,
HEIGHT = window.innerHeight;
renderer.setSize(WIDTH, HEIGHT);
camera.aspect = WIDTH / HEIGHT;
camera.updateProjectionMatrix();
});
// Set the background color of the scene.
renderer.setClearColor(0x333F47, 1);
// Create a light, set its position, and add it to the scene.
var light = new THREE.PointLight(0xffffff);
light.position.set(-100,200,100);
scene.add(light);
group = new THREE.Object3D();
for(i=0; i < 15; i+=3) {
for(j=0; j < 15; j+=3) {
var loader = new THREE.JSONLoader();
loader.load( "models/treehouse_logo.js", function(geometry){
var material = new THREE.MeshLambertMaterial({color: 0x55B663});
var mesh = new THREE.Mesh(geometry, material);
mesh.position.set(i,0,j);
group.add(mesh);
});
//alert("iteration"+i+" "+j);
}
}
scene.add( group );
// Add OrbitControls so that we can pan around with the mouse.
controls = new THREE.OrbitControls(camera, renderer.domElement);
}
// Renders the scene and updates the render as needed.
function animate() {
// Read more about requestAnimationFrame at /
requestAnimationFrame(animate);
// Render the scene.
renderer.render(scene, camera);
controls.update();
}
I'm using the Three.js javascript library. To test it I downloaded the an example from here.
I'm trying to display several times the same element using a for loop. There two questions related (1, 2) but it's not exactly what I want. My problem is that if I create the element inside the loop it will only display the last element of the iteration. In this particular case the element in position (12,12).
But, if I do an action like an alert it will display all the elements. Also if I have any other functions that delays the execution.
I saw some examples running, as the mrdoob examples, but I would like this code running because I need to load several mesh instead of generating primitive figures.
// Set up the scene, camera, and renderer as global variables.
var scene, camera, renderer;
var group;
// Call functions
init();
animate();
// Sets up the scene.
function init() {
// Iterator
var i, j;
// Create the scene and set the scene size.
scene = new THREE.Scene();
var WIDTH = window.innerWidth,
HEIGHT = window.innerHeight;
// Create a renderer and add it to the DOM.
renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setSize(WIDTH, HEIGHT);
document.body.appendChild(renderer.domElement);
// Create a camera, zoom it out from the model a bit, and add it to the scene.
camera = new THREE.PerspectiveCamera(45, WIDTH / HEIGHT, 0.1, 20000);
camera.position.set(0,20,20);
scene.add(camera);
// Create an event listener that resizes the renderer with the browser window.
window.addEventListener('resize', function() {
var WIDTH = window.innerWidth,
HEIGHT = window.innerHeight;
renderer.setSize(WIDTH, HEIGHT);
camera.aspect = WIDTH / HEIGHT;
camera.updateProjectionMatrix();
});
// Set the background color of the scene.
renderer.setClearColor(0x333F47, 1);
// Create a light, set its position, and add it to the scene.
var light = new THREE.PointLight(0xffffff);
light.position.set(-100,200,100);
scene.add(light);
group = new THREE.Object3D();
for(i=0; i < 15; i+=3) {
for(j=0; j < 15; j+=3) {
var loader = new THREE.JSONLoader();
loader.load( "models/treehouse_logo.js", function(geometry){
var material = new THREE.MeshLambertMaterial({color: 0x55B663});
var mesh = new THREE.Mesh(geometry, material);
mesh.position.set(i,0,j);
group.add(mesh);
});
//alert("iteration"+i+" "+j);
}
}
scene.add( group );
// Add OrbitControls so that we can pan around with the mouse.
controls = new THREE.OrbitControls(camera, renderer.domElement);
}
// Renders the scene and updates the render as needed.
function animate() {
// Read more about requestAnimationFrame at http://www.paulirish./2011/requestanimationframe-for-smart-animating/
requestAnimationFrame(animate);
// Render the scene.
renderer.render(scene, camera);
controls.update();
}
Share
Improve this question
edited May 23, 2017 at 11:45
CommunityBot
11 silver badge
asked Jul 24, 2014 at 10:19
albertgumialbertgumi
3421 gold badge6 silver badges13 bronze badges
2 Answers
Reset to default 8What you are doing here is incredibly inefficient:
for(i=0; i < 15; i+=3) {
for(j=0; j < 15; j+=3) {
var loader = new THREE.JSONLoader();
loader.load( "models/treehouse_logo.js", function(geometry){
var material = new THREE.MeshLambertMaterial({color: 0x55B663});
var mesh = new THREE.Mesh(geometry, material);
mesh.position.set(i,0,j);
group.add(mesh);
});
//alert("iteration"+i+" "+j);
}
}
This would be much better done like this (untested):
var loader = new THREE.JSONLoader();
loader.load( "models/treehouse_logo.js", function( geometry ){
var material, mesh, i, j, instance;
material = new THREE.MeshLambertMaterial({ color: 0x55B663 });
mesh = new THREE.Mesh( geometry, material );
for ( i = 0; i < 15; i += 3 ) {
for ( j = 0; j < 15; j += 3 ) {
instance = mesh.clone();
instance.position.set( i, 0, j );
group.add( instance );
}
}
});
You'd need to do repeat this pattern for each unique mesh.
The problems your current approach has are:
- More memory needed by the GPU for each identical mesh
- More memory needed by the browser to remember each identical mesh
- More processing power required by the GPU as more memory needs to be processed
- Each time you call the loader, you instruct the browser to execute a request. That's some 25 identical requests in your case. They should e from the cache, but it'll still be slow.
- You may have variables scoping issues too which gives issues with the loader callback, but I'm not entirely sure about that.
alert() makes for a very poor debugging tool by the way as it changes the way the browser reacts: it stops executing JavaScript when the alert is open and that affects the loader and similar things. You're better off with the Console logging methods.
I would say it is because you are setting the loader variable in each iteration of the loop which will override the loader of the last iteration.
Why is the actual loading being done in a loop? Why not load it once and clone it?
eg.
group = new THREE.Object3D();
var loader = new THREE.JSONLoader();
loader.load( "models/treehouse_logo.js", function(geometry){
var material = new THREE.MeshLambertMaterial({color: 0x55B663});
for(i=0; i < 15; i+=3) {
for(j=0; j < 15; j+=3) {
var mesh = new THREE.Mesh(geometry.clone(), material);
mesh.position.set(i,0,j);
group.add(mesh);
}
}
});
scene.add( group );
The above code is untested