camera-rock.ts 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. /**
  2. * Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. */
  6. import { Camera } from '../../../mol-canvas3d/camera';
  7. import { clamp } from '../../../mol-math/interpolate';
  8. import { Quat } from '../../../mol-math/linear-algebra/3d/quat';
  9. import { Vec3 } from '../../../mol-math/linear-algebra/3d/vec3';
  10. import { degToRad } from '../../../mol-math/misc';
  11. import { ParamDefinition as PD } from '../../../mol-util/param-definition';
  12. import { PluginStateAnimation } from '../model';
  13. const _dir = Vec3(), _axis = Vec3(), _rot = Quat();
  14. type State = { snapshot: Camera.Snapshot };
  15. export const AnimateCameraRock = PluginStateAnimation.create({
  16. name: 'built-in.animate-camera-rock',
  17. display: { name: 'Camera Rock', description: 'Rock the 3D scene around the x-axis in view space' },
  18. isExportable: true,
  19. params: () => ({
  20. durationInMs: PD.Numeric(4000, { min: 100, max: 20000, step: 100 }),
  21. speed: PD.Numeric(1, { min: 1, max: 10, step: 1 }, { description: 'How many times to rock from side to side.' }),
  22. angle: PD.Numeric(10, { min: 0, max: 180, step: 1 }, { description: 'How many degrees to rotate in each direction.' }),
  23. }),
  24. initialState: (p, ctx) => ({ snapshot: ctx.canvas3d!.camera.getSnapshot() }) as State,
  25. getDuration: p => ({ kind: 'fixed', durationMs: p.durationInMs }),
  26. teardown: (_, state: State, ctx) => {
  27. ctx.canvas3d?.requestCameraReset({ snapshot: state.snapshot, durationMs: 0 });
  28. },
  29. async apply(animState: State, t, ctx) {
  30. if (t.current === 0) {
  31. return { kind: 'next', state: animState };
  32. }
  33. const snapshot = animState.snapshot;
  34. if (snapshot.radiusMax < 0.0001) {
  35. return { kind: 'finished' };
  36. }
  37. const phase = t.animation
  38. ? t.animation?.currentFrame / (t.animation.frameCount + 1)
  39. : clamp(t.current / ctx.params.durationInMs, 0, 1);
  40. const angle = Math.sin(phase * ctx.params.speed * Math.PI * 2) * degToRad(ctx.params.angle);
  41. Vec3.sub(_dir, snapshot.position, snapshot.target);
  42. Vec3.normalize(_axis, snapshot.up);
  43. Quat.setAxisAngle(_rot, _axis, angle);
  44. Vec3.transformQuat(_dir, _dir, _rot);
  45. const position = Vec3.add(Vec3(), snapshot.target, _dir);
  46. ctx.plugin.canvas3d?.requestCameraReset({ snapshot: { ...snapshot, position }, durationMs: 0 });
  47. if (phase >= 0.99999) {
  48. return { kind: 'finished' };
  49. }
  50. return { kind: 'next', state: animState };
  51. }
  52. });