Adding non-visual properties to objects in Three.js: How to do it?

My question is quite vast, and I am unsure of where to begin. Please bear with me.

I am working on a project that involves the management of over 200 objects. These objects need to be displayed in a container on the side of the field, each with non-visual attributes. When a user clicks on an object, I want its attributes to be shown in the container.

How should I approach this task?

I could simply retrieve the name of the selected object and then query a dictionary for its key value pairs. However, I am wondering if there is a simpler way to achieve this.

Answer №1

To handle the click event, I leveraged a library known as threex.domevents. For more details, you can refer to the GitHub page. The code for the event is fairly self-explanatory.

Initially, domevents must be initialized within your scene in the following manner:

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

Subsequently, I designed a custom Mesh object:

// function to generate a 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;
}

// function to generate a random integer for position
var min = -50;
var max = 50;

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

// defining 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;

    // setting up 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 container has:');
        console.log(destinationContainer.userData);

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

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

The functions genRandomId and genRandomInt serve as random generators for illustration purposes. The code for generating random ids was inspired by a Stack Overflow post titled Generate random string/characters in JavaScript.

Incorporate around 200 instances of MyMesh meshes in your 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++;
}

Lastly, render the scene:

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

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

    renderer.render(scene, camera);
};

render();

A demo showcasing the complete source code can be accessed through this link:

If you open the browser console and click on a cube, you'll observe that the planeMesh alters its userData attributes with those of the clicked cube mesh.

Answer №2

Absolutely! It's perfectly fine to add your own custom keys directly onto a Three.js object without causing any issues, as long as you're careful not to overwrite any crucial built-in Three.js keys by mistake. To keep things organized and prevent conflicts, I suggest creating a designated "namespace" for all of your custom keys within the object.

For instance, if you have a Three.js object named foo, you could store all your custom keys under foo.myCustomNamespace. This way, data like foo.myCustomNamespace.name and

foo.myCustomNamespace.description
will be grouped together and won't clash with THREE.js properties.

Additionally, Three.js conveniently offers a pre-defined namespace specifically for user data called userData. You can access it via THREE.Object3D.userData.

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

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the reason behind the requirement in Javascript (ES.next) that a function must be declared as async in order to utilize await functionality?

Shouldn't a compiler or parser be intelligent enough to recognize when a function utilizes await, and automatically convert it to an async function? Why is there a requirement for me to explicitly type the async keyword? It just clutters the code, an ...

Obtaining only a portion of the text when copying and editing it

I have a React application where I am attempting to copy text from an HTML element, modify it, and then send it back to the user. I have been successful in achieving this, but I am facing an issue where even if I select only a portion of the text, I still ...

What is the best way to make ASP dropdownlist as read-only using CSS or JavaScript?

I'm having trouble setting a dropdown list to read-only. I've tried setting enabled = false, but then the font color appears blurry and distorted. The same technique works fine for textboxes using textbox.readonly = false. Is there a way to achie ...

Can the MemoryRouter be successfully nested within the BrowserRouter in a React application?

I've been on a quest for some time now, trying to uncover whether it's feasible to utilize MemoryRouter solely for specific routes while maintaining the use of BrowserRouter in general. My goal is to navigate to a particular component without alt ...

Is there a way to achieve a transparent background while animating the second text?

I am seeking to create a unique typography animation that involves animating the second text, which is colored and consists of multiple text elements to animate. The animation should showcase each text element appearing and disappearing one after the other ...

Is there a way to dynamically update the TargetControlID of an AutoCompleteExtender using client-side JavaScript?

Typically, I am able to set the TargetControlID on the server side using code similar to this: AutoCompleteExtender ace = new AutoCompleteExtender(); ace.ID = "AutoCompleteExtender1"; ace.TargetControlID = "whatever"; While I understand how t ...

Troubleshooting Vue component data management issues

I'm perplexed as to why the data is coming up as undefined even though I am passing the correct property from the component. Here is my Vue component: Vue.component('store-squaretile-component',{ template: '#store-squaretile-compon ...

transform the outcome of a $lookup operation into an object rather than an array

When performing a $lookup from a _id, the result is always 1 document. This means that I would like the result to be an object instead of an array with one item. let query = mongoose.model('Discipline').aggregate([ { $match: { ...

Windowing box inside a container box

I am looking to implement scrolling for just the "chat-messages" div within the "chat-bar" div on my site. I want only this specific section to be scrollable, while the rest of the site remains stationary. Currently, I have to scroll through the entire pag ...

Using TypeScript with Vue and Pinia to access the store

Is it necessary to type the Store when importing it to TypeScript in a Pinia Vue project? // Component <p>{{ storeForm.firstName }}</p> // receiving an error "Property 'storeForm' does not exist on type" // Store ...

Leveraging CreateBrowserRouter from React Router alongside a Redux store

I'm currently working on integrating Redux and React-Router into a React blog project. I am fetching data from an API and storing it in Redux, but for some reason, the data is not rendering and no error messages are being displayed. Here is the code ...

Calculate the variance between two variables

I am facing a challenge where I have an object and the 'Hours' field is saved as a string. I am looking to convert this string into actual hours and then calculate the difference between the two variables. const groupSchedule=[ {"days":"sat" ...

"Utilizing the Image onLoad event in isomorphic/universal React: Activating event registration once the image has been

When a page is rendered isomorphically, the image can be downloaded before the main script.js file. This means that the image may already be loaded before the react register's the onLoad event, resulting in the event never being triggered. script.js ...

Convert a String to JSON using either JavaScript or jQuery

Currently, I am developing a JavaScript animation script and I am aiming to allow individuals to define behavior declaratively within the HTML. This is the format I envision for my HTML: <div data-animation="top: 600, left: 600, opacity: 1, start: 0.2 ...

What is the method for updating state in React without relying on any events to trigger

I am trying to continuously update the value of a counter variable at fixed intervals in my code. Here is what I have so far: class Counter extends React.Component { constructor(props) { super(props); this.state = { myCount: 1 ...

Live notification application using node.js

I am looking to create a recipe maker webapp for practice purposes. This webapp will consist of 2 main pages: the index page and the recipes page. On the "index" page, users can create their own recipes. On the "recipes" page, users can view a table ...

Guide on leveraging socket post connection event in socket.io

Apologies for any language barriers. I am facing an issue with my app.js server. I have implemented sockets and utilize the join event within the 'connection' event. A function inside the 'connection' event requires a socket parameter, ...

Is there a way to identify the presence of a mouse on a website?

In the process of developing a website, I encountered a dilemma with navigation buttons. They needed to be large for aesthetic reasons and ease of use but had to be small when not in use. To address this, I decided to shrink the buttons into thumbnails on ...

Using cURL instead of AJAX for PHP requests

My current situation may seem simple, but it feels like a tough challenge for me right now. I am attempting to scrape a website that utilizes AJAX calls to retrieve data. This website has a form where you can select options and then click the submit butt ...

Is there a way to prevent pushing the same object into an array when adding objects to it?

While working on my project, I encountered an issue when creating a new array with objects checked in the checkboxes. Upon submitting, I received an error message: "flattenChildren(...): Encountered two children with the same key, .$3. Child keys must be u ...