OutlineEffect on imported GLB models with multiple meshes

Hey everyone, I have been writing a program where you can import 3D models, move them around, scale them, rotate them, etc. Right now I’m trying to produce an outline effect around the 3D models on hover (like in games like the sims). To do this I have been using the OutlineEffect from THREE postprocessing library. Refer to docs here

It works really nicely for basic Geometry such as BoxGeometry or SphereGeometry but because it relies on a model’s mesh to produce the effect, models imported via GLTF Loader (I’m only allowing glb files to be imported at the moment), which can sometimes have multiple meshes only make it possible to highlight the outline of specific segments as each mesh relates to a different part of the overall model.

In my efforts to develop a solution, I attempted to merge all of the meshes of a imported model via the two functions below (I developed the mergeMeshes function based on this question) :

/** Get Array of meshes from imported model */
    getMeshes = model => {

        // Traverse model and get all meshes
        let meshes = []
        model.traverse(child => {
            if (child.type != 'Mesh' && child.type != 'SkinnedMesh') return
            meshes.push(child)
        })

        return meshes
    }

    /** Merge Array of meshes */
    mergeMeshes = (meshes) => {
 
        let materials = [],
        geometries = [],
        mergedGeometry = new THREE.BufferGeometry(),
        meshMaterial,
        mergedMesh;

        meshes.forEach((mesh, index) => {
            mesh.updateMatrix();
            geometries.push(mesh.geometry);
            meshMaterial = new THREE.MeshStandardMaterial(mesh.material);
            materials.push(meshMaterial);
        });

        mergedGeometry = BufferGeometryUtils.mergeBufferGeometries(geometries, true);
        mergedGeometry.groupsNeedUpdate = true;

        mergedMesh = new THREE.Mesh(mergedGeometry, materials);

        return mergedMesh;
       
    }

I pass the model returned from GLTFLoader to the getMeshes() function and merge the returned array of meshes via the mergeMeshes() function. then add the mergedMesh to the scene instead the object returned by GLTFLoader. FYI, I only do this for models that contain more than one mesh, otherwise i just use the single mesh contained within the model.

So this seemed to work but during testing i realised there were two exception cases. 1) models that have built-in animation, the outline doesn’t match the model as it moves and just remains static. 2) Very complex models which have a large amount of meshes (like more than 50) the merging process just seems to break the models all together, making certain parts grow big while other stay the same size.

So what I’m asking here is if anybody has attempted the same thing as me and developed a better system in which to achieve this goal or if there is a way to improve or change the way i am merging meshes for the better. Even if you have an idea as to fix my two exception case or why they might be happening. It would go a long way in helping my debug this problem. Thanks in advance for any help you can give me.

Also before anybody asks, I’m not sure if i could produce a reliable fiddle as there is a lot of non relevant code used to make everything work and not sure i could produce a working fiddle summarising all that.

If you want to support any glTF/GLB model, including those with animation, you’ll need to find a way to display outlines that doesn’t require merging the meshes first. Merged scenes are not going to animate correctly.

THREE.OutlineEffect does not require this merging, outlinePass.selectedObjects = [...] is an array — would that work here?

1 Like

Hey donmccurdy, thanks for the reply. Using an array of meshes as input instead of a single mesh would help me tremendously. Is THREE.OutlineEffect different from the one in postproccesing? If so, are there docs for it i can look at?

This is examples/jsm/postprocessing/OutlinePass.js, and I’m looking at the example here:

https://threejs.org/examples/?q=outline#webgl_postprocessing_outline

There are no docs for the official OutlineEffect (PRs are always welcome to start them), just the example and the general postprocessing docs. I’m not sure what the third-party postprocessing library you linked to is, or how it differs from the official version though.

Ok cool. I’ve since realised that i was being kinda stupid about my approach to all of this. I never needed to merge meshes. I just needed to add the effect to all meshes in a model. That is working nicely. However, I’m still facing the same issue where the outline doest stick to animated models, just the static mesh. Not sure if there even is a solution to that. I might have to investigate THREE.OutlineEffect and see if thats any better but its gonna be tough without any docs. I appreciate your responses though. They did help.