google / model-viewer

Easily display interactive 3D models on the web and in AR!
https://modelviewer.dev
Apache License 2.0
6.88k stars 816 forks source link

Selecting Specific Frames in an Animation #1241

Closed methot-ilya-3ds closed 4 years ago

methot-ilya-3ds commented 4 years ago

Other GLTF viewers include a means of stepping through an animation's frames.

Is there a way to start/stop an animation on a specific frame?

My hope is to connect the animation frame to HTML scrolling in order to progress an animation as a user scrolls down the page.

elalish commented 4 years ago

Yes, there is a currentTime property which can be set to seek the animation to the desired time. So long as you set that on each raf callback, I think you can accomplish what you're after. Please let me know if you have any trouble.

methot-ilya-3ds commented 4 years ago

This is working for me, modelViewer.currentTime seems to work just fine

mesmaili151 commented 4 years ago

@methot-ilya-3ds Hi, can you share your project code?

methot-ilya-3ds commented 4 years ago

@mesmaili151 Sure, here is the script I used along with the model viewer. I have not progressed the project as of yet as I am still awaiting the addition of animated cameras.

<model-viewer onload="StartScroll()" id="car_crash" shadow-intensity="1" autoplay shadow-softness="1" preload currentTime="0" skybox-image= "Images/darkMirror.hdr"  poster="Images/loading.gif" src="Example/Source" alt="An animated car crash"  camera-target="0m 0m 0m">
<script> 
   function Focus_Bleu() {
             const modelViewer = document.querySelector('#car_crash');
             modelViewer.currentTime = window.scrollY / 100;    
             window.requestAnimationFrame(Focus_Bleu);
         }

   function StartScroll() {
      window.requestAnimationFrame(Focus_Bleu);
   } 
</script>
elalish commented 4 years ago

@methot-ilya-3ds While you're waiting for us to add support for glTF cameras, keep in mind that we still perform camera interpolation even when camera-controls is off, so you can set camera-orbit and camera-target in time with your animation to get pretty smooth camera motion.

methot-ilya-3ds commented 4 years ago

Using the following code I have been able to setup:

  1. Scrolling to progress the animation
  2. Smooth camera movement during a scroll

This will work until the glTF cameras are added, however you can see how this process of creating inline keyframes is much more tedious.

var scrollMaxY = Math.max( document.body.scrollHeight, document.body.offsetHeight, 
                   document.documentElement.clientHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight ); // max scroll distance

                     var AnimBegin = 0; // beginning of animation
                     var AnimEnd = 2.3; // end of animation
                     var AnimDuration = AnimEnd- AnimBegin; // duration of the animation

                     var CurrentTime = AnimBegin + ((window.scrollY / scrollMaxY) * AnimDuration); // uses the max scroll distance to interpolate through the animation frames                  

                     modelViewer.currentTime = CurrentTime;

                     // Create keyframes by choosing start and end points for when to start camera movement
                     if(CurrentTime >= 0 && CurrentTime < 1) {

                        var StartCamMovement = 0;
                        var EndCamMovement = 1;
                        var TotalAnimationDuration= EndCamMovement - StartCamMovement;

                        var InitCamPos = 90; // initial camera position
                        var FinalCamPos = 0; // final camera position
                        var DeltaCamPos = FinalCamPos - InitCamPos; // total change in Camera position

                        var Rotation = StartCamMovement + ((CurrentTime / TotalAnimationDuration) * DeltaCamPos); 

                        currentrotation = Rotation; // This global variable is necessary since it does not seem simple to extract the current rotation from the modelViewer.cameraOrbit string

                        modelViewer.cameraOrbit = Rotation +'deg, ' + Rotation + 'deg, 5m';
elalish commented 4 years ago

@methot-ilya-3ds Agreed, and thank you for sharing your work-around. I'm sure others will also find it useful. Also, if you don't have any more than these two keyframes, you can also use the calc(env(window-scroll-y)) approach as discussed in #1265.

methot-ilya-3ds commented 4 years ago

I've encountered an odd bug with camera-Orbit:

Although I have been setting the camera-orbit distance and rotation: (0deg, 0-360deg, 0 - 50m)

there is no change at all to the camera distance or the camera angle when these values specifically change.

When changing the following values: (0-360deg, 0deg, 0m) the camera moves laterally and orbits around the object.

This creates a problem for zooming in on objects or adjusting the camera angle in the y-coordinate plane.

elalish commented 4 years ago

@methot-ilya-3ds I'm having a little trouble following exactly what the problem is; a Glitch would be helpful so I can see what you mean. You're welcome to remix our official one from your own account.

methot-ilya-3ds commented 4 years ago

I've uploaded my example to the following page

In the example scrolling the page will change ALL the values of the camera-orbit variable.

elalish commented 4 years ago

@methot-ilya-3ds Thank you! A couple things; first it's using v0.9 instead of v1.0. This was my fault; I just updated our Glitch example to remove the @version so that it will automatically pick the latest. Second, since you're setting the radius to the same value as the rotations, I believe it is being clamped to its min/max since meters and degrees tend to be at different scale. You may want to set your min/maxCameraOrbit or multiply your commanded radius until it's a more realistic scale.

methot-ilya-3ds commented 4 years ago

@elalish Thank you for your assistance with this problem.

All my changes to original code can be found in the Glitch link I have provided above.

I experimented with the min/max CameraOrbit settings. Changing the maxCameraOrbit settings will change the initial camera settings, but further changes to phi and radius through code have no apparent effect.

I've modified my code so although the Phi, Theta, and Radius are all being changed at the same rate, the maximum value is set to 10 which should not cause any problems for the radius while still showing visible camera changes.

In the example I added a separate keyframe which changes the camera orbit when you scroll down far enough however you can still see that only the phi value changes.

                     if(CurrentTime > 1) { 
                        modelViewer.cameraOrbit = "90deg, 45deg, 1m";
                     }

When checking the console the .cameraOrbit variables ARE changing but there are no visual changes.

elalish commented 4 years ago

@methot-ilya-3ds This is a really cool example of advanced functionality. I like it especially because I'm an aerospace engineer and I did a bunch of CFD visualization earlier in my career. Definitely the highest and best use of glTF - how did you export it?

This may be a crazy idea, but would you be willing to submit a PR adding an example like this to our dev pages? If that model or something similar can go up under a CC-BY license, then I'd be happy to review the PR to help make the demo work and fix whatever bugs it exposes in model-viewer. I noticed a couple things looking through your glitch, but talking here is not the most efficient way to fix it.

methot-ilya-3ds commented 4 years ago

There would need to be some talk with my team before I can confirm that this is possible.

Let's talk further about the logistics of your proposal over email. I found your twitter account linked to your thingiverse page. I've followed you on Twitter and we can exchange emails there. My handle is @Methotilya

mesmaili151 commented 4 years ago

@methot-ilya-3ds thanks for sharing your project, I have same problem with

                     if(CurrentTime > 1) { 
                        modelViewer.cameraOrbit = "90deg, 45deg, 1m";
                     }

and how you exported the 3dmodel?! its really cool

mesmaili151 commented 4 years ago

@methot-ilya-3ds try this code:

 if(CurrentTime > 1) {
    modelViewer.cameraOrbit = "calc(-50rad * -5rad)   calc(80deg + env(window-scroll-y) * 0deg) calc(10m - env(window-scroll-y) * 1.5m)";
}
methot-ilya-3ds commented 4 years ago

@mesmaili151 Thank you very much! Your code helped me realize that my syntax was wrong the whole time. .cameraOrbit does not expect commas in between its values and as a result it was only able to interpret the phi value but not the radius or theta!

As for the model, my company works a lot with mechanical simulations and these are a few results which are available to be presented to the public. I use Blender for animating and editing.