Jump to content
Search Community

How to loop over Three objects nested in a GLTF import?

Robert Wildling test
Moderator Tag

Recommended Posts

May I first say that I tried countless examples and templates for three and vue on codepen, stackblitz, jsfiddle and codesandbox, but to no avail. GLTFLoader (and OrbitControls) make problems when imported from somewhere else, at least with the latest versions. After 2 days I decided to move on and ask my question and provide a github repo. Of course I do understand, if you won't look at it. But, as I said: I couldn't make it work anywhere, so this is really all I can do... for what's it worth here ti is: https://github.com/rowild/three-and-gsap-and-gltf

I'll try to explain my problem anyway, maybe a codepen is not necessary.

I import a gltf model successfully into a three scene. The gltf model contains many little cubes that I would eventually like to manipulate with gsap. (There is a post with an image on stackexchange: https://blender.stackexchange.com/questions/301825/how-to-convert-separate-linked-faces-to-individual-meshes/301828#301828)

The essential code for importing that model is: 

const gltfLoader = new GLTFLoader()
gltfLoader.load(
    '/models/ball.gltf',
    (gltf) =>
    {
        scene.add(gltf.scene)

        const allCubes = []

        gltf.scene.children.forEach(cube => {
            cube.castShadow = true
            cube.receiveShadow = true
            cube.scale.set(0.2, 0.2, 0.2)

            allCubes.push(cube)
        })

        console.log('allCubes =', allCubes);

        // gsap.to( gltf.scene.children, {
        //     duration: 2,
        //     "scale.x": 1,
        //     stagger: {
        //         amount: 0.1,
        //         grid: "auto",
        //         from: "center"
        //     }
        // })
    }
)

The result of logging `gltf.scene`  to the console is shown in the screenshot.

In order to get hold of the cubes, I save the to a new array `allCubes`, which is meant for GSAP, but this might not be necessary, since they can be accessed directly via `gsap.scene.children` if I am not mistaken. However, neither of those work when the gsap object is created (it is meant to scale the cubes to Vector3(1, 1, 1) again after having been set to 0.2). Instead I get this error in the console:

```
gsap-core.js:732 Uncaught (in promise) TypeError: a[(wrapAt++)].getBoundingClientRect is not a function
    at gsap-core.js:732:41
    at new Tween2 (gsap-core.js:3254:48)
    at Object.to (gsap-core.js:3618:12)
    at Index.vue:168:9
    at GLTFLoader.js:228:6
    at GLTFLoader.js:2553:5
```
 

What do I have to do to be able to let gsap operate on each of the cubes sequentially?


Thank you!
 

 

Screenshot 2023-09-29 at 22.03.15.png

See the Pen by (@) on CodePen

Link to comment
Share on other sites

Hi,

 

I don't have a lot of experience with THREE so I can't do a lot to replicate your issue. Most likely this seems related to the fact that you're passing an object to GSAP in a way it can't be handled. You need to target the x property of the scale object.

 

One option I can think of is to create an array of objects that you can tween and use the onUpdate method to apply the changes to each cube element, but that would imply to loop through all the cubes in the callback in order to apply the scale values to each cube:

const scales  = gltf.scene.children.map(cube => {
  cube.castShadow = true;
  cube.receiveShadow = true;
  cube.scale.set(0.2, 0.2, 0.2);
  return { x: 0.2 };
});

Then you can run GSAP with advanced staggers on that array:

gsap.to( scales, {
  duration: 2,
  x: 1,
  stagger: {
    amount: 0.1,
    grid: "auto",
    from: "center"
  },
  onUpdate: updateScales,
});

Sorry I can't be of more assistance, but this is not really a GSAP issue but a limitation of sorts in the way THREE (and most of the WebGL libraries I know for that matter) works when it comes to it's display objects/geometries.

 

Hopefully this helps.

Happy Tweening!

  • Like 1
Link to comment
Share on other sites

@Rodrigo Thank you very much for your insights! Always an eye-opener! (And sorry for replying so late.)

I ams till trying to figure put what "updateScales" would look like. And if that solution wouldn't apply the same scale amount to all cubes already existing...
But first and foremost I do understand your argument of the 2 loop-run-throughs on each iteration and that the difference in architecture makes my approach rather impossible. I will look for options in Three itself. If a follow-up question comes along, I will post again. 

Thank you and, as you say: Happy tweening!

Link to comment
Share on other sites

Hi,

 

Yeah most likely the update callback would involve looping through all the elements.

 

Another option could be to create an array of  dummy Objects, animate the properties of those using advanced staggers and using the object's set method to update the corresponding THREE cube.

 

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set

 

Something like this:

See the Pen dywqpJZ by GreenSock (@GreenSock) on CodePen

 

Just loop through the cubes, create an object for each and point each cube when updating that particular object.

 

Hopefully this helps

Happy Tweening!

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...