Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...
jacob_truax

Performance issues with TimelineMax and Three.js

Warning: Please note

This thread was started before GSAP 3 was released. Some information, especially the syntax, may be out of date for GSAP 3. Please see the GSAP 3 migration guide and release notes for more information about how to update the code to GSAP 3's syntax. 

Recommended Posts

Hello, 

 

I am pretty new to GSAP and so I may be doing something wrong, but I am having a performance issue with multiple back and forths animating three.js objects and then reversing them. 

 

As you can see on my project (linked below) when you click the three.js objects and then click the back button all the animations work fine. But the more you click them, the slower they start to become and the longer the reverse animation takes on the objects and on the text. Now I am not sure if I set it up wrong and its just an issue with my code, or whether its a performance issue. Can someone please see my GSAP code below and see if they can pin point what might be happening?

 

Here is a link to my project: http://jacobtruax.info/

 

Code for the Tweening:

const tl = new TimelineLite()
  const tlFNUP = new TimelineLite()
  const tlOld = new TimelineLite()
  const tlAlex = new TimelineLite()
  const tlCam = new TimelineLite()
  TweenMax.set(backTag,{autoAlpha:0});
  TweenMax.set(footerTag, {autoAlpha:0});
  TweenMax.set(moreTag, {autoAlpha:0});



function onDocumentMouseDown(event) {
      const intersections = raycaster.intersectObjects(objects)
      if (intersections.length > 0){
        if(projectHov){
          tl.play();
          tl.add( TweenMax.to(footerTag, .5, {delay: 1, autoAlpha: 1,}));

          tl.to(backTag, 1, {
            delay: 1.25,
            autoAlpha:1,
          }, 0);
          tl.to(moreTag, 1, {
            delay: 1.35,
            autoAlpha: 1,
          }, 0);
        }


        if (intersections[0].object == old ) {
          if(projectHov){
            tlOld.play();
            projectHov = false
            tlOld.add(TweenMax.to(old, 1.5, {three:{scaleX: 2.5, scaleY: 2.5, x:0, y:0, z:0}, ease:Power2.easeInOut}));
            tlOld.to(fnup, 1, {three:{y:-4000, opacity: 0 }, ease:Power2.easeInOut}, 0);
            tlOld.to(alex, 1, {three:{y:-4000, opacity: 0 }, ease:Power2.easeInOut}, 0);
            tlOld.to(cam, 1, {three:{y:-4000, opacity: 0 }, ease:Power2.easeInOut}, 0);
            tlOld.to(mirrorCube, 1, {three:{y:-400, opacity: 0 }, ease:Power2.easeInOut}, 0);
          groupRotate = false
        }

        }
        if (intersections[0].object == fnup) {
          if(projectHov){
            tlFNUP.play();
            projectHov = false
            tlFNUP.add(TweenMax.to(fnup, 1.5, {three:{scaleX: 2.5, scaleY: 2.5, x:0, y:0, z:0 }, ease:Power2.easeInOut}));
            tlFNUP.to(old, 1, {three:{y:-4000, opacity: 0 }, ease:Power2.easeInOut}, 0);
            tlFNUP.to(alex, 1, {three:{y:-4000, opacity: 0 }, ease:Power2.easeInOut}, 0);
            tlFNUP.to(cam, 1, {three:{y:-4000, opacity: 0 }, ease:Power2.easeInOut}, 0);
          groupRotate = false
          tlFNUP.to(mirrorCube, 1, {three:{y:-400, opacity: 0 }, ease:Power2.easeInOut}, 0);
        }

        }
        if (intersections[0].object == cam) {
          if(projectHov){
            tlCam.play();
            projectHov = false
            tlCam.add(TweenMax.to(cam, 1.5, {three:{scaleX: 2.5, scaleY: 2.5, x:0, y:0, z:0}, ease:Power2.easeInOut}));
            tlCam.to(fnup, 1, {three:{y:-4000, opacity: 0 }, ease:Power2.easeInOut}, 0);
            tlCam.to(alex, 1, {three:{y:-4000, opacity: 0 }, ease:Power2.easeInOut}, 0);
            tlCam.to(old, 1, {three:{y:-4000, opacity: 0 }, ease:Power2.easeInOut}, 0);
          oldRotate = false
          groupRotate = false
          tlCam.to(mirrorCube, 1, {three:{y:-400, opacity: 0 }, ease:Power2.easeInOut}, 0);
        }
        }
        if (intersections[0].object == alex) {
          if(projectHov){
            tlAlex.play();
            projectHov = false
            tlAlex.add(TweenMax.to(alex, 1.5, {three:{scaleX: 2.5, scaleY: 2.5, x:0, y:0, z:0}, ease:Power2.easeInOut}));
            tlAlex.to(fnup, 1, {three:{y:-4000, opacity: 0 }, ease:Power2.easeInOut}, 0);
            tlAlex.to(cam, 1, {three:{y:-4000, opacity: 0 }, ease:Power2.easeInOut}, 0);
            tlAlex.to(old, 1, {three:{y:-4000, opacity: 0 }, ease:Power2.easeInOut}, 0);
          oldRotate = false
          groupRotate = false
          tlAlex.to(mirrorCube, 1, {three:{y:-400, opacity: 0 }, ease:Power2.easeInOut}, 0);
        }

        }

      }
  
  backTag.addEventListener("click", function() {
  projectHov = true
  groupRotate = true
  tlOld.reverse();
  tlAlex.reverse();
  tlCam.reverse();
  tlFNUP.reverse();
  tl.reverse();
})

 

Link to comment
Share on other sites

I don't really have time to dissect this, but a few quick thoughts:

  1. It looks like you're reusing the same timelines and you keep adding more and more and more tweens to them on every mousedown. That sounds very wasteful and problematic to me. After 5 clicks, you'd probably have 5 of the same tweens fighting to the control the same properties of the same object, though overwriting should handle the conflicts you still end up with a bunch of tweens running that don't need to be. I'm not even sure you need to use timelines for this (and it's not "wrong"), but I'd probably just fire off new tweens (or create a new timeline each time...that's totally fine). 
  2. If you're always animating to() certain values, are you potentially starting at values that are closer and closer to those end values, thus it LOOKS like things are slowing down just because of the logic you're using? So, for example, if the first time you animate from 0 to 1000 over the course of 1 second...but it only gets to 500 before you do something else...and then the user clicks again and it's now going from 500 to 1000 over the course of 1 second - that would move half as fast. See what I mean? 

 

Link to comment
Share on other sites

43 minutes ago, GreenSock said:

I don't really have time to dissect this, but a few quick thoughts:

  1. It looks like you're reusing the same timelines and you keep adding more and more and more tweens to them on every mousedown. That sounds very wasteful and problematic to me. After 5 clicks, you'd probably have 5 of the same tweens fighting to the control the same properties of the same object, though overwriting should handle the conflicts you still end up with a bunch of tweens running that don't need to be. I'm not even sure you need to use timelines for this (and it's not "wrong"), but I'd probably just fire off new tweens (or create a new timeline each time...that's totally fine). 
  2. If you're always animating to() certain values, are you potentially starting at values that are closer and closer to those end values, thus it LOOKS like things are slowing down just because of the logic you're using? So, for example, if the first time you animate from 0 to 1000 over the course of 1 second...but it only gets to 500 before you do something else...and then the user clicks again and it's now going from 500 to 1000 over the course of 1 second - that would move half as fast. See what I mean? 

 

 

1. I am kind of confused by this. It is not aa document mousedown, it is only when a three.js object has been raycasted (clicked). Though, I am reusing the same timeline, I was under the impression that was the point of the timeline? So a timeline is innitiated, it plays out, and to start another the user has to hit the "back" button which would then reverse() the initially selected timeline. If the person clicks the same object as the first time again it would then play() the timeline again. Is this bad practice? are they compiling somehow and thats slowing them down? 

 

2.To answer your second point, it always finishes the to() before another timeline can be triggered, becuase the objects that fire off the timelines disappear once one starts.

Link to comment
Share on other sites

It's totally fine to use timelines, especially if you need to reverse() things. Yes, that's SUPER handy for those types of animations. But at my cursory glance, you keep adding more and more and more tweens to the timeline. I don't see anywhere that you clear() it. Maybe that's part of the key here - clear() before you rebuild?

Link to comment
Share on other sites

Ah wonderful I am sure that is the issue! I will look into the docs and read about it. Now I feel like I see the issue, everytime I am clicking something I am recreating that timeline, where as I was thinking it was only creating it the once and then replaying it when the same object was clicked again. But actually its replaying the initial one and adding a new one correct? And the best way to get around this is to clear(). Is there a way to just replay a tween considering its already been reversed?

Link to comment
Share on other sites

8 hours ago, jacob_truax said:

everytime I am clicking something I am recreating that timeline, where as I was thinking it was only creating it the once and then replaying it when the same object was clicked again

 

Sort of. Technically you're not creating a new timeline instance itself (you're reusing), but you're re-populating it with more and more tweens (child animations). 

 

Instead of re-building the same thing on every mousedown, you could probably just build all those timeline animations OUTSIDE of that function (once) and then just play(0) or reverse() them accordingly. Much more efficient. Does that help? 

Link to comment
Share on other sites

Yes that is extremely helpful thank you. Its seems though that just switching the lines where I add a tweenMax

 

tlCam.add(TweenMax.to(cam, 1.5, {three:{scaleX: 2.5, scaleY: 2.5, x:0, y:0, z:0}, ease:Power2.easeInOut}));

 

to this solved the problem. Is it because now I am not creating child animations?

 

tlCam.to(cam, 1.5, {three:{scaleX: 2.5, scaleY: 2.5, x:0, y:0, z:0}, ease:Power2.easeInOut}, 0);

 

 

Link to comment
Share on other sites

Actually, those lines produce identical results except (and this is certainly important) in the first example with the full "TweenMax.to(...)" getting added, you didn't define any position parameter so it gets added to the END of the timeline whereas your second line has a position parameter of 0, thus it's added to the very beginning of the timeline. 

 

Remember that the timeline.to() method is just a shortcut for doing timeline.add( TweenMax.to(...) ). Internally it's the same. But I bet that adding it to the END of the timeline is what was messing you up before, especially because you had a bunch of other tweens in there that were piling up. See what I mean? 

Link to comment
Share on other sites

Ah wow ok I totally see what you mean. Thanks!

I have another little question. 

 

Before, I was animating the autoAlpha of an h2 element when you clicked on the three.js objects (the "more" button on my website) and it was working just fine. However, I changed the h2 element to a link and now the animation is lagging and running slower than expected. Do you know why this would happen? Below is my javascript and html. 

 

I would understand if it was the same issue as above, but as you can see I am animating other h2 elements just fine. It was only when I switched the "more" element from a h2 to a link in my html that it started acting slow. Again you can see this in action here: jacobtruax.info

 

Thanks!

 


JS

const moreTag = document.getElementById("more")



const tl = new TimelineLite()

TweenMax.set(moreTag, {autoAlpha:0});



function onDocumentMouseDown(event) {
      const intersections = raycaster.intersectObjects(objects)
      if (intersections.length > 0){
        if(projectHov){
          tl.play();
          tl.to(footerTag, .5, {delay: 1, autoAlpha: 1,}, 0);

          tl.to(backTag, 1, {
            delay: 1.25,
            autoAlpha:1,
          }, 0);
          tl.to(moreTag, 1, {
            delay: 1.25,
            autoAlpha: 1,
          }, 0);
        }

}



backTag.addEventListener("click", function() {
  projectHov = true
  groupRotate = true
  tlOld.reverse();
  tlAlex.reverse();
  tlCam.reverse();
  tlFNUP.reverse();
  tl.reverse();
})

 

 HTML

<div class="back">
    <h2 id="back">Back</h2>
  </div>

  <div class="more">
    <a href="work.html" id="more">More</a>
  </div>

 

Link to comment
Share on other sites

3 hours ago, jacob_truax said:

Below is my javascript and html. 

 

What, no CSS? 

 

That's where the problem is...

 

 

 

  • Like 2
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.

×