How to access geometries and materials after Collada is loaded

The following code loads a Collada with the name 1.dae in the scene. A click on the element with id="red" loads a new Collada with the name 2.dae in the scene and replaced the first. I know, I have to use dispose() for the first loaded model to make sure now, that the geometries and the materials of 1.dae, which are not used anymore, gets deleted from browser cache. And here is my problem: I do not know, how to access the geometries and neither the materials of the loaded Collada to call dispose() on it. What I have to do, to get access to geometries and materials of the loaded 1.dae file?

    <script type="module">

    import * as THREE from '../three119/build/three.module.js'; //r119 31.07.2020
    import { ColladaLoader } from '../three119/examples/jsm/loaders/ColladaLoader.js'; //31.07.2020
    import { OrbitControls } from '../three119/examples/jsm/controls/OrbitControls.js'; //31.07.2020

    var canvas, camera, scene, renderer, model, controls, collada;
    var modelNumber = 1;

	init();
	animate();

	function init() {
        canvas = document.getElementById( 'canvas' );
        
        camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
        camera.position.set( 0, 0, 10 );

		scene = new THREE.Scene();

		// loading Collada when loading page
        
		var loadingManager = new THREE.LoadingManager(); 

		var loader = new ColladaLoader( loadingManager );
        
        loader.load( getModelURL(), function ( collada ) { model = collada.scene; scene.add( model ) } );

		// switch to next model

		document.getElementById ( "down" ).onclick = function () {
			
			modelNumber = modelNumber + 1;
			
			loader.load ( getModelURL (), function ( collada ) { 

				scene.remove(model);

				camera.position.set( 0, 0, 10 );
				
				model = collada.scene;
				
				scene.add( model );	

			}, undefined, function ( error ) {

				modelNumber = modelNumber - 1;

		} ) };	

		document.getElementById("up").onclick = function(){
			
			modelNumber = modelNumber - 1;
			
			loader.load ( getModelURL (), function ( collada ) { 

				scene.remove(model);
				
				camera.position.set( 0, 0, 10 );
				
				model = collada.scene;
				
				scene.add( model );
			
			}, undefined, function ( error ) {

				modelNumber = modelNumber + 1;
				
				console.log(modelNumber)

		} ) };	

		// Lights, Renderer, Controls

        var ambientLight = new THREE.AmbientLight( 0xcccccc, 0.4 );
		scene.add( ambientLight );

		var directionalLight = new THREE.DirectionalLight( 0xffffff, 0.8 );
		directionalLight.position.set( 1, 1, 0 ).normalize();
		scene.add( directionalLight );

		renderer = new THREE.WebGLRenderer();
		renderer.setPixelRatio( window.devicePixelRatio );
		renderer.setSize( window.innerWidth, window.innerHeight );
		canvas.appendChild( renderer.domElement );

        controls = new OrbitControls( camera, renderer.domElement );
        controls.addEventListener( 'change', render ); // call this only in static scenes (i.e., if there is no animation loop)
        controls.enableDamping = true; // an animation loop is required when either damping or auto-rotation are enabled
		controls.dampingFactor = 0.25;
        controls.screenSpacePanning = false;
        controls.minDistance = 10;
		controls.maxDistance = 500
        controls.maxPolarAngle = Math.PI / 2;

		window.addEventListener( 'resize', onWindowResize, false );

	};

	function onWindowResize() {

		camera.aspect = window.innerWidth / window.innerHeight;
		camera.updateProjectionMatrix();

		renderer.setSize( window.innerWidth, window.innerHeight );

	};

	function animate() {

		requestAnimationFrame( animate );

		controls.update();

		render();

	};

	function render() {

		renderer.render( scene, camera );
		
	};

    function getModelURL() {
        
		var modelFileName = '../DAE/' + modelNumber + '.dae';
        
		return modelFileName;

    };

</script>
</body>

The idea is to traverse through the object hierarchy and then access all geometries and materials. Please try:

Instead of using scene, use the code with your model variable.

1 Like

Thanks @Mugen87. With the model variable it works, even if I thought, it has to work with the scene variable too. When I use the mentioned approach i get this error:

grafik

I used a simple cube model made in SketchUp with only colors as materials. I think that’s why it’s automatically parsed as MeshLambertMaterial. Therefore I changed the code and no error appears.

model.traverse(object => {
					
	if (!object.isMesh) return

	object.geometry.dispose()
					
	console.log('dispose geometry done!')
					
	//if (!object.material instanceof THREE.MeshLambertMaterial) return

	if (!object.material.isMaterial) return

	object.material.dispose()
					
console.log('dispose material done!')})	 

I hope to find a way to control the free memory…
:fox_face: :man_shrugging:

This code is fine unless an object as multiple materials applied to it. In this case, no materials will be disposed. If the code form the other thread does not work, write cleanMaterial() less fancy like so:

function cleanMaterial(material) {
	material.dispose();
	const keys = Object.keys(material);
	for(const key of keys) {
		const value = material[key];
		if (value && value.isTexture) {
			value.dispose();
		}
	}
}
1 Like

It works perfect with “less fancy”.

grafik

Thank you. :dragon:

1 Like