javascriptthree.js3dmouseeventraycasting

Empty {} or undefined response when raycasting GLB 3d model for retrieving userData


I have read several posts about this but I still can figure out what is happening on my code. I have a THREE.JS scene and I'm loading some GLB models in it. What I want to do is attach some data coming from JSON to each model and retrieve this data when I hover the mouse over it. My issue is that I'm getting a {} or undefined from the raycast response whenever I hover the objects in the scene.

When I compare it to other similar questions I found, users are telling the person with the similar issue to do what I already did (using intersectObjects and the true flag; or adding the objects to intersect to a separate array).

This is my code for loading the models:

const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath('jsm/libs/draco/gltf/');

const loader = new GLTFLoader();
loader.setDRACOLoader(dracoLoader);

function loadModel(loader, modelToLoad, jsonDestinationData, jsonItemInfo) {
    loader.load(
        modelToLoad,
        function (gltf) {
            const model = gltf.scene;
    
            model.userData = {
                description: jsonItemInfo.description,
                type: jsonItemInfo.type
            };
            model.translateX(jsonDestinationData.length);

            itemsToRead.push(model);
            scene.add(model);
            console.log(model.userData);
        },
        undefined,
        function(e) {
            console.error(e);
        }
    );
}

From this first console.log(model.userData) I can see the information is there. I can read the information I want printed in the console.

This is my code for the raycast:

raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObjects(itemsToRead, true);
if (intersects.length > 0) {
   var selectedObject = intersects[0].object;
   console.log(selectedObject.userData);
}

From this second console.log(selectedObject.userData) when the the intersect function is executed during the hover, I get the {} printed in the console instead of the userData I was expecting to see.

Is it possible to add the userData to a model this way (I read in another post someone saying that it might not be possible to add userData to imported models, but no one confirmed it)? Is there something missing in the raycast function to correctly retrieve the data or for this case this operation isn't possible?


Solution

  • Ok, I found a solution.

    I don't know if it's the only one, but it worked for the code I posted above.

    I didn't found this in any other question here in the Stack Overflow, so I'm gonna leave the answer here in case anyone has a similar case. One of those suggested Google's AI answers from the top of the page when you search something was the one who pointed me in the right direction of what was missing.

    The issue was in the way I was setting the userData. Instead of setting it directly like this:

    model.userData = {
        description: jsonItemInfo.description,
        type: jsonItemInfo.type
    };
    

    The correct way is to add the info from a success callback function inside the loader.load. This is the code for the callback:

    model.traverse((loadedModel) => {
            loadedModel.userData.description = jsonItemInfo.description;
            loadedModel.userData.type = jsonItemInfo.type;
        }
    );
    

    And the full code previously presented after the update is:

    function loadModel(loader, modelToLoad, jsonDestinationData, jsonItemInfo) {
        loader.load(
            modelToLoad,
            function (gltf) {
                const model = gltf.scene;
        
                model.translateX(jsonDestinationData.length);
    
                itemsToRead.push(model);
                scene.add(model);
    
                model.traverse((loadedModel) => {
                        loadedModel.userData.description = jsonItemInfo.description;
                        loadedModel.userData.type = jsonItemInfo.type;
                    }
                );
            },
            undefined,
            function(e) {
                console.error(e);
            }
        );
    }