1

I have a rather broad question, but no idea how to tackle that. So forgive me.

I am trying to have several (like 200 and more) objects and, let's just say, a container to the side of the field, where I draw the objects. Now what I want is, that each object has some non visual attributes and when I click on that object, the attributes should appear in that container.

Now I could go about it?

I mean, I know I can ask for the name of the selected object and then do a key value query from some dictionary. Question is, whether there is an easier way to go about it.

Nelnel
  • 61
  • 1
  • 5

2 Answers2

2

For the click event I used a library called threex.domevents, check the GitHub page for more information, the code for the event it's self explanatory.

First domevents needs to be initialized in your scene like this:

var domEvents = new THREEx.DomEvents(camera, renderer.domElement);

Then I created a custom Mesh object:

// random id
function genRandomId()
{
    var text = "";
    var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

    for( var i=0; i < 5; i++ )
        text += possible.charAt(Math.floor(Math.random() * possible.length));

    return text;
}

// random int for position
var min = -50;
var max = 50;

function genRandomInt(min, max) {
    return Math.floor(Math.random() * (max - min)) + min;
}

// custom mesh --------------------------------------------
function MyMesh(geometry, material, destinationContainer) {
    THREE.Mesh.call(this, geometry, material);

    this.userData = {
        foo1: genRandomId(),
        foo2: genRandomId(),
        foo3: genRandomId(),
    };

    this.position.x = genRandomInt(min, max);
    this.position.y = genRandomInt(min, max);
    this.position.z = genRandomInt(min, max);

    var that = this;

    // click event listener
    domEvents.addEventListener(this, 'click', function(event) {
        console.log('clicked object on position:');
        console.log(that.position);

        destinationContainer.userData = that.userData;

        console.log('Now the conainer has:');
        console.log(destinationContainer.userData);

        destinationContainer.userData = that.userData;
    }, false);
}

MyMesh.prototype = Object.create(THREE.Mesh.prototype);
MyMesh.prototype.constructor = MyMesh;

genRandomId and genRandomInt are random generators for the pourpose of illustrating this example, I took the code for the random ids from Generate random string/characters in JavaScript.

In your scene you can generate 200 (or more) MyMesh meshes and add them to the scene:

const color = 0x156289;
const emissive = 0x072534;

var planeGeometry = new THREE.PlaneGeometry(5, 5);
var planeMaterial = new THREE.MeshPhongMaterial({
    color: color,
    emissive: emissive,
    side: THREE.DoubleSide,
    shading: THREE.FlatShading
});

var planeMesh = new THREE.Mesh(planeGeometry, planeMaterial);

scene.add(planeMesh);

var objGeometry = new THREE.BoxGeometry(1, 1, 1);
var objMaterial = new THREE.MeshPhongMaterial({
    color: color,
    emissive: emissive,
    shading: THREE.FlatShading
});

var i = 0;

while (i < 200) {
    scene.add(new MyMesh(objGeometry, objMaterial, planeMesh));
    i++;
}

And finally render the scene:

var render = function() {
    requestAnimationFrame(render);

    planeMesh.rotation.x += 0.010;
    planeMesh.rotation.y += 0.010;

    renderer.render(scene, camera);
};

render();

This is a demo with the full source code: http://run.plnkr.co/plunks/W4x8XsXVroOaLUCSeXgO/

Open the browser console and click on a cube and you'll see the that planeMesh is switching its userData attributes with the ones of the clicked cube mesh.

Community
  • 1
  • 1
Marcs
  • 3,768
  • 5
  • 33
  • 42
1

Yes, that's fine. You can put your own custom keys directly on a Three.js object and it shouldn't bother it as long as you don't accidentally overwrite an important built-in Three.js key. For that reason I'd recommend that you put all of your custom keys in a "namespace" on the object so they're nice and neat and contained.

For example, if you had a Three.js object foo, you could put all your keys under foo.myCustomNamespace, so that your custom data like foo.myCustomNamespace.name, foo.myCustomNamespace.description, etc. are all together and won't interfere with THREE.js properties.

Edit: Three.js provides a built-in namespace for user data called, conveniently, userData. Access it on THREE.Object3D.userData.

https://github.com/mrdoob/three.js/blob/master/src/core/Object3D.js#L92

jered
  • 11,220
  • 2
  • 23
  • 34
  • 3
    Should maybe add: three.js already has an object named `userData` in every Object3D-instance for exactly this purpose: https://github.com/mrdoob/three.js/blob/master/src/core/Object3D.js#L92 (data in that object will be cloned and serialized automatically) – Martin Schuhfuß Nov 05 '16 at 22:02