I am learning to load a JSON format and manipulate it using tQuery. I did successfully load the animating model, but it did not load the textures, as it loads the pitch-black model animating in screen. The model is perfectly fine, as it is the example model used in Three.js, named stork.js.
This is my code.
<script>
var world=tQuery.createWorld().boilerplate().start();
world.removeCameraControls();
// Animation Variables
var animOffset = 0, // starting frame of animation
duration = 1000, // milliseconds to complete animation
keyframes = 12, // total number of animation frames = SEE THE FILE OF MODEL!
interpolation = duration / keyframes, // milliseconds per frame
lastKeyframe = 0, // previous keyframe
currentKeyframe = 0,
bird,bird_material;
var jsonLoader = new THREE.JSONLoader();
jsonLoader.load("models/stork.js",
function(geometry, materials){
if(geometry.morphColors && geometry.morphColors.length) {
var colorMap = geometry.morphColors[0];
for (var i = 0; i < colorMap.colors.length; i ++) {
geometry.faces[i].color = colorMap.colors[i];
geometry.faces[i].color.offsetHSL( 0, 0.3, 0 );
}
}
geometry.computeMorphNormals();
addModelToScene(geometry, materials);
});
function addModelToScene(geometry, materials){
for (var i = 0; i < materials.length; i++) {
materials[i].morphTargets = true;
}
bird_material = new THREE.MeshPhongMaterial({
color: 0xffffff, morphTargets: true, morphNormals: true,
vertexColors: THREE.FaceColors, shading: THREE.SmoothShading
});
bird = new THREE.Mesh( geometry,bird_material );
bird.scale.set(0.02,0.02,0.02);
bird.position.set(0,0,0);
bird.rotation.set(0,3.9,0);
bird.castShadow = true;
var object3DNew = new tQuery.Object3D();
object3DNew.add(bird).addTo(world);
}
world.hook(function(){
if(bird){
var time = new Date().getTime() % duration;
var keyframe = Math.floor(time / interpolation) + animOffset;
if (keyframe != currentKeyframe){
bird.morphTargetInfluences[lastKeyframe] = 0;
bird.morphTargetInfluences[currentKeyframe] = 1;
bird.morphTargetInfluences[keyframe] = 0;
lastKeyframe = currentKeyframe;
currentKeyframe = keyframe;
}
bird.morphTargetInfluences[keyframe] = (time % interpolation) / interpolation;
bird.morphTargetInfluences[lastKeyframe] = 1 - bird.morphTargetInfluences[keyframe];
}
});
</script>
This is the result I get:
It was really stupid of me, Thankyou Jerome Etienne for the answer. The answer is, add the light to the scene.
Related
Me and my friend have been working on a uni assignment - a simple Pacman clone - in ThreeJS (mandatory) and we've had this problem since pretty much the beginning. As the scene keeps running, it starts going faster and faster with each second. It's not like there becomes less stuff to render, everything is pretty much the same.
import * as THREE from '././../three.js-master/build/three.module.js';
function main() {
const canvas = document.querySelector('#canva');
const renderer = new THREE.WebGLRenderer({ canvas });
renderer.setSize(window.innerWidth, window.innerHeight);
/* Camera */
const fov = 40;
const aspect = window.innerWidth / window.innerHeight;
const near = 0.1;
const far = 1000;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
// I want to go for that angled look
// Angled enough to show depth, but still have everything important visible
camera.position.set(0, 65, -45); //Man setting up the camera is fun and not at all painful
camera.up.set(0, 0, 1);
camera.lookAt(0, 0, 0);
const scene = new THREE.Scene();
/* Lights */
const mainLight = new THREE.DirectionalLight(0xffffff, .85);
mainLight.position.set(0, 20, 0);
scene.add(mainLight);
mainLight.castShadow = true;
mainLight.shadow.mapSize.width = 2048;
mainLight.shadow.mapSize.height = 2048;
// const light = new THREE.PointLight(0xffffff, 1);
// light.position.set(30, 0, 30);
// scene.add(light);
/* Board */
const boardGeometry = new THREE.PlaneGeometry(50, 50);
const boardMaterial = new THREE.MeshToonMaterial({ color: 0xEEEEEE, side: THREE.DoubleSide });
const board = new THREE.Mesh(boardGeometry, boardMaterial);
board.rotation.x = Math.PI / 2; //The board must be placed flat on the x axis
scene.add(board);
/* Player */
const playerBox = new THREE.Box3() // Used to determine collisions
const playerGeometry = new THREE.BoxGeometry(1, 1, 1.5);
const playerMaterial = new THREE.MeshToonMaterial({ color: 0xAAAAAA });
const player = new THREE.Mesh(playerGeometry, playerMaterial);
player.geometry.computeBoundingBox(playerBox);
/* Players Axes helper */
const axesHelper = new THREE.AxesHelper(5);
player.add(axesHelper);
scene.add(player);
/* Box helper */
const playerHelper = new THREE.Box3Helper(playerBox, 0xffff00);
scene.add(playerHelper);
/* Enemy #1 */
const enemy1Box = new THREE.Box3()
const enemy1Geometry = new THREE.BoxGeometry(1, 1, 1);
const enemy1Material = new THREE.MeshToonMaterial({ color: 0x0000ff });
const enemy1 = new THREE.Mesh(enemy1Geometry, enemy1Material);
enemy1.position.x = 2
enemy1.geometry.computeBoundingBox(enemy1Box);
scene.add(enemy1);
const enemyHelper = new THREE.Box3Helper(enemy1Box, 0xffff00);
scene.add(enemyHelper);
/////////////////////
/* Cheese */
const smallCollectibleRadius = .4
const bigCollectibleRadius = .6
/* Standard cheese */
var cheeseList = []
var cheeseBoxList = []
const cheeseBox = new THREE.Box3();
const cheeseGeometry = new THREE.SphereGeometry(smallCollectibleRadius, 100, 100);
const cheeseMaterial = new THREE.MeshToonMaterial({ color: 0xffff00, emissive: 0xffff00 });
var cheese = new THREE.Mesh(cheeseGeometry, cheeseMaterial); // Changed const to var so it could be set to null in order to get rid of after collecting
cheese.position.set(0, 0, 3)
scene.add(cheese);
cheese.geometry.computeBoundingBox(cheeseBox);
const cheeseHelper = new THREE.Box3Helper(cheeseBox, 0xffff00);
scene.add(cheeseHelper);
/* SuperCheese */
const superCheeseGeometry = new THREE.SphereGeometry(bigCollectibleRadius, 100, 100);
const superCheeseMaterial = new THREE.MeshToonMaterial({ color: 0xcb6600, emissive: 0x0000ff });
const superCheese = new THREE.Mesh(superCheeseGeometry, superCheeseMaterial);
superCheese.position.set(0, 0, 5)
scene.add(superCheese);
/* Outer wall generation */
const walls = [];
const wallGeometry = new THREE.BoxGeometry(1, 1, 1);
const wallMaterial = new THREE.MeshToonMaterial({ color: 0xAAAAAA });
//Yes I know the wall being split into blocks might not look good for now
//Please trust me, it will make more sense later
//Top
for (var i = 0; i < 49; i++) {
const wall = new THREE.Mesh(wallGeometry, wallMaterial);
wall.position.set(24.5 - i, 0.5, 24.5)
walls.push(wall);
}
//Right
for (var i = 0; i < 49; i++) {
const wall = new THREE.Mesh(wallGeometry, wallMaterial);
wall.position.set(-24.5, 0.5, 24.5 - i)
walls.push(wall);
}
//Bottom
for (var i = 0; i < 49; i++) {
const wall = new THREE.Mesh(wallGeometry, wallMaterial);
wall.position.set(-24.5 + i, 0.5, -24.5)
walls.push(wall);
}
//Left
for (var i = 0; i < 49; i++) {
const wall = new THREE.Mesh(wallGeometry, wallMaterial);
wall.position.set(24.5, 0.5, -24.5 + i)
walls.push(wall);
}
//Tried to do the four of them as a single double loop
//Might try again later
for (var i = 0; i < walls.length; i++) scene.add(walls[i]);
//////////////////////////
function makeCoins(num, cheeseList_t = cheeseList, cheeseBoxList_t = cheeseBoxList) { //I know these names break the convention.
const smallCollectibleRadius = .4
const bigCollectibleRadius = .6
for (let i = 0; i < num; i++) {
console.log("I'm a fake cheese!")
const cheeseBox = new THREE.Box3();
const cheeseGeometry = new THREE.SphereGeometry(smallCollectibleRadius, 100, 100);
const cheeseMaterial = new THREE.MeshToonMaterial({ color: 0xffff00, emissive: 0xffff00 });
var cheese = new THREE.Mesh(cheeseGeometry, cheeseMaterial);
cheese.position.set(0, 0, (6 + i))
cheese.userData.idd = i // it's in a dict form, {"idd":i}
scene.add(cheese);
cheese.geometry.computeBoundingBox(cheeseBox);
const cheeseHelper = new THREE.Box3Helper(cheeseBox, 0xffff00);
scene.add(cheeseHelper);
cheeseList_t.push(cheese)
cheeseBoxList_t.push(cheeseBox)
}
}
makeCoins(2) // IT WORKS, HOLY COW
console.log(cheeseList[1])
function checkCollision(box) {
/* Code sucks but works and will by changed in future anyway */
var collision = playerBox.intersectsBox(box);
if (collision == true) {
return true
}
}
function collect(item) {
/* TODO: Collecting cheeses */
}
var points = 0;
function updatePoints(amount) {
points += amount
}
document.addEventListener("keypress", function (event) {
/* Additional player movement's listener that doesn't throw 2137 msgs in the console.
It would be great to make it the only one player movement's listener */
if (checkCollision(enemy1Box)) {
/**/
console.log("You bumped into enemy1!")
}
if (cheese !== null && !('consumed' in cheese.userData) && checkCollision(cheeseBox)) {
/* This will go to collect() function once finished */
console.log("Yummy cheese!")
scene.remove(cheese)
cheese.userData.consumed = true // good to know there is this userData feature
cheese = null
updatePoints(1)
}
/* For testing purposes */
var coinBox = cheeseBoxList[0]
if (checkCollision(coinBox)){
console.log("HOLY GUACAMOLE, IT WORKS") // IT REALLY DOES!
}
});
/////////////////////////////////////////////////////////////////////////////////////////////////
/* Render stuff */
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
function render(time) {
time *= 0.001;
const speed = 0.0005
const rotSpeed = 0.00005
const dir = new THREE.Vector3();
if (resizeRendererToDisplaySize(renderer)) {
const canvas = renderer.domElement;
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
/* Updating boxes */
enemy1Box.copy(enemy1.geometry.boundingBox).applyMatrix4(enemy1.matrixWorld);
playerBox.copy(player.geometry.boundingBox).applyMatrix4(player.matrixWorld);
if (cheese !== null && !('consumed' in cheese.userData)) {
cheeseBox.copy(cheese.geometry.boundingBox).applyMatrix4(cheese.matrixWorld);
}
/* TEST */
var coin = cheeseList[0]
var coinBox = cheeseBoxList[0]
coinBox.copy(coin.geometry.boundingBox).applyMatrix4(coin.matrixWorld); // HOLY COW, IT SEEMS TO WORK
/* I'm afraid it'll lag everything but I can't think of better way of doing this;
this MUST be in render(), otherwise it won't update, but for loop in HERE... ugh
I will not run this. I care for my new PC. I don't want it to burn. I don't care for yours tho. Sorry not sorry, mate
IT'S NOT FINISHED YET, DON'T THINK OF RUNNING THIS
for (let i = 0; i < num; i++) {
coin = coinList[i]
coinBox = coinBoxList[i]
coinBox.copy(coin.geometry.boundingBox).applyMatrix4(coin.matrixWorld);
}
*/
document.getElementById("points").innerHTML = points
document.addEventListener("keypress", function (event) {
if (event.keyCode == 119) { //W going forward
if (checkCollision(enemy1Box)) {
console.log("Can't go any further!") // TODO: Delete in the future
} else {
player.getWorldDirection(dir);
player.position.addScaledVector(dir, speed);
}
}
if (event.keyCode == 115) { //S going backward
player.getWorldDirection(dir);
player.position.addScaledVector(dir, -speed);
}
if (event.keyCode == 97) { //A left rotation
player.rotation.y += rotSpeed
}
if (event.keyCode == 100) { //D right rotation
player.rotation.y -= rotSpeed
}
});
renderer.render(scene, camera);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
main();
You’re adding keypress event listeners inside your render loop. This means that by the time 60 frames have gone by, you’ll have 60 event listeners doing the same thing. That’s why you’re seeing your scene speeding up: the more frames have passed, the more event listeners you’ve added.
Just initialize those events outside the render loop, and you’ll see the issue go away.
what I try to accomplish sounds easy but bothers me for days now.
How may I add Objects to a scene, with a little pause between every adding ?
Within a loop{
I am calling the make_obj- function()
then I call the wait- function().
}
What happens is, that the program does not show the single added objects followed by a pause but puts them all together to the screen when the loop ends after all pauses were made.
I tried to explain it before here
Three.js scene not reacting while program is running
but it seems to be explained to complicated so I broke it down.
Thanks in advance.
Edit_1:
Yes, I can.
Please be so kind and think of scene and three as objects inserted by another class.
These are standard instantions
test = function ( scene, three ){
this.scene = scene;
this.caller_inst = three;
var that= this;
var depth_mod=0;
this.start_loop=function(){
var i;
for( i = 0;
i < 10;
i++
)
this.make_objects();
this.wait(1000);
};
this.wait = function( ms ){
// comment these 2 lines to see effect of "normal" wait loop
setTimeout(function(){ console.log("Wait!"); }, ms);
return;
console.log( "wait start");
var start = new Date ()
. getTime ();
var end = start;
while( end < start + ms ){
end = new Date ()
. getTime ();
}//while
console.log( "wait ended");
};
this.make_objects = function( count_rows, count_columns ){
var color = '#'+Math.floor(Math.random()*16777215).toString(16);
var sphere_geometry = new THREE.SphereGeometry(1);
var material1 = new THREE.MeshPhongMaterial({ color: color, specular: 0x555555 });
var sphere_mesh = new THREE.Mesh(sphere_geometry, material1);
this.scene.add( sphere_mesh );
sphere_mesh.position . copy ( that.caller_inst.camera.position );
sphere_mesh.position.x = sphere_mesh.position.x+5+depth_mod;
sphere_mesh.position.z = sphere_mesh.position.z-15 + depth_mod;
that.caller_inst.renderer . render ( that.caller_inst.scene
, that.caller_inst.camera
);
depth_mod = depth_mod-1;
};//function
};//class
I tried a little modification which brings the sam result.
this.start_loop=function(){
var i;
for( i = 0;
i < 10;
i++
){
setTimeout(function(){ that.make_objects(); }, 1500);
}
};
Why does a manual waiting not work like:
var i;
for( i = 0;
i < 10;
i++
)
this.object[ i ].visible = true;
this.wait(1000);
};
?
With setTimeout function.
Make a function that adds an object. Then just call that via setTimeout. For multiple additions, you can just add another setTimeout call at the end of your object adding function.
function sayHi() {
alert('Hello');
}
setTimeout(sayHi, 1000);
This page seems to have nice examples: https://javascript.info/settimeout-setinterval
There are lots of ways to do something in a loop with a pause. The modern es6 way is to use async functions.
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
async function doThingsOverTime() {
for (let i = 0; i < 10; ++i) {
console.log(i); // add object here
await wait(1000); // wait 1 second
}
}
doThingsOverTime();
example:
<canvas id="c"></canvas>
<script type="module">
import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r113/build/three.module.js';
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
async function main() {
const canvas = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({canvas});
const fov = 40;
const aspect = 2; // the canvas default
const near = 0.1;
const far = 50;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.z = 16;
const scene = new THREE.Scene();
{
const color = 0xFFFFFF;
const intensity = 1;
const light = new THREE.DirectionalLight(color, intensity);
light.position.set(-1, 2, 4);
scene.add(light);
}
const boxWidth = 1;
const boxHeight = 1;
const boxDepth = 1;
const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
function makeInstance(geometry, color, x) {
const material = new THREE.MeshPhongMaterial({color});
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
cube.position.x = x;
return cube;
}
const cubes = [];
function render(time) {
time *= 0.001; // convert time to seconds
cubes.forEach((cube, ndx) => {
const speed = 1 + ndx * .1;
const rot = time * speed;
cube.rotation.x = rot;
cube.rotation.y = rot;
});
renderer.render(scene, camera);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
const numCubes = 11;
for (let i = 0; i < numCubes; ++i) {
const u = i / (numCubes - 1);
const x = (u * 2 - 1) * 10;
cubes.push(makeInstance(geometry, `hsl(${u * 360},100%,70%)`, x));
await wait(1000);
}
}
main();
</script>
I have made a collision detection. You can place objects at the raycaster/mouse position on a floor. Therefore you need to click on a button 'Add object', then you get a object(helper) that follows the mouse to see if the new object get a collision with another object. When you click on the position you want, the new object will be placed to the world if there is no collision.
The collision detection I have made works perfectly when the object that is already placed in the world has the same size as the helper/new object.
On the next screenshot you can see a big object and a small(red) helper. The color red means that there is a collision. When I move the mouse more to the right it turns green.
Why does my collision detection work only with 2 objects that have the same size and why doesn't it not with different ones?
Here is my code in the Click event to show the big object:
var geometry = new THREE.BoxGeometry(200, 200, 300);
var bigobject = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({
color: 0xFBF5D7,
opacity: 1
}));
bigobject.position.copy(intersects[0].point);
bigobject.position.y = 100;
objects.push(bigobject);
scene.add(bigobject);
Here is my code to show the helper when the button 'Add object' is clicked:
var geometry = new THREE.BoxGeometry( 50, 50, 100 );
helper = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { color: 0x00ff00, opacity: 1 } ) );
helper.name = 'helper';
scene.add( helper );
Here is my code in the MouseMove event to detect the collision:
if(scene.getObjectByName( 'helper' )) {
helper.position.copy( intersects[ 0 ].point );
helper.position.y = 25;
var helperWidth = helper.geometry.parameters.width;
var helperLength = helper.geometry.parameters.depth;
var validpositionObject = true;
for (var i = 0; i < objects.length; i++) {
var objectWidth = objects[i].geometry.parameters.width;
var objectLength = objects[i].geometry.parameters.depth;
// MIN X
var helperMinX = helper.position.x;
var objectMinX = objects[i].position.x;
// MAX X
var helperMaxX = helperWidth + helper.position.x;
var objectMaxX = objectWidth + objects[i].position.x;
// MIN Z
var helperMinZ = helper.position.z;
var objectMinZ = objects[i].position.z;
// MAX Z
var helperMaxZ = helperLength + helper.position.z;
var objectMaxZ = objectLength + objects[i].position.z;
if (objectMinX <= helperMaxX && objectMaxX >= helperMinX && objectMinZ <= helperMaxZ && objectMaxZ >= helperMinZ) {
validpositionObject = false;
}
}
if ( validpositionObject === true ) {
helper.material.color.setHex( 0x00ff00 );
validposition = true;
}else{
helper.material.color.setHex( 0xff0000 );
validposition = false;
}
}
What goes wrong with the position when it is a big and a small object.. Can anyone help me in the right direction? Many thanks
Use this:
function collisonXZ(o1, o2) {
if (Math.abs(o1.position.x - o2.position.x) > (o1.geometry.parameters.width + o2.geometry.parameters.width) / 2)
return false;
if (Math.abs(o1.position.z - o2.position.z) > (o1.geometry.parameters.depth + o2.geometry.parameters.depth) / 2)
return false;
return true;
}
var validpositionObject = true;
for (var i = 0; i < objects.length; i++) {
if (collisionXZ(helper, objects[i])) {
validpositionObject = false;
break;
}
}
Suppose I have 10 objects and I want for each object to be given a texture picked for me randomly out of a pool of 10 textures. How do I go about that for this mesh object?
for(var int = 0; int <= 10 ; int++)
{ var loader = new THREE.TextureLoader();
var testMat = new THREE.MeshPhongMaterial({ map: loader.load('images/image1') });
var testGeo = new THREE.SphereGeometry(50, 50, 50);
testSphere = new THREE.Mesh(testGeo, testMat);
testSphere.position.set(distance, 100, 100);
scene.add(testSphere); }
Assuming all of your texture-images are named in a numeric/sequential manner, you could do:
...
var testMat = new THREE.MeshPhongMaterial({ map: loader.load('images/image' + THREE.Math.randInt(1, 10) ) });
...
If not, then you'd make a list of filenames in a manner similar to this, and choose a random value from the list:
var texturesList = [
'images/image1',
'images/some-other-image',
'images/yet-another-image',
...
'images/10th-image'
];
...
...
var randIndex = THREE.Math.randInt(0, texturesList.length - 1);
var randTexture = loader.load(texturesList[randIndex]);
var testMat = new THREE.MeshPhongMaterial({ map: randTexture });
...
Good day!
Have issue with memory handling. I read lots of forums but still can't find whats wrong with my code.
I'm working on project where I combine d3.js with three.js to visualize nodes like planets on orbits in space.
I have a lot of data - like 8K planets in 8+ orbits. But when I try to load new data - I can't destroy current tree without memory leak.
I would be grateful for any help! Here is part of code where I create planets and where I try to destroy them:
function initTree(root) {
var start, end;
var nodes = tree.nodes(root); //this is d3.js tree init
var depth = getDepth(root);
var first_x_offset = nodes[0].x;
if (isNaN(first_x_offset)) {first_x_offset = 0}
//create orbits
var orbitTexture = new THREE.ImageUtils.loadTexture('img/orbit_texture.png');
var orbitMaterial = new THREE.MeshBasicMaterial({map: orbitTexture, transparent:true, side: THREE.DoubleSide, alphaTest: 0.05, opacity:0.3});
var sphereGeometry = new THREE.SphereGeometry(1, 6, 6);
var orbitSize = 30;
for (var k=1; k<depth; k++) {
var orbit = new THREE.Mesh(new THREE.CircleGeometry(orbitSize*k, 64), orbitMaterial);
orbit.rotation.x = -90*Math.PI/180;
orbit.name = 'orbit';
scene.add(orbit);
}
//end orbits
//camera position
camera.position.x = 0;
camera.position.y = 70;
camera.position.z = -orbitSize*depth-100;
controls.target.x = 0;
controls.target.y = 0;
controls.target.z = 0;
camera.up.x = 0;
camera.up.y = 1;
camera.up.z = 0;
//this is parent object to place in center
var parent = new THREE.Object3D();
parent.name = 'parent';
scene.add(parent);
y=0;
spheres = {};
objects = [];
nodes.forEach(function(d) {
if (d.type == 'BLANK') {return}
d.x = d.x - first_x_offset;
if (isNaN(d.x)) {d.x = 0}
var sphereMaterial = new THREE.MeshLambertMaterial({color: 0xdddddd, wireframe: false, opacity: 0.7, transparent: true});
var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial );
sphere.material.color.setHex(color_type[d.type]);
sphere.castShadow = false; //maybe change to true
sphere.id2 = y;
d.id2 = y;
sphere.d = d;
sphere.scale.x = radius_type[d.type];
sphere.scale.y = radius_type[d.type];
sphere.scale.z = radius_type[d.type];
sphere.name = 'sphere';
spheres[y] = sphere;
//count items of each type
count_type[d.type]++;
//how many nodes in tree
y++;
//create pivot
var pivot = new THREE.Object3D;
//rotate it
pivot.rotation.y = d.x*Math.PI/180-90;
//append to parent
pivot.name = 'pivot';
parent.add(pivot);
//add mesh to pivot
var default_distance = size/(depth-1);
if (d.y > 0) {
d.y = (Math.round(d.y/default_distance)) * (orbitSize-8.8);
}
sphere.position.x = d.y;
sphere.position.y = 0; //should be 0!
sphere.position.z = d.y;
objects.push(sphere);
pivot.add(sphere);
});
nodesLength = y;
render();
$('.loading').fadeOut(500);
if (!animationId) {
animate();
}
temp = null;
nodes = null;
}
So I'm adding spheres to parent Object3D and then add it to scene.
And here is destroy function:
function destroyTree() {
//spheres
//console.log(renderer.info);
var to_delete = [];
for (var i=0; i<spheres.length; i++) {
scene.remove(spheres[i]);
spheres[i].material.dispose();
spheres[i].geometry.dispose();
}
for (var i=0; i<spheres.length; i++) {
spheres[i] = undefined;
}
spheres = {};
for (var i=0; i<objects.length; i++) {
scene.remove(objects[i]);
}
for (var i=0; i<objects.length; i++) {
objects[i] = undefined;
}
objects = [];
var parent = scene.getObjectByName('parent');
scene.remove(parent);
if (links.length) {
for (var i=0; i<links.length; i++) {
scene.remove(links[i]);
}
}
links = [];
scene.traverse(function (child) {
if (child instanceof THREE.Mesh) {
if (child.name.length) {
to_delete.push(child);
}
}
});
for (var i=0; i<to_delete.length; i++) {
scene.remove(to_delete[i]);
to_delete[i].geometry.dispose();
to_delete[i].material.dispose();
to_delete[i] = undefined;
}
to_delete = [];
}
Wouldn't traversing the scene find the spheres too? And in that loop you could dispose directly without need for the to_delete array. If all speres are not children of the scene then maybe reconsider when to create them? These would just be optimizations and probably do little other then clarify where it might be leaking.
Then again maybe try holding an array of textures and releasing those directly?
Wait here it is, this link says to remove the objects and textures from the renderer as well.
Memory leak in Three.js
renderer.deallocateObject
renderer.deallocateTexture