[ThreeJS Force Graph] Dispose deallocated Material array bugfix

in utopian-io •  5 months ago

image.png

This contribution is a bugfix to ThreeJS Force-Directed Graph Javascript library authored by @vasturiano. It is a WebGL subclass of three.js Javascript 3D library to represent graph data in 3-dimensional geometry using force-directed physics.

Repository

https://github.com/vasturiano/three-forcegraph

image.png

Lastly I was studying how to interact with 3d-oriented graph data using three.js and @vasturiano's 3D Force-Directed Graph. During building complex data structues I decided to represent some of graph nodes as BoxGeometry

Although the task is simple, I couldn't get it to work.

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 );

Above code works fine. The difference occurs when I had to set an array of materials to describe each of 6-side box separately - THREE.Mesh allows this kind of usage but it bring unexpected consequences.

Issue

.nodeThreeObject(node => {
    var box = new THREE.BoxGeometry(10, 10, 10);
    var materials = [
        new THREE.MeshStandardMaterial({color: 'red'}),
        new THREE.MeshStandardMaterial({color: 'green'}),
        new THREE.MeshStandardMaterial({color: 'blue'}),
        new THREE.MeshStandardMaterial({color: 'cyan'}),
        new THREE.MeshStandardMaterial({color: 'magenta'}),
        new THREE.MeshStandardMaterial({color: 'yellow'}),
    ];
    // 'materials' is of type Array()
    return new THREE.Mesh(box, materials);
});

https://gist.github.com/mys/ff6100af32790ed99890cf4378a14020

If we set custom cube, set of more than one material and modify graphData after, error occurs:

image.png

Through reversing code libraries and picking out whether it is issue of Texture class, Material or Mesh I have finally found dispose() function throwing error:

// Clear the scene
for (var t = function t(e) {
    e.geometry && e.geometry.dispose(),
    e.material && e.material.dispose(), << error
    e.texture && e.texture.dispose(),
    e.children && e.children.forEach(t)

It seemed that e.material was type of Array(). Like we all know, javascript arrays don't have dispose() activity. All is clear now.

@vasturiano's comment: Ah, I wasn't aware a mesh could have an array of materials. Neat.

Solution

My idea was to check whether we deal with an array or object type. Then each children element (material) dispose in a loop.

if (obj.material) {
    if (Array.isArray(obj.material)) {
        obj.material.forEach(material => {
            material.dispose();
        });
    }
    else {
        obj.material.dispose();
    }
}

@vasturiano's did only one correction for performance. instanceof Array is much more effective than isArray(). Often we deal with tens of thousands objects iteracting each other. Every single performance is significant in 3D rendering.
Good to know there is much difference between instanceof Array and isArray(), even if they give same result.

I don't mind if project's author merged this code by himself. I just wanted to make sure this library suit my needs for my new Steem project (incoming).

if (obj.material) { obj.material instanceof Array ? obj.material.forEach(m => m.dispose()) : obj.material.dispose(); }

Final change


Small teaser of a project I am working on

Links

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!
Sort Order:  

Thank you for your contribution. Its good to catch those bugs and fix it.

Your contribution has been evaluated according to Utopian policies and guidelines, as well as a predefined set of questions pertaining to the category.


Need help? Write a ticket on https://support.utopian.io/.
Chat with us on Discord.
[utopian-moderator]

Hey @mys
Thanks for contributing on Utopian.
We’re already looking forward to your next contribution!

Want to chat? Join us on Discord https://discord.gg/h52nFrV.

Vote for Utopian Witness!

please stop auto voting my comments.

·

I appreciate Your work as much as @steemhunt do. If they stop so do I.

·
·

%0.5 is not much of a appreciation. Anyway, your votes getting annoying as they trigger the notifications everytime I make comment. Please stop.

Congratulations @mys! You have completed the following achievement on Steemit and have been rewarded with new badge(s) :

Award for the number of upvotes

Click on the badge to view your Board of Honor.
If you no longer want to receive notifications, reply to this comment with the word STOP

Do not miss the last post from @steemitboard:
SteemitBoard World Cup Contest - Russia vs Croatia


Participate in the SteemitBoard World Cup Contest!
Collect World Cup badges and win free SBD
Support the Gold Sponsors of the contest: @good-karma and @lukestokes


Do you like SteemitBoard's project? Then Vote for its witness and get one more award!

Your study was great with coding knowledge

Congratulations @mys! You have completed the following achievement on Steemit and have been rewarded with new badge(s) :

Award for the number of comments received

Click on the badge to view your Board of Honor.
If you no longer want to receive notifications, reply to this comment with the word STOP

Do not miss the last post from @steemitboard:
SteemitBoard World Cup Contest - Home stretch to the finals. Do not miss them!


Participate in the SteemitBoard World Cup Contest!
Collect World Cup badges and win free SBD
Support the Gold Sponsors of the contest: @good-karma and @lukestokes


Do you like SteemitBoard's project? Then Vote for its witness and get one more award!

Just as the meaning of the top illustration in this article, your efforts have also set a star in the sky.👍