nglviewer / ngl

WebGL protein viewer
http://nglviewer.org/ngl/
MIT License
657 stars 168 forks source link

Apply multiple rotations #970

Closed gbayarri closed 1 year ago

gbayarri commented 1 year ago

I would like to rotate multiple times a structure and I don't know what I'm missing, but the rotation is applied only once.

Here is a test code:

var stage = new NGL.Stage( "viewport" );

stage.loadFile("rcsb://4cup", { defaultRepresentation: true }).then(function () {
   setInterval(() =>  {
     stage.compList[0].setRotation( [1, 0, 0 ])
     console.log(stage.viewerControls.getOrientation())
   }, 1000)
})

https://codepen.io/gbayarri/pen/JjaWXGx

I want to rotate 1 radian in the X axis every second.

This only applies the rotation once, the first time, so it seems that I should get the current rotation previously and calculate the new one from the old one. The problem is how to get the current rotation? I tried to decompose the Matrix4 current orientation and modify the rotation with the value given by the component after setRotation() (component.quaternion) but it doesn't work either.

Any ideas? Thanks!

fredludlow commented 1 year ago

A quick way to do it:

var stage = new NGL.Stage( "viewport" );

stage.loadFile("rcsb://4cup", { defaultRepresentation: true }).then(function () {
   var n = 0
   setInterval(() =>  {
     stage.compList[0].setRotation( [n++, 0, 0 ])
     console.log(stage.viewerControls.getOrientation())
   }, 1000)
})

You can look at AnimationControls.spinComponent as well: https://codepen.io/fludlow/pen/jOvBjYX

stage.loadFile("rcsb://4cup", { defaultRepresentation: true }).then(function (c) {
   stage.animationControls.spinComponent(c, );
})

Docs for spinComponent on this page: https://nglviewer.org/ngl/api/class/src/controls/animation-controls.js~AnimationControls.html#instance-method-spinComponent

gbayarri commented 1 year ago

Hi @fredludlow , thanks for your answer.

I've tried before the incremental for the setRotation(), but if you execute it, you will see that the getOrientation() returns always the same value:

https://codepen.io/gbayarri/pen/JjaWXGx?editors=1111

This example was for simplifying things, but I have the orientation of the structure saved in a JS object and I need to update it. So as I said in my previous message, I think the key would be to get the current rotation after updating it.

My idea was to create 3 sliders for X, Y and Z and build a custom rotation where I can assign the angles with precision. Then, save this angles in a JS structure and in a JSON file.

As I need to assign exact values to the rotation, I discarded the spinComponent() at the beginning.

Thanks!

fredludlow commented 1 year ago

I think that's because you're asking for the viewer's rotation matrix (i.e, when you use the mouse to rotate the view, you're not actually rotating the molecule, you're rotating the whole scene). I know there's a bit of a disconnect between the order of operations used in NGL (which is loosely CAD-based) and those typically used in game design. In e.g. a FPS game, the camera (player) moves around a world, whereas in NGL the camera always looks along some arbitrary 'z' direction. Dragging the mouse moves the world underneath the camera (this corresponds to the viewer matrix). It would probably be good to have a diagram explaining what all the transformations are and the order they get applied!

I think this snippet does the right thing (you can see the updated values in the console log)

var stage = new NGL.Stage( "viewport" );

stage.loadFile("rcsb://4cup", { defaultRepresentation: true }).then(function () {
   var n = 0
   setInterval(() =>  {
     stage.compList[0].setRotation( [n++, 0, 0 ])
     console.log(stage.compList[0].matrix)
   }, 1000)
})
fredludlow commented 1 year ago

some arbitrary 'z' direction.

Actually, arbitrary isn't quite the right word - if you load a molecule and don't rotate anything, the default view is such that you're looking down the z-axis in the molecule's coordinates - rotating the scene - (mouse-drag) updates the viewer's orientation matrix. Rotating a component as you're doing updates its own internal matrix.

gbayarri commented 1 year ago

Ok, so the problem (as I suspected) is that I'm trying to apply rotation to a component and then get the orientation of the viewer. Am I right?

So as I need to modify the viewer orientation in order to save it, what I've finally done is to use the stage.viewerControls.spin() function and it seems to work:

https://codepen.io/gbayarri/pen/NWLvJXj

This function only spins one degree every second.

Thanks!