Reputation: 705
I know that there are a lot of topics about memory leak but I tried the solutions and it still doesn't work.
I am working on this example
So I have
materialPano=new THREE.MeshFaceMaterial( materials );
materialPano.needsUpdate=true;
mesh = new THREE.Mesh( new THREE.CubeGeometry( 400, 400, 400, 7, 7, 7 ), materialPano );
I am adding some functionality to change the texture when I click on a button. The problem is that the previous texture isn't deleted and the used memory increased at each new texture.
So when I click on the button, it executes a function which does:
materials = [loadTexture(myNewTexture1 ), loadTexture( myNewTexture2),loadTexture( myNewTexture3 ),loadTexture( myNewTexture4 ),loadTexture( myNewTexture5), loadTexture( myNewTexture6)];
myNewTexureK
is the new image file which changes with the button. And I update the mesh material.
materialPano.materials=materials;
mesh.material=materialPano;
The problem is that I don't know how to delete the previous texture. I tried a lot of things like that :
for(var k=0;k<materials.length;k++){
materials[k].deallocate();
scene.remove(materials[k]);
renderer.deallocateTexture(materials[k]);
renderer.deallocateMaterial(materials[k]);
renderer.deallocateObject(materials[k]);
delete materials[k];
materials[k]=null;
}
renderer.deallocateMaterial(materials);
renderer.deallocateObject(materials);
delete materials;
materials=null;
And here I do materials=[loadTexture(newTexture,...)];
And I changed the loadTexture
function like that :
function loadTexture( path ) {
var texture = new THREE.Texture( texture_placeholder );
var material = new THREE.MeshBasicMaterial( { map: texture, overdraw: true } );
var image = new Image();
image.onload = function () {
texture.needsUpdate = true;
material.map.image = this;
render();
};
image.src = path;
texture.deallocate();//new line
renderer.deallocateTexture( texture );//new line
return material;
}
But it doesn't delete anything! And without any modification of the example, I noticed that when I refresh the page, memory increases too, so there is a memory leak in the example?
Is there a way to really delete texture to avoid memory leak?
Thanks a lot!
Nobody has a solution? :( I edit the message to try to be more precise. I have :
var mesh;
function loadTexture( path ) {
var texture = new THREE.Texture( texture_placeholder );
var material = new THREE.MeshBasicMaterial( { map: texture, overdraw: true } );
var image = new Image();
image.onload = function () {
texture.needsUpdate = true;
material.map.image = this;
render();
};
image.src = path;
texture.deallocate();
renderer.deallocateTexture( texture );
return material;
}
function init(){
//some initializations, create scene, webgl renderer, ...
var materiales = [
loadTexture( '1.jpg' ),
loadTexture( '2.jpg'),
loadTexture( '3.jpg' ),
loadTexture( '4.jpg' ),
loadTexture( '5.jpg'),
loadTexture( '6.jpg' )
];
mesh = new THREE.Mesh( new THREE.CubeGeometry( 400, 400, 400, 7, 7, 7 ),new THREE.MeshFaceMaterial( materiales ) );
scene.add( mesh );
}
When I click on a button, I do :
updateTexture(){
var materiales = [
loadTexture( 'new1.jpg' ),
loadTexture( 'new2.jpg'),
loadTexture( 'new3.jpg' ),
loadTexture( 'new4.jpg' ),
loadTexture( 'new5.jpg'),
loadTexture( 'new6.jpg' )
];
mesh.material=new THREE.MeshFaceMaterial( materiales );
}
The problem is that the memory increases at each click. With only that code, it's normal, there is nothing which deletes the previous mesh.material. But I tried a lot of things like :
mesh.deallocate(mesh.material);
mesh.geometry.deallocate(mesh.material);
scene.deallocate(mesh.material);
renderer.deallocateMaterial(mesh.material);
renderer.deallocateTexture(mesh.material);
renderer.deallocateObject(mesh.material);
scene.remove(mesh.material);
And the memory still increases. I precise that I work on Firefox v 17.0.1. The leak also appears on Chrome.
Upvotes: 1
Views: 5452
Reputation: 705
Problem solved for the webgl version.
Add :
for(var k=0;k<materialsT.length;k++){
renderer.deallocateTexture(materialsT[k].map);
renderer.deallocateTexture(materialsT[k]);
materialsT[k].deallocate();
materialsT[k].map.deallocate();
}
in the changeTexture function just before materialsT=[ loadTexture(...), ...]., and
texture.deallocate();
renderer.deallocateTexture( texture );
in the loadTexture function just before the return.
But, there is still a leak for the canvas version.
Upvotes: 0
Reputation: 705
Sorry for the wait. You can test the code here : http://jodyj.com/test/ There are the canvas version and the webgl version. Just click on the button to see memory increase (in the process window for example).
For the canvas version, the memory leak appears on Firefox and Chrome but not IE. For the webgl version (not IE), Firefox and Chrome have the memory leak. I commented the code and I indicated which line creates the leak (materialPano.materials=materialsT; ). I tested with the function deallocate on mesh, material but it doesn't change anything.
Thanks!
Upvotes: 0
Reputation: 705
Here is the modification I made to http://mrdoob.github.com/three.js/examples/webgl_panorama_equirectangular.html
I added the loadTexture function from http://mrdoob.github.com/three.js/examples/canvas_geometry_panorama.html, the button to execute the changeTexture() function.
<!DOCTYPE html>
<head>
<title>three.js webgl - equirectangular panorama demo</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
background-color: #000000;
margin: 0px;
overflow: hidden;
}
#info {
position: absolute;
top: 0px; width: 100%;
color: #ffffff;
padding: 5px;
font-family:Monospace;
font-size:13px;
font-weight: bold;
text-align:center;
}
a {
color: #ffffff;
}
</style>
</head>
<body>
<div id="container"></div>
<div id="info"><a href="http://threejs.org" target="_blank">three.js webgl</a> - equirectangular panorama demo. photo by <a href="http://www.flickr.com/photos/jonragnarsson/2294472375/" target="_blank">Jón Ragnarsson</a>.<input id="changeTexture" type="button" value="Memory leak test" onclick="changeTexture();"> </div>
<script src="./build/three.min.js"></script>
<script>
var idTexture='id1';
var camera, scene, renderer;
var fov = 70,
texture_placeholder,
isUserInteracting = false,
onMouseDownMouseX = 0, onMouseDownMouseY = 0,
lon = 0, onMouseDownLon = 0,
lat = 0, onMouseDownLat = 0,
phi = 0, theta = 0;
var materialsT, materialPano;
init();
animate();
function init() {
var container, mesh;
container = document.getElementById( 'container' );
camera = new THREE.PerspectiveCamera( fov, window.innerWidth / window.innerHeight, 1, 1100 );
camera.target = new THREE.Vector3( 0, 0, 0 );
scene = new THREE.Scene();
renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
//put here your 6 textures, one per face. Of course, you can use the same texture for all the faces
materialsT = [
loadTexture( idTexture+'.jpg' ),
loadTexture( idTexture+'.jpg' ),
loadTexture( idTexture+'.jpg' ),
loadTexture(idTexture+'.jpg' ),
loadTexture( idTexture+'.jpg' ),
loadTexture( idTexture+'.jpg' )
];
materialPano=new THREE.MeshFaceMaterial( materialsT );
mesh = new THREE.Mesh( new THREE.CubeGeometry( 256, 256, 256, 7, 7, 7 ),materialPano );
mesh.scale.x = -1;
scene.add( mesh );
container.appendChild( renderer.domElement );
document.addEventListener( 'mousedown', onDocumentMouseDown, false );
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
document.addEventListener( 'mouseup', onDocumentMouseUp, false );
document.addEventListener( 'mousewheel', onDocumentMouseWheel, false );
document.addEventListener( 'DOMMouseScroll', onDocumentMouseWheel, false);
window.addEventListener( 'resize', onWindowResize, false );
}
function loadTexture( path ) {
var texture = new THREE.Texture( texture_placeholder );
var material = new THREE.MeshBasicMaterial( { map: texture, overdraw: true } );
var image = new Image();
image.onload = function () {
texture.needsUpdate = true;
material.map.image = this;
render();
};
image.src = path;
texture.deallocate();
renderer.deallocateTexture( texture );
return material;
}
function changeTexture(){
idCourant=(idTexture=='id1')?'id2':'id1';
//you can use the same texture, there is still the memory leak
materialsT = [
loadTexture( idTexture+'.jpg' ),
loadTexture( idTexture+'.jpg'),
loadTexture( idTexture+'.jpg' ),
loadTexture( idTexture+'.jpg' ),
loadTexture( idTexture+'.jpg'),
loadTexture( idTexture+'.jpg' )
];
materialPano.materials=materialsT;//without this line, I don't have memory leak but I can't change the texture. So it means that loadTexture doesn't have memory leak since the memory doesn't increase when I click on the button with only materialsT=[loadTexture(...),...] in the changeTexture() function.
//I try with the following (put before materialPano.materials=materialsT; of course) to deallocate materialPano but it doesn't do anything
/*
renderer.deallocateTexture(materialPano.materials);
renderer.deallocateMaterial(materialPano.materials);
renderer.deallocateObject(materialPano.materials);
renderer.deallocateTexture(materialPano);
renderer.deallocateMaterial(materialPano);
renderer.deallocateObject(materialPano);
//*/
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function onDocumentMouseDown( event ) {
event.preventDefault();
isUserInteracting = true;
onPointerDownPointerX = event.clientX;
onPointerDownPointerY = event.clientY;
onPointerDownLon = lon;
onPointerDownLat = lat;
}
function onDocumentMouseMove( event ) {
if ( isUserInteracting ) {
lon = ( onPointerDownPointerX - event.clientX ) * 0.1 + onPointerDownLon;
lat = ( event.clientY - onPointerDownPointerY ) * 0.1 + onPointerDownLat;
}
}
function onDocumentMouseUp( event ) {
isUserInteracting = false;
}
function onDocumentMouseWheel( event ) {
// WebKit
if ( event.wheelDeltaY ) {
fov -= event.wheelDeltaY * 0.05;
// Opera / Explorer 9
} else if ( event.wheelDelta ) {
fov -= event.wheelDelta * 0.05;
// Firefox
} else if ( event.detail ) {
fov += event.detail * 1.0;
}
camera.projectionMatrix.makePerspective( fov, window.innerWidth / window.innerHeight, 1, 1100 );
render();
}
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
lat = Math.max( - 85, Math.min( 85, lat ) );
phi = ( 90 - lat ) * Math.PI / 180;
theta = lon * Math.PI / 180;
camera.target.x = 500 * Math.sin( phi ) * Math.cos( theta );
camera.target.y = 500 * Math.cos( phi );
camera.target.z = 500 * Math.sin( phi ) * Math.sin( theta );
camera.lookAt( camera.target );
renderer.render( scene, camera );
}
</script>
</body>
I don't know how and where to use mesh.material.materials[ i ].map = texture; texture.needsUpdate = true; as you told me.
Thanks!
Upvotes: 0